Skip to content
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

Datetime casting with custom format #2658

Merged
merged 24 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
02d3857
Override transformModelValue and getCastType methods;
hans-thomas Oct 31, 2023
8c21570
Add test for custom datetime casting;
hans-thomas Oct 31, 2023
21763f9
Handle custom data;
hans-thomas Oct 31, 2023
ecdeabf
Add test for custom date;
hans-thomas Oct 31, 2023
e55384d
Add test for custom date;
hans-thomas Oct 31, 2023
6d9f406
Handling Immutable date;
hans-thomas Oct 31, 2023
959ad71
Add test for immutable date;
hans-thomas Oct 31, 2023
f785038
Handling immutable date;
hans-thomas Oct 31, 2023
a47f066
Add test for immutable date;
hans-thomas Oct 31, 2023
37e6b4e
Update Model.php
hans-thomas Oct 31, 2023
444fcb6
Add test for immutable datetime;
hans-thomas Oct 31, 2023
8d5f7af
WIP
hans-thomas Oct 31, 2023
1ed645b
Add test for immutable datatime with custom format;
hans-thomas Oct 31, 2023
ffd216f
Merge branch '2655' of github.com:hans-thomas/laravel-mongodb into 2655
hans-thomas Oct 31, 2023
75fdfae
WIP
hans-thomas Oct 31, 2023
15b790e
Fix phpcs;
hans-thomas Oct 31, 2023
2ce8c57
WIP
hans-thomas Oct 31, 2023
764ceb1
Revert changes in Model;
hans-thomas Nov 1, 2023
f193850
Revert "Revert changes in Model;"
hans-thomas Nov 1, 2023
4113b85
replace switch with match in Model::castAttribute;
hans-thomas Nov 2, 2023
8c83d81
CarbonInterface replaced with DateTimeInterface in Model::transformMo…
hans-thomas Nov 2, 2023
6dab8ee
Add comment;
hans-thomas Nov 2, 2023
d78f58a
Merge branch '4.1' into 2655
GromNaN Nov 2, 2023
326933e
Apply suggestions from code review
GromNaN Nov 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion src/Eloquent/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,6 +28,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;
Expand All @@ -41,6 +43,7 @@
use function method_exists;
use function sprintf;
use function str_contains;
use function str_starts_with;
use function strcmp;
use function uniqid;

Expand Down Expand Up @@ -199,6 +202,36 @@ public function getAttribute($key)
return parent::getAttribute($key);
}

/** @inheritdoc */
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.
// @see Model::setAttribute()
if ($this->hasCast($key) && $value instanceof CarbonInterface) {
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
$value->settings(array_merge($value->getSettings(), ['toStringFormat' => $this->getDateFormat()]));
hans-thomas marked this conversation as resolved.
Show resolved Hide resolved

$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)
{
Expand All @@ -217,7 +250,7 @@ public function setAttribute($key, $value)
{
$key = (string) $key;

//Add casts
// Add casts
if ($this->hasCast($key)) {
$value = $this->castAttribute($key, $value);
}
Expand Down Expand Up @@ -270,6 +303,19 @@ public function fromJson($value, $asObject = false)
return Json::decode($value ?? '', ! $asObject);
}

/** @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()
{
Expand Down
56 changes: 56 additions & 0 deletions tests/Casts/DateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace MongoDB\Laravel\Tests\Casts;

use Carbon\CarbonImmutable;
use DateTime;
use Illuminate\Support\Carbon;
use MongoDB\Laravel\Tests\Models\Casting;
Expand Down Expand Up @@ -61,4 +62,59 @@ 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);
}

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,
);
}

public function testImmutableDateWithCustomFormat(): 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,
);
}
}
61 changes: 59 additions & 2 deletions tests/Casts/DatetimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace MongoDB\Laravel\Tests\Casts;

use Carbon\CarbonImmutable;
use DateTime;
use Illuminate\Support\Carbon;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;
Expand All @@ -19,7 +21,7 @@ protected function setUp(): void
Casting::truncate();
}

public function testDate(): void
public function testDatetime(): void
{
$model = Casting::query()->create(['datetimeField' => now()]);

Expand All @@ -32,7 +34,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']);

Expand All @@ -50,4 +52,59 @@ 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);
}

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,
);
}

public function testImmutableDatetimeWithCustomFormat(): 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,
);
}
}
13 changes: 13 additions & 0 deletions tests/Models/Casting.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ class Casting extends Eloquent
'jsonValue',
'collectionValue',
'dateField',
'dateWithFormatField',
'immutableDateField',
'immutableDateWithFormatField',
'datetimeField',
'dateWithFormatField',
'datetimeWithFormatField',
'immutableDatetimeField',
'immutableDatetimeWithFormatField',
];

protected $casts = [
Expand All @@ -38,6 +45,12 @@ class Casting extends Eloquent
'jsonValue' => 'json',
'collectionValue' => 'collection',
'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',
'immutableDatetimeField' => 'immutable_datetime',
'immutableDatetimeWithFormatField' => 'immutable_datetime:j.n.Y H:i',
];
}