-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.8] Handle database urls for database connections. #28308
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some conventions you need to be aware of.
Co-Authored-By: mathieutu <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@driesvints I applied your suggestions and will add all the docblocks in a future commit.
BUT I really don't understand why you want to replace all the typehints by phpdoc. I understand that typehints can create issues in some cases (magic methods, proxy, etc.) but not here.
When methods can only handle strings and return strings, why not using language features, instead of adding comments to try to reproduce this native behavior?
This is a real question, because I'm wondering what I'm missing here.
Thanks.
@mathieutu because it's the current convention of the framework and its libraries. When a convention is in place it's best to stick to it. On a personal note I'm also in favor of introducing types but it would need to be introduced in a new major release somewhere in the future: laravel/ideas#1409 |
Please also make |
@driesvints ok, understood the point, thanks (event if there is already a lot of typehints in framework, like all the Another thing: You have converted all private methods and properties to protected, so the class can be extended easily. I agree with that. But as you also replaced UrlParser instantiation from container to direct If it stays instanced by the container, it will be easy for devs to overwrite it in a service provider. 😉 |
No it's not. It's currently just general know-how from looking at the code already in place. PRs to the docs to improve this are appreciated.
I don't consider this to be a reason to resolve it through the container. There are other ways to overwrite this. What you could do is pass it as a constructor argument and then use the container outside the actual object to resolve it. |
Can totally do that if you prefer, but for me it just moves the problem to higher levels (actually two: DatabaseManager is instancied in src/Illuminate/Database/Capsule/Manager.php:63 and src/Illuminate/Database/DatabaseServiceProvider.php:62). The container was already passed and used directly in the class, it's why I did that way. |
Yeah, you're right. That's a bit unfortunate but I believe that we should refrain from adding new implementations of which use that dependency. That's why I think another constructor dependency is the way to go. At both places where the manager is instantiated you can use the container to resolve the dependency. This would have to go to 5.9 then though because it's a breaking change for anyone using the manager separately. |
@driesvints Made the changes, and added all the docblock. I let the container part to someone else, for the day there will be a need. And, just to finish on the "convention" part, I let you see what the boss was doing 2 years ago: https://github.com/laravel/framework/blame/56d11705d817123715a0b64d6daf92963eaa26f0/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php#L55 😛 (just a bit of , only to say that in my opinion we should not loose time on things like that, and just take advantage of what the language has to offer. Good improvements are coming quite quickly to PHP, and it would be too bad that an accumulation of debt let us years back.) Thanks anyway for the time you spent helping me with this PR! |
No problem.
Hah! I do think that's a real exception though. Thanks for your work! |
Thanks for the great work @mathieutu! Does this only apply to database connections? It would be great to have this for Redis connections as well (Heroku Redis uses this URL format). |
❤️ I can get rid of my hack-y overrides at the top of my config/database.php files in applications I deploy to Heroku now 😄 <?php
if (getenv('DATABASE_URL')) {
// Parse URL and set individual config keys
} |
@djtarazona Hi, actually everything is made to be used with redis too. It may still needs a call to do in the proper place, I have to check how Redis is handled in Laravel (I'm a bit rusted about that). If needed and if you want to open a PR, I can help you with that. We also need to document that, and with my poor english some help will be much needed! |
@mathielo What version of Laravel is this available in? |
@martinbean v5.8.15 at least |
@driesvints Cool. Thanks! |
@mathielo Do you have an example of how this is supposed to be used? I’ve just updated an application to Laravel 5.8.15 (confirmed by running DATABASE_URL=postgres://homestead:[email protected]:5432/tickets However, my application seems to try and connect to the default connection ( |
You'll need to update your 'pgsql' => [
'url' => env('DATABASE_URL'),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
], Note that you can also remove the |
Never mind, worked it out for myself! I needed to add a return [
'connections' => [
'pgsql' => [
+ 'url' => env('DATABASE_URL', null),
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
],
],
]; |
@martinbean no, I do not. 😂 You probably want to ping @mathieutu. Cheers! |
@mathielo Sorry, picked wrong person from the mention auto-complete 😂 |
It's exactly that! return [
'connections' => [
'pgsql' => [
+ 'url' => env('DATABASE_URL', null),
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
],
],
]; |
@mathieutu Cool. Is this working for Redis configuration, too? |
@martinbean I let you try and let me know? Will doing the corresponding PR, depending of your answer. 😉 |
@mathieutu As far as I can see the url is not implemented for redis. |
Ok thanks. I'll try to do a PR for that in the week-end.
|
@mathieutu Thanks! |
@mathieutu: Does this work with Redis now? |
I sware I'll take a look this week-end 😉 |
Hey guys! https://github.com/nrk/predis/wiki/Connection-Parameters However, an array is typed for the $config variable in \Illuminate\Redis\Connectors\PredisConnector::connect. Passing it as an array like that works well: 'redis' => [
'client' => 'predis',
'default' => [
'redis://h:password@host:12499',
],
], BUT:
So in conclusion, in my opinion, we don't even need any preprocessing on our side (we totally could, but don't need), we just have to remove the type hint of the connector (and I'd be glad to do the PR 😉). I let you give me your feedback about that, as you will have much more experience with this topic than me! Thoughts? |
I can confirm that this is a working config for the redis database when using the predis client. 'redis' => [
'client' => 'predis',
'default' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=0',
],
'session' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=1',
],
], BUT, it does not seem to work when using phpredis instead of predis. |
It doesn't work with PhpRedis:
[
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'predis'),
'prefix' => env('REDIS_PREFIX'),
],
'default' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=' . env('REDIS_DB', 0),
],
'queues' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=' . env('REDIS_QUEUES_DB', 1),
],
'sessions' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=' . env('REDIS_SESSIONS_DB', 2),
],
'cache' => [
env('REDIS_URL', 'redis://127.0.0.1:6379') . '?database=' . env('REDIS_CACHE_DB', 3),
],
],
] |
Ok, so let's go, I'll do exactly the same than for databases, to be able to configure easily with an url key (and so add database in its dedicated key aside). I'll try to do that tomorrow (could even be released during the day if my students work a bit autonomously! 😇) |
Here we go! |
Great job @mathieutu . Any hint on how you would use |
Hi @tainmar, actually not specially, but all the parameters passed in query string are merged to the options, so you should be able to write anything you want like that. I let you see examples in tests: |
Thanks @mathieutu indeed, the examples make sense. 'read' => [
'url' => [
env('DATABASE_URL_READ'),
],
],
'write' => [
'url' => [
env('DATABASE_URL_WRITE'),
],
], |
Following #28096
I've directly integrated it in the connection process, so it's fully transparent for the user, and without any breaking change (see the tests about it).
Usages
I've covered many cases and examples in tests, so I let you dig into them, and give me back your thoughts about it.
I'm also using it in a real project, and for now it works like a charm.
Thanks.
Matt'