From 02d3857ff07b05dc43c9f74fdd19500a388dc50a Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 16:22:52 +0330 Subject: [PATCH 01/22] Override transformModelValue and getCastType methods; --- src/Eloquent/Model.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 72c4d2a5f..a09b0b125 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -199,6 +199,28 @@ public function getAttribute($key) return parent::getAttribute($key); } + /** @inheritdoc */ + protected function transformModelValue($key, $value) + { + $value = parent::transformModelValue($key,$value); + if ($value instanceof DateTimeInterface) { + $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); + } + + return $value; + } + + /** @inheritdoc */ + protected function getCastType($key) + { + $castType = $this->getCasts()[$key]; + if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) { + $this->setDateFormat(Str::after($castType, ':')); + } + + return parent::getCastType($key); + } + /** @inheritdoc */ protected function getAttributeFromArray($key) { @@ -217,7 +239,7 @@ public function setAttribute($key, $value) { $key = (string) $key; - //Add casts + // Add casts if ($this->hasCast($key)) { $value = $this->castAttribute($key, $value); } From 8c21570aa0d2413901b6f72d61711c241b0c0d05 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 16:23:58 +0330 Subject: [PATCH 02/22] Add test for custom datetime casting; --- tests/Casts/DatetimeTest.php | 19 +++++++++++++++++-- tests/Models/Casting.php | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/Casts/DatetimeTest.php b/tests/Casts/DatetimeTest.php index 77a9cb4b6..aab4a507d 100644 --- a/tests/Casts/DatetimeTest.php +++ b/tests/Casts/DatetimeTest.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Casts; +use DateTime; use Illuminate\Support\Carbon; use MongoDB\Laravel\Tests\Models\Casting; use MongoDB\Laravel\Tests\TestCase; @@ -19,7 +20,7 @@ protected function setUp(): void Casting::truncate(); } - public function testDate(): void + public function testDatetime(): void { $model = Casting::query()->create(['datetimeField' => now()]); @@ -32,7 +33,7 @@ public function testDate(): void self::assertEquals(now()->subDay()->format('Y-m-d H:i:s'), (string) $model->datetimeField); } - public function testDateAsString(): void + public function testDatetimeAsString(): void { $model = Casting::query()->create(['datetimeField' => '2023-10-29']); @@ -50,4 +51,18 @@ public function testDateAsString(): void (string) $model->datetimeField, ); } + + public function testDatetimeWithCustomFormat(): void + { + $model = Casting::query()->create(['datetimeWithFormatField' => new DateTime()]); + + self::assertInstanceOf(Carbon::class, $model->datetimeWithFormatField); + self::assertEquals(now()->format('j.n.Y H:i'), (string) $model->datetimeWithFormatField); + + $model->update(['datetimeWithFormatField' => now()->subDay()]); + + self::assertInstanceOf(Carbon::class, $model->datetimeWithFormatField); + self::assertEquals(now()->subDay()->format('j.n.Y H:i'), (string) $model->datetimeWithFormatField); + } + } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 5f825f954..91bfa5771 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -25,6 +25,7 @@ class Casting extends Eloquent 'collectionValue', 'dateField', 'datetimeField', + 'datetimeWithFormatField', ]; protected $casts = [ @@ -39,5 +40,6 @@ class Casting extends Eloquent 'collectionValue' => 'collection', 'dateField' => 'date', 'datetimeField' => 'datetime', + 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', ]; } From 21763f9b505f0dc60eeaf363924c1f417e94c860 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 16:34:34 +0330 Subject: [PATCH 03/22] Handle custom data; --- src/Eloquent/Model.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index a09b0b125..beb79b7fa 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -204,6 +204,10 @@ protected function transformModelValue($key, $value) { $value = parent::transformModelValue($key,$value); if ($value instanceof DateTimeInterface) { + $castType = $this->getCasts()[$key]; + if (str_starts_with($castType, 'date')) { + $value->startOfDay(); + } $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); } From ecdeabfa287d4204e6b0af68928f9235f8ef9421 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 16:34:47 +0330 Subject: [PATCH 04/22] Add test for custom date; --- tests/Casts/DateTest.php | 14 ++++++++++++++ tests/Models/Casting.php | 2 ++ 2 files changed, 16 insertions(+) diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index e0c775503..3c08d914c 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -61,4 +61,18 @@ public function testDateAsString(): void (string) $model->dateField, ); } + + /** @group hans */ + public function testDateWithCustomFormat(): void + { + $model = Casting::query()->create(['dateWithFormatField' => new DateTime()]); + + self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); + self::assertEquals(now()->startOfDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); + + $model->update(['dateWithFormatField' => now()->subDay()]); + + self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); + self::assertEquals(now()->startOfDay()->subDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 91bfa5771..e985c92bc 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -25,6 +25,7 @@ class Casting extends Eloquent 'collectionValue', 'dateField', 'datetimeField', + 'dateWithFormatField', 'datetimeWithFormatField', ]; @@ -40,6 +41,7 @@ class Casting extends Eloquent 'collectionValue' => 'collection', 'dateField' => 'date', 'datetimeField' => 'datetime', + 'dateWithFormatField' => 'date:j.n.Y H:i', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', ]; } From e55384d68b11e7259f3a69644f12991b2290be56 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 16:34:47 +0330 Subject: [PATCH 05/22] Add test for custom date; --- tests/Casts/DateTest.php | 13 +++++++++++++ tests/Models/Casting.php | 2 ++ 2 files changed, 15 insertions(+) diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index e0c775503..bc970c6f0 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -61,4 +61,17 @@ public function testDateAsString(): void (string) $model->dateField, ); } + + public function testDateWithCustomFormat(): void + { + $model = Casting::query()->create(['dateWithFormatField' => new DateTime()]); + + self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); + self::assertEquals(now()->startOfDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); + + $model->update(['dateWithFormatField' => now()->subDay()]); + + self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); + self::assertEquals(now()->startOfDay()->subDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 91bfa5771..e985c92bc 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -25,6 +25,7 @@ class Casting extends Eloquent 'collectionValue', 'dateField', 'datetimeField', + 'dateWithFormatField', 'datetimeWithFormatField', ]; @@ -40,6 +41,7 @@ class Casting extends Eloquent 'collectionValue' => 'collection', 'dateField' => 'date', 'datetimeField' => 'datetime', + 'dateWithFormatField' => 'date:j.n.Y H:i', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', ]; } From 6d9f406adf76f76d29859ce65d82fbac1124c301 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:22:19 +0330 Subject: [PATCH 06/22] Handling Immutable date; --- src/Eloquent/Model.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index beb79b7fa..2a40c2a72 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -203,12 +203,14 @@ public function getAttribute($key) protected function transformModelValue($key, $value) { $value = parent::transformModelValue($key,$value); - if ($value instanceof DateTimeInterface) { + if ($this->hasCast($key) && $value instanceof DateTimeInterface) { + $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); + $castType = $this->getCasts()[$key]; - if (str_starts_with($castType, 'date')) { + if (($this->isCustomDateTimeCast($castType)&& str_starts_with($castType, 'date:')) || + ( $this->isImmutableCustomDateTimeCast($castType) && str_starts_with($castType, 'immutable_date:'))) { $value->startOfDay(); } - $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); } return $value; From 959ad7151cf9fcf9631049f5ebe956b82f0e97a4 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:22:37 +0330 Subject: [PATCH 07/22] Add test for immutable date; --- tests/Casts/DateTest.php | 22 ++++++++++++++++++++++ tests/Models/Casting.php | 6 ++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index bc970c6f0..b30016c8f 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Casts; +use Carbon\CarbonImmutable; use DateTime; use Illuminate\Support\Carbon; use MongoDB\Laravel\Tests\Models\Casting; @@ -74,4 +75,25 @@ public function testDateWithCustomFormat(): void self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); self::assertEquals(now()->startOfDay()->subDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); } + + public function testImmutableDate(): void + { + $model = Casting::query()->create(['immutableDateField' => new DateTime()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateField); + self::assertEquals(now()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->immutableDateField); + + $model->update(['immutableDateField' => now()->subDay()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateField); + self::assertEquals(now()->startOfDay()->subDay()->format('Y-m-d H:i:s'), (string) $model->immutableDateField); + + $model->update(['immutableDateField' => '2023-10-28']); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateField); + self::assertEquals( + Carbon::createFromTimestamp(1698577443)->subDay()->startOfDay()->format('Y-m-d H:i:s'), + (string) $model->immutableDateField, + ); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index e985c92bc..6f6e285bd 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -24,8 +24,9 @@ class Casting extends Eloquent 'jsonValue', 'collectionValue', 'dateField', - 'datetimeField', 'dateWithFormatField', + 'immutableDateField', + 'datetimeField', 'datetimeWithFormatField', ]; @@ -40,8 +41,9 @@ class Casting extends Eloquent 'jsonValue' => 'json', 'collectionValue' => 'collection', 'dateField' => 'date', - 'datetimeField' => 'datetime', 'dateWithFormatField' => 'date:j.n.Y H:i', + 'immutableDateField' => 'immutable_date', + 'datetimeField' => 'datetime', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', ]; } From f785038e9b5e656c6649036dd06db5070f3cb686 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:23:31 +0330 Subject: [PATCH 08/22] Handling immutable date; --- src/Eloquent/Model.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 2a40c2a72..2bc20e69b 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -298,6 +298,23 @@ public function fromJson($value, $asObject = false) return Json::decode($value ?? '', ! $asObject); } + /** @inheritdoc */ + protected function castAttribute($key, $value) + { + $castType = $this->getCastType($key); + + switch ($castType) { + case 'immutable_custom_datetime': + case 'immutable_datetime': + if (str_starts_with($this->getCasts()[$key],'immutable_date')){ + return $this->asDate($value)->toImmutable(); + } + return $this->asDateTime($value)->toImmutable(); + default: + return parent::castAttribute($key, $value); + } + } + /** @inheritdoc */ public function attributesToArray() { From a47f066fa3d61f8eb5b13a7c9c7df5d6aa957503 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:23:45 +0330 Subject: [PATCH 09/22] Add test for immutable date; --- tests/Casts/DateTest.php | 21 +++++++++++++++++++++ tests/Models/Casting.php | 2 ++ 2 files changed, 23 insertions(+) diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index b30016c8f..b871d56e5 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -96,4 +96,25 @@ public function testImmutableDate(): void (string) $model->immutableDateField, ); } + + public function testImmutableDateWithFormat(): void + { + $model = Casting::query()->create(['immutableDateWithFormatField' => new DateTime()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateWithFormatField); + self::assertEquals(now()->startOfDay()->format('j.n.Y H:i'), (string) $model->immutableDateWithFormatField); + + $model->update(['immutableDateWithFormatField' => now()->startOfDay()->subDay()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateWithFormatField); + self::assertEquals(now()->startOfDay()->subDay()->format('j.n.Y H:i'), (string) $model->immutableDateWithFormatField); + + $model->update(['immutableDateWithFormatField' => '2023-10-28']); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDateWithFormatField); + self::assertEquals( + Carbon::createFromTimestamp(1698577443)->subDay()->startOfDay()->format('j.n.Y H:i'), + (string) $model->immutableDateWithFormatField, + ); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 6f6e285bd..ccbc58d97 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -26,6 +26,7 @@ class Casting extends Eloquent 'dateField', 'dateWithFormatField', 'immutableDateField', + 'immutableDateWithFormatField', 'datetimeField', 'datetimeWithFormatField', ]; @@ -43,6 +44,7 @@ class Casting extends Eloquent 'dateField' => 'date', 'dateWithFormatField' => 'date:j.n.Y H:i', 'immutableDateField' => 'immutable_date', + 'immutableDateWithFormatField' => 'immutable_date:j.n.Y H:i', 'datetimeField' => 'datetime', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', ]; From 37e6b4ee4c84fea9679e89619bc7dd3ec71ea981 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:32:42 +0330 Subject: [PATCH 10/22] Update Model.php --- src/Eloquent/Model.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 2bc20e69b..1a763fc47 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -207,8 +207,7 @@ protected function transformModelValue($key, $value) $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); $castType = $this->getCasts()[$key]; - if (($this->isCustomDateTimeCast($castType)&& str_starts_with($castType, 'date:')) || - ( $this->isImmutableCustomDateTimeCast($castType) && str_starts_with($castType, 'immutable_date:'))) { + if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { $value->startOfDay(); } } @@ -306,7 +305,7 @@ protected function castAttribute($key, $value) switch ($castType) { case 'immutable_custom_datetime': case 'immutable_datetime': - if (str_starts_with($this->getCasts()[$key],'immutable_date')){ + if (str_starts_with($this->getCasts()[$key],'immutable_date:')){ return $this->asDate($value)->toImmutable(); } return $this->asDateTime($value)->toImmutable(); From 444fcb648c2878763e79b2b196f1dfb7feefd8d1 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:33:18 +0330 Subject: [PATCH 11/22] Add test for immutable datetime; --- tests/Casts/DatetimeTest.php | 21 +++++++++++++++++++++ tests/Models/Casting.php | 2 ++ 2 files changed, 23 insertions(+) diff --git a/tests/Casts/DatetimeTest.php b/tests/Casts/DatetimeTest.php index aab4a507d..93b971db8 100644 --- a/tests/Casts/DatetimeTest.php +++ b/tests/Casts/DatetimeTest.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Casts; +use Carbon\CarbonImmutable; use DateTime; use Illuminate\Support\Carbon; use MongoDB\Laravel\Tests\Models\Casting; @@ -65,4 +66,24 @@ public function testDatetimeWithCustomFormat(): void self::assertEquals(now()->subDay()->format('j.n.Y H:i'), (string) $model->datetimeWithFormatField); } + public function testImmutableDatetime(): void + { + $model = Casting::query()->create(['immutableDatetimeField' => new DateTime()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeField); + self::assertEquals(now()->format('Y-m-d H:i:s'), (string) $model->immutableDatetimeField); + + $model->update(['immutableDatetimeField' => now()->subDay()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeField); + self::assertEquals(now()->subDay()->format('Y-m-d H:i:s'), (string) $model->immutableDatetimeField); + + $model->update(['immutableDatetimeField' => '2023-10-28 11:04:03']); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeField); + self::assertEquals( + Carbon::createFromTimestamp(1698577443)->subDay()->format('Y-m-d H:i:s'), + (string) $model->immutableDatetimeField, + ); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index ccbc58d97..361d1a44d 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -29,6 +29,7 @@ class Casting extends Eloquent 'immutableDateWithFormatField', 'datetimeField', 'datetimeWithFormatField', + 'immutableDatetimeField', ]; protected $casts = [ @@ -47,5 +48,6 @@ class Casting extends Eloquent 'immutableDateWithFormatField' => 'immutable_date:j.n.Y H:i', 'datetimeField' => 'datetime', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', + 'immutableDatetimeField' => 'immutable_datetime', ]; } From 8d5f7af181e9c201174dfa20649aa5cf214753f1 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:35:34 +0330 Subject: [PATCH 12/22] WIP --- tests/Casts/DateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index b871d56e5..bd4b76424 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -97,7 +97,7 @@ public function testImmutableDate(): void ); } - public function testImmutableDateWithFormat(): void + public function testImmutableDateWithCustomFormat(): void { $model = Casting::query()->create(['immutableDateWithFormatField' => new DateTime()]); From 1ed645b242a0520ed02195214a0c256cd4bcd97c Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:36:40 +0330 Subject: [PATCH 13/22] Add test for immutable datatime with custom format; --- tests/Casts/DatetimeTest.php | 21 +++++++++++++++++++++ tests/Models/Casting.php | 2 ++ 2 files changed, 23 insertions(+) diff --git a/tests/Casts/DatetimeTest.php b/tests/Casts/DatetimeTest.php index 93b971db8..e888d84f8 100644 --- a/tests/Casts/DatetimeTest.php +++ b/tests/Casts/DatetimeTest.php @@ -86,4 +86,25 @@ public function testImmutableDatetime(): void (string) $model->immutableDatetimeField, ); } + + public function testImmutableDatetimeWithFormat(): void + { + $model = Casting::query()->create(['immutableDatetimeWithFormatField' => new DateTime()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeWithFormatField); + self::assertEquals(now()->format('j.n.Y H:i'), (string) $model->immutableDatetimeWithFormatField); + + $model->update(['immutableDatetimeWithFormatField' => now()->subDay()]); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeWithFormatField); + self::assertEquals(now()->subDay()->format('j.n.Y H:i'), (string) $model->immutableDatetimeWithFormatField); + + $model->update(['immutableDatetimeWithFormatField' => '2023-10-28 11:04:03']); + + self::assertInstanceOf(CarbonImmutable::class, $model->immutableDatetimeWithFormatField); + self::assertEquals( + Carbon::createFromTimestamp(1698577443)->subDay()->format('j.n.Y H:i'), + (string) $model->immutableDatetimeWithFormatField, + ); + } } diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 361d1a44d..0b3801ad1 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -30,6 +30,7 @@ class Casting extends Eloquent 'datetimeField', 'datetimeWithFormatField', 'immutableDatetimeField', + 'immutableDatetimeWithFormatField', ]; protected $casts = [ @@ -49,5 +50,6 @@ class Casting extends Eloquent 'datetimeField' => 'datetime', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', 'immutableDatetimeField' => 'immutable_datetime', + 'immutableDatetimeWithFormatField' => 'immutable_datetime:j.n.Y H:i', ]; } From 75fdfae27da7f28648e13fea3c404644226b45b2 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:38:38 +0330 Subject: [PATCH 14/22] WIP --- tests/Models/Casting.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Models/Casting.php b/tests/Models/Casting.php index 60cd7f6f9..9e232cf15 100644 --- a/tests/Models/Casting.php +++ b/tests/Models/Casting.php @@ -49,7 +49,6 @@ class Casting extends Eloquent 'immutableDateField' => 'immutable_date', 'immutableDateWithFormatField' => 'immutable_date:j.n.Y H:i', 'datetimeField' => 'datetime', - 'dateWithFormatField' => 'date:j.n.Y H:i', 'datetimeWithFormatField' => 'datetime:j.n.Y H:i', 'immutableDatetimeField' => 'immutable_datetime', 'immutableDatetimeWithFormatField' => 'immutable_datetime:j.n.Y H:i', From 15b790e51eba92dd261bdfe0ed29d85807d7f6ac Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 17:39:50 +0330 Subject: [PATCH 15/22] Fix phpcs; --- src/Eloquent/Model.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 1a763fc47..9ad6d4ff0 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -27,6 +27,7 @@ use function abs; use function array_key_exists; use function array_keys; +use function array_merge; use function array_unique; use function array_values; use function class_basename; @@ -41,6 +42,7 @@ use function method_exists; use function sprintf; use function str_contains; +use function str_starts_with; use function strcmp; use function uniqid; @@ -202,9 +204,9 @@ public function getAttribute($key) /** @inheritdoc */ protected function transformModelValue($key, $value) { - $value = parent::transformModelValue($key,$value); + $value = parent::transformModelValue($key, $value); if ($this->hasCast($key) && $value instanceof DateTimeInterface) { - $value->settings(array_merge($value->getSettings(),['toStringFormat'=>$this->getDateFormat()])); + $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); $castType = $this->getCasts()[$key]; if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { @@ -305,9 +307,10 @@ protected function castAttribute($key, $value) switch ($castType) { case 'immutable_custom_datetime': case 'immutable_datetime': - if (str_starts_with($this->getCasts()[$key],'immutable_date:')){ + if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { return $this->asDate($value)->toImmutable(); } + return $this->asDateTime($value)->toImmutable(); default: return parent::castAttribute($key, $value); From 2ce8c5782b7c2b4c23b085b649dd6e8cd89cddd0 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 31 Oct 2023 18:12:14 +0330 Subject: [PATCH 16/22] WIP --- tests/Casts/DatetimeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Casts/DatetimeTest.php b/tests/Casts/DatetimeTest.php index e888d84f8..a90901a82 100644 --- a/tests/Casts/DatetimeTest.php +++ b/tests/Casts/DatetimeTest.php @@ -87,7 +87,7 @@ public function testImmutableDatetime(): void ); } - public function testImmutableDatetimeWithFormat(): void + public function testImmutableDatetimeWithCustomFormat(): void { $model = Casting::query()->create(['immutableDatetimeWithFormatField' => new DateTime()]); From 764ceb1cef9882b08bbaecb3e3b3b74d6704aed9 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 1 Nov 2023 16:07:47 +0330 Subject: [PATCH 17/22] Revert changes in Model; --- src/Eloquent/Model.php | 86 +++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 9ad6d4ff0..035d4eb2a 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -201,32 +201,32 @@ public function getAttribute($key) return parent::getAttribute($key); } - /** @inheritdoc */ - protected function transformModelValue($key, $value) - { - $value = parent::transformModelValue($key, $value); - if ($this->hasCast($key) && $value instanceof DateTimeInterface) { - $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); - - $castType = $this->getCasts()[$key]; - if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { - $value->startOfDay(); - } - } - - return $value; - } - - /** @inheritdoc */ - protected function getCastType($key) - { - $castType = $this->getCasts()[$key]; - if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) { - $this->setDateFormat(Str::after($castType, ':')); - } - - return parent::getCastType($key); - } +// /** @inheritdoc */ +// protected function transformModelValue($key, $value) +// { +// $value = parent::transformModelValue($key, $value); +// if ($this->hasCast($key) && $value instanceof DateTimeInterface) { +// $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); +// +// $castType = $this->getCasts()[$key]; +// if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { +// $value->startOfDay(); +// } +// } +// +// return $value; +// } + +// /** @inheritdoc */ +// protected function getCastType($key) +// { +// $castType = $this->getCasts()[$key]; +// if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) { +// $this->setDateFormat(Str::after($castType, ':')); +// } +// +// return parent::getCastType($key); +// } /** @inheritdoc */ protected function getAttributeFromArray($key) @@ -299,23 +299,23 @@ public function fromJson($value, $asObject = false) return Json::decode($value ?? '', ! $asObject); } - /** @inheritdoc */ - protected function castAttribute($key, $value) - { - $castType = $this->getCastType($key); - - switch ($castType) { - case 'immutable_custom_datetime': - case 'immutable_datetime': - if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { - return $this->asDate($value)->toImmutable(); - } - - return $this->asDateTime($value)->toImmutable(); - default: - return parent::castAttribute($key, $value); - } - } +// /** @inheritdoc */ +// protected function castAttribute($key, $value) +// { +// $castType = $this->getCastType($key); +// +// switch ($castType) { +// case 'immutable_custom_datetime': +// case 'immutable_datetime': +// if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { +// return $this->asDate($value)->toImmutable(); +// } +// +// return $this->asDateTime($value)->toImmutable(); +// default: +// return parent::castAttribute($key, $value); +// } +// } /** @inheritdoc */ public function attributesToArray() From f19385076683557a49055dee35b984cc3f59da94 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 1 Nov 2023 18:43:55 +0330 Subject: [PATCH 18/22] Revert "Revert changes in Model;" This reverts commit 764ceb1cef9882b08bbaecb3e3b3b74d6704aed9. --- src/Eloquent/Model.php | 86 +++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 035d4eb2a..9ad6d4ff0 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -201,32 +201,32 @@ public function getAttribute($key) return parent::getAttribute($key); } -// /** @inheritdoc */ -// protected function transformModelValue($key, $value) -// { -// $value = parent::transformModelValue($key, $value); -// if ($this->hasCast($key) && $value instanceof DateTimeInterface) { -// $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); -// -// $castType = $this->getCasts()[$key]; -// if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { -// $value->startOfDay(); -// } -// } -// -// return $value; -// } - -// /** @inheritdoc */ -// protected function getCastType($key) -// { -// $castType = $this->getCasts()[$key]; -// if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) { -// $this->setDateFormat(Str::after($castType, ':')); -// } -// -// return parent::getCastType($key); -// } + /** @inheritdoc */ + protected function transformModelValue($key, $value) + { + $value = parent::transformModelValue($key, $value); + if ($this->hasCast($key) && $value instanceof DateTimeInterface) { + $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); + + $castType = $this->getCasts()[$key]; + if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { + $value->startOfDay(); + } + } + + return $value; + } + + /** @inheritdoc */ + protected function getCastType($key) + { + $castType = $this->getCasts()[$key]; + if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) { + $this->setDateFormat(Str::after($castType, ':')); + } + + return parent::getCastType($key); + } /** @inheritdoc */ protected function getAttributeFromArray($key) @@ -299,23 +299,23 @@ public function fromJson($value, $asObject = false) return Json::decode($value ?? '', ! $asObject); } -// /** @inheritdoc */ -// protected function castAttribute($key, $value) -// { -// $castType = $this->getCastType($key); -// -// switch ($castType) { -// case 'immutable_custom_datetime': -// case 'immutable_datetime': -// if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { -// return $this->asDate($value)->toImmutable(); -// } -// -// return $this->asDateTime($value)->toImmutable(); -// default: -// return parent::castAttribute($key, $value); -// } -// } + /** @inheritdoc */ + protected function castAttribute($key, $value) + { + $castType = $this->getCastType($key); + + switch ($castType) { + case 'immutable_custom_datetime': + case 'immutable_datetime': + if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { + return $this->asDate($value)->toImmutable(); + } + + return $this->asDateTime($value)->toImmutable(); + default: + return parent::castAttribute($key, $value); + } + } /** @inheritdoc */ public function attributesToArray() From 4113b852baa4fa969b091a4c36ba0fc46770b106 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Thu, 2 Nov 2023 15:32:30 +0330 Subject: [PATCH 19/22] replace switch with match in Model::castAttribute; --- src/Eloquent/Model.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 9ad6d4ff0..3750c3ac5 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -304,17 +304,12 @@ protected function castAttribute($key, $value) { $castType = $this->getCastType($key); - switch ($castType) { - case 'immutable_custom_datetime': - case 'immutable_datetime': - if (str_starts_with($this->getCasts()[$key], 'immutable_date:')) { - return $this->asDate($value)->toImmutable(); - } - - return $this->asDateTime($value)->toImmutable(); - default: - return parent::castAttribute($key, $value); - } + return match ($castType) { + 'immutable_custom_datetime','immutable_datetime' => str_starts_with($this->getCasts()[$key], 'immutable_date:') ? + $this->asDate($value)->toImmutable() : + $this->asDateTime($value)->toImmutable(), + default => parent::castAttribute($key, $value) + }; } /** @inheritdoc */ From 8c83d818fee232e3922244e6e67a76ee1579badb Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Thu, 2 Nov 2023 16:03:11 +0330 Subject: [PATCH 20/22] CarbonInterface replaced with DateTimeInterface in Model::transformModelValue method; --- src/Eloquent/Model.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 3750c3ac5..5f349a71d 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -7,6 +7,7 @@ use Brick\Math\BigDecimal; use Brick\Math\Exception\MathException as BrickMathException; use Brick\Math\RoundingMode; +use Carbon\CarbonInterface; use DateTimeInterface; use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Contracts\Queue\QueueableEntity; @@ -205,7 +206,7 @@ public function getAttribute($key) protected function transformModelValue($key, $value) { $value = parent::transformModelValue($key, $value); - if ($this->hasCast($key) && $value instanceof DateTimeInterface) { + if ($this->hasCast($key) && $value instanceof CarbonInterface) { $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); $castType = $this->getCasts()[$key]; From 6dab8ee0d6082d088572f8a1281bdea21cf58505 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Thu, 2 Nov 2023 16:10:55 +0330 Subject: [PATCH 21/22] Add comment; --- src/Eloquent/Model.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 5f349a71d..ebfc8a9dd 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -206,6 +206,8 @@ public function getAttribute($key) protected function transformModelValue($key, $value) { $value = parent::transformModelValue($key, $value); + // Casting attributes to any of date types, will convert that attribute + // to a Carbon or CarbonImmutable instance. It's done in setAttribute method L254. if ($this->hasCast($key) && $value instanceof CarbonInterface) { $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); From 326933e7b7abc955d853b68545b812945ef450ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 2 Nov 2023 21:22:17 +0100 Subject: [PATCH 22/22] Apply suggestions from code review --- src/Eloquent/Model.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index ebfc8a9dd..c4c73d67d 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -207,7 +207,8 @@ protected function transformModelValue($key, $value) { $value = parent::transformModelValue($key, $value); // Casting attributes to any of date types, will convert that attribute - // to a Carbon or CarbonImmutable instance. It's done in setAttribute method L254. + // to a Carbon or CarbonImmutable instance. + // @see Model::setAttribute() if ($this->hasCast($key) && $value instanceof CarbonInterface) { $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()]));