-
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] Upgrade Carbon to version 2 and allow CarbonImmutable #25310
Conversation
I think 5.8 is definitely the right choice. 5.7 is coming out fairly soon, and Carbon v2 is still only in beta. |
Having Immutable Dates in 5.7 would be the cherry in the pie. |
composer.json
Outdated
@@ -23,7 +23,7 @@ | |||
"erusev/parsedown": "^1.7", | |||
"league/flysystem": "^1.0.8", | |||
"monolog/monolog": "^1.12", | |||
"nesbot/carbon": "^1.26.3", | |||
"nesbot/carbon": "^2.0.0-beta.5", |
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 ^2.0
would be fine.
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.
Please also update the other composer.json files in this project.
// Finally, we will just assume this date is in the format used by default on | ||
// the database connection and use that format to create the Carbon object | ||
// that is returned back out to the developers after we convert it here. | ||
return Carbon::createFromFormat( |
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.
I don't think that the Carbon factory is so advanced that it can possibly know the format of the date time used by the database connection :)
I thought StyleCI expected alphabetical order for imports as my IDE set them, but seems not. Someone can explain to me the expected order? https://github.styleci.io/analyses/8AEyl9 |
Nope, Laravel style is to sort them by length first. And StyleCI clearly depicts that by showing what needs to be placed where. |
I prefer to know the rule rather than apply the StyleCI at each commit. For my knowledge, as there is no .styleci.yml, how this setting has been enforced? |
You can apply rules for the repo on the StyleCI website if you are the owner of the repo. So there is no need for the styleci.yml to be in the repo. |
Are we going to start using |
@crynobone Good question. I think we should use |
@@ -157,7 +161,7 @@ public function delete(CanResetPasswordContract $user) | |||
*/ | |||
public function deleteExpired() | |||
{ | |||
$expiredAt = Carbon::now()->subSeconds($this->expires); | |||
$expiredAt = app(Factory::class)->now()->subSeconds($this->expires); | |||
|
|||
$this->getTable()->where('created_at', '<', $expiredAt)->delete(); |
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.
Auth component doesn't load app()
which is under Illuminate\Foundation
, nor does it require illuminate/container
.
@@ -554,7 +554,8 @@ protected function getMinutes($duration) | |||
$duration = $this->parseDateInterval($duration); | |||
|
|||
if ($duration instanceof DateTimeInterface) { | |||
$duration = Carbon::now()->diffInSeconds(Carbon::createFromTimestamp($duration->getTimestamp()), false) / 60; | |||
$dateFactory = app(Factory::class); | |||
$duration = $dateFactory->now()->diffInSeconds($dateFactory->createFromTimestamp($duration->getTimestamp()), false) / 60; |
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.
Cache component doesn't load app()
which is under Illuminate\Foundation
, nor does it require illuminate/container
.
*/ | ||
public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) | ||
{ | ||
return Carbon::instance(CronExpression::factory( | ||
return app(Factory::class)->instance(CronExpression::factory( | ||
$this->getExpression() | ||
)->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); |
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.
Console component doesn't load app()
which is under Illuminate\Foundation
, nor does it require illuminate/container
.
return $value; | ||
} | ||
|
||
$dateFactory = app(Factory::class); |
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.
Database component doesn't load app()
which is under Illuminate\Foundation
.
@@ -548,7 +548,7 @@ public function getAwsTemporaryUrl($adapter, $path, $expiration, $options) | |||
public function getRackspaceTemporaryUrl($adapter, $path, $expiration, $options) | |||
{ | |||
return $adapter->getContainer()->getObject($path)->getTemporaryUrl( | |||
Carbon::now()->diffInSeconds($expiration), | |||
app(Factory::class)->now()->diffInSeconds($expiration), |
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.
Filesystem component doesn't load app()
which is under Illuminate\Foundation
, nor does it require illuminate/container
.
This would fine on the framework level, but once you need to pull in a single component none will work with this changes. |
OK, but what do you propose so? Remember the desired feature: the user should be able to set somewhere the class he want for any date accessible at application level. So it may not be needed everywhere. Carbon instances used then destroyed and never returned could still be created the old way. But if the user would have chosen CarbonImmutable as date type, he certainly would expect to get CarbonImmutable for datetime columns in Eloquent models. |
Who desire this feature? What's the advantage of requiring I don't see any advantage on resolving factory when a class only generate a carbon instance and use the output or compare times. The only component that might heavily take advantage of Immutable is the database component, and maybe for queues and scheduling. |
@@ -59,7 +59,7 @@ public function toMail($notifiable) | |||
protected function verificationUrl($notifiable) | |||
{ | |||
return URL::temporarySignedRoute( | |||
'verification.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()] | |||
'verification.verify', app(Factory::class)->now()->addMinutes(60), ['id' => $notifiable->getKey()] |
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.
This is just going to create a "60 minutes datetime from now", a plain Carbon::now()->addMinutes(60)
should work fine.
return [ | ||
'email' => $email, | ||
'token' => $this->hasher->make($token), | ||
'created_at' => app(Factory::class)->now(), |
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.
This is just used to store "now" as created_at
for reset_passwords
, Carbon::now()
should be more than enough.
@@ -136,7 +140,7 @@ public function exists(CanResetPasswordContract $user, $token) | |||
*/ | |||
protected function tokenExpired($createdAt) | |||
{ | |||
return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast(); | |||
return app(Factory::class)->parse($createdAt)->addSeconds($this->expires)->isPast(); |
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.
This just to check if the token has expired. Why do we need to make it complicated?
CarbonImmutable is not an other library. It's the immutable variant which means: $date = $this->created_at->addWeeks(6); // Get a date from DB
// If date is CarbonImmutable, $later is a new instance 6 weeks later
// If it's Carbon as now, it will alter $this->created, both $this->created
// and $date are the same object modified. It's something very asked in Carbon issues, but you can also find many topic here: #24718 So there are 2 different interests:
The factory system via The factory is also a way embed things more properly. With Carbon 2, we deprecated global setters and recommend to use factories instead: $factory1 = new Factory([
'locale' => 'fr',
]);
$factory2 = new Factory([
'locale' => 'de',
]);
$factory1->now()->dayName; // French
$factory2->now()->dayName; // German So factory would allow to set specific settings to instances created by the framework. However, I'm OK to consider using it only for public API dates. Maybe there are other opinions about this? |
Thanks all for your help. I will have a second iteration on this according to your recommendations:
|
The point is we don't think we need a container to instantiate a factory that instantiates a carbon object (or any other date). As long as you don't introduce a container need into the entire framework, it should be fine. With the recent events, I can now see how 5.8 is definitely the better target for this. |
Yes, it's exactly what I planned and why I close this one. Carbon project will not handle this because we want to abandon the facade pattern (mostly static setters), then each third-party library could get its own factory with its own settings with no impact for the app. So I would create this facade in the Illuminate\Support namespace to carry the factory dedicated to Laravel dates exposed to the user. |
We don't need Yes there is a request or needs for |
Hi,
This PR is not ready to be merged yet, this is a proof of concept to be discussed. This is about upgrading to Carbon 2 and as Carbon 2 comes with a factory, it could allow Laravel users to choose
CarbonImmutable
as default class for dates (immutability seems very asked). Or it would allow to change in a easier way the class/engine to use for date with anything (jessengers/date, chronos, or simply a custom user sub-class).It would be done with:
After this code, any
now()
,today()
or inner Carbon creations would create CarbonImmutable instances.I targeted 5.8, tell me if you think it should be 5.7 or else.
If you think it's the right way to do it. I could go further with tests, doc and maybe a dedicated place in config to set date class and settings.