diff --git a/CHANGELOG.md b/CHANGELOG.md index b536def07..56fe478d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. -## [4.1.3] - unreleased +## [4.1.3] - 2024-03-05 -* Fix the timezone of `datetime` fields when they are read from the database by @GromNaN in [#2739](https://github.com/mongodb/laravel-mongodb/pull/2739) +* Fix the timezone of `datetime` fields when they are read from the database. By @GromNaN in [#2739](https://github.com/mongodb/laravel-mongodb/pull/2739) +* Fix support for null values in `datetime` and reset `date` fields with custom format to the start of the day. By @GromNaN in [#2741](https://github.com/mongodb/laravel-mongodb/pull/2741) ## [4.1.2] - 2024-02-22 diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index dbf7579cd..83239c8eb 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -205,9 +205,10 @@ protected function transformModelValue($key, $value) if ($this->hasCast($key) && $value instanceof CarbonInterface) { $value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()])); + // "date" cast resets the time to 00:00:00. $castType = $this->getCasts()[$key]; - if ($this->isCustomDateTimeCast($castType) && str_starts_with($castType, 'date:')) { - $value->startOfDay(); + if (str_starts_with($castType, 'date:') || str_starts_with($castType, 'immutable_date:')) { + $value = $value->startOfDay(); } } @@ -315,19 +316,6 @@ protected function fromDecimal($value, $decimals) return new Decimal128($this->asDecimal($value, $decimals)); } - /** @inheritdoc */ - protected function castAttribute($key, $value) - { - $castType = $this->getCastType($key); - - 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 */ public function attributesToArray() { diff --git a/tests/Casts/DateTest.php b/tests/Casts/DateTest.php index 20ce5dd9a..64743bce0 100644 --- a/tests/Casts/DateTest.php +++ b/tests/Casts/DateTest.php @@ -52,6 +52,12 @@ public function testDate(): void self::assertInstanceOf(Carbon::class, $refetchedModel->dateField); self::assertInstanceOf(UTCDateTime::class, $model->getRawOriginal('dateField')); self::assertEquals(now()->subDay()->startOfDay()->format('Y-m-d H:i:s'), (string) $refetchedModel->dateField); + + $model = Casting::query()->create(); + $this->assertNull($model->dateField); + + $model->update(['dateField' => null]); + $this->assertNull($model->dateField); } public function testDateAsString(): void @@ -84,6 +90,12 @@ public function testDateWithCustomFormat(): void self::assertInstanceOf(Carbon::class, $model->dateWithFormatField); self::assertEquals(now()->startOfDay()->subDay()->format('j.n.Y H:i'), (string) $model->dateWithFormatField); + + $model = Casting::query()->create(); + $this->assertNull($model->dateWithFormatField); + + $model->update(['dateWithFormatField' => null]); + $this->assertNull($model->dateWithFormatField); } public function testImmutableDate(): void @@ -105,6 +117,12 @@ public function testImmutableDate(): void Carbon::createFromTimestamp(1698577443)->subDay()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->immutableDateField, ); + + $model = Casting::query()->create(); + $this->assertNull($model->immutableDateField); + + $model->update(['immutableDateField' => null]); + $this->assertNull($model->immutableDateField); } public function testImmutableDateWithCustomFormat(): void @@ -126,5 +144,11 @@ public function testImmutableDateWithCustomFormat(): void Carbon::createFromTimestamp(1698577443)->subDay()->startOfDay()->format('j.n.Y H:i'), (string) $model->immutableDateWithFormatField, ); + + $model = Casting::query()->create(); + $this->assertNull($model->immutableDateWithFormatField); + + $model->update(['immutableDateWithFormatField' => null]); + $this->assertNull($model->immutableDateWithFormatField); } } diff --git a/tests/Casts/DatetimeTest.php b/tests/Casts/DatetimeTest.php index 022ed3535..49f1cd9c6 100644 --- a/tests/Casts/DatetimeTest.php +++ b/tests/Casts/DatetimeTest.php @@ -36,6 +36,12 @@ public function testDatetime(): void self::assertInstanceOf(Carbon::class, $model->datetimeField); self::assertInstanceOf(UTCDateTime::class, $model->getRawOriginal('datetimeField')); self::assertEquals(now()->subDay()->format('Y-m-d H:i:s'), (string) $model->datetimeField); + + $model = Casting::query()->create(); + $this->assertNull($model->datetimeField); + + $model->update(['datetimeField' => null]); + $this->assertNull($model->datetimeField); } public function testDatetimeAsString(): void @@ -70,6 +76,12 @@ public function testDatetimeWithCustomFormat(): void self::assertInstanceOf(Carbon::class, $model->datetimeWithFormatField); self::assertEquals(now()->subDay()->format('j.n.Y H:i'), (string) $model->datetimeWithFormatField); + + $model = Casting::query()->create(); + $this->assertNull($model->datetimeWithFormatField); + + $model->update(['datetimeWithFormatField' => null]); + $this->assertNull($model->datetimeWithFormatField); } public function testImmutableDatetime(): void @@ -92,6 +104,12 @@ public function testImmutableDatetime(): void Carbon::createFromTimestamp(1698577443)->subDay()->format('Y-m-d H:i:s'), (string) $model->immutableDatetimeField, ); + + $model = Casting::query()->create(); + $this->assertNull($model->immutableDatetimeField); + + $model->update(['immutableDatetimeField' => null]); + $this->assertNull($model->immutableDatetimeField); } public function testImmutableDatetimeWithCustomFormat(): void @@ -113,5 +131,11 @@ public function testImmutableDatetimeWithCustomFormat(): void Carbon::createFromTimestamp(1698577443)->subDay()->format('j.n.Y H:i'), (string) $model->immutableDatetimeWithFormatField, ); + + $model = Casting::query()->create(); + $this->assertNull($model->immutableDatetimeWithFormatField); + + $model->update(['immutableDatetimeWithFormatField' => null]); + $this->assertNull($model->immutableDatetimeWithFormatField); } }