diff --git a/README.md b/README.md index 4ea52a56..767b3190 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,6 @@ By default, the Eloquent Driver stores all data in a single `data` column. Howev { return [ // The casts from Statamic's base model... - 'date' => 'datetime', 'data' => 'json', 'published' => 'boolean', diff --git a/src/Entries/EntryModel.php b/src/Entries/EntryModel.php index 6d8c0e7c..d5d5baaa 100644 --- a/src/Entries/EntryModel.php +++ b/src/Entries/EntryModel.php @@ -2,7 +2,9 @@ namespace Statamic\Eloquent\Entries; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Arr; +use Illuminate\Support\Carbon; use Statamic\Eloquent\Database\BaseModel; class EntryModel extends BaseModel @@ -14,12 +16,31 @@ class EntryModel extends BaseModel protected function casts(): array { return [ - 'date' => 'datetime', 'data' => 'json', 'published' => 'boolean', ]; } + public function date(): Attribute + { + return Attribute::make( + get: function ($value) { + return Carbon::parse($value, 'UTC'); + }, + set: function ($value) { + if (! $value instanceof Carbon) { + $value = Carbon::parse($value, 'UTC'); + } + + if ($value->tzName !== 'UTC') { + $value = $value->utc(); + } + + return $value->format('Y-m-d H:i:s'); + }, + ); + } + public function author() { return $this->belongsTo(\App\Models\User::class, 'data->author'); diff --git a/tests/Entries/EntryModelTest.php b/tests/Entries/EntryModelTest.php index ad55eb30..cb14ddf6 100644 --- a/tests/Entries/EntryModelTest.php +++ b/tests/Entries/EntryModelTest.php @@ -2,12 +2,17 @@ namespace Tests\Entries; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\DB; use PHPUnit\Framework\Attributes\Test; use Statamic\Eloquent\Entries\EntryModel; use Tests\TestCase; class EntryModelTest extends TestCase { + use RefreshDatabase; + #[Test] public function it_gets_attributes_from_json_column() { @@ -22,4 +27,88 @@ public function it_gets_attributes_from_json_column() $this->assertEquals('bar', $model->foo); $this->assertEquals(['foo' => 'bar'], $model->data); } + + #[Test] + public function it_gets_date_as_utc() + { + config()->set('app.timezone', 'America/New_York'); // -05:00 + date_default_timezone_set('America/New_York'); + + DB::table('entries')->insert([ + 'id' => '1', + 'site' => 'en', + 'published' => 1, + 'date' => '2025-01-01 12:11:10', + 'collection' => 'blog', + 'data' => '{}', + ]); + + $date = EntryModel::find(1)->date; + + $this->assertInstanceOf(Carbon::class, $date); + $this->assertEquals('2025-01-01T12:11:10+00:00', $date->toIso8601String()); + } + + #[Test] + public function it_sets_utc_date_from_string() + { + config()->set('app.timezone', 'America/New_York'); // -05:00 + date_default_timezone_set('America/New_York'); + + $model = new EntryModel; + $model->id = 1; + $model->site = 'en'; + $model->published = true; + $model->collection = 'blog'; + $model->date = '2025-01-01 12:11:10'; + $model->data = []; + $model->save(); + + $this->assertDatabaseHas('entries', [ + 'id' => 1, + 'date' => '2025-01-01 12:11:10', + ]); + } + + #[Test] + public function it_sets_utc_date_from_carbon() + { + config()->set('app.timezone', 'America/New_York'); // -05:00 + date_default_timezone_set('America/New_York'); + + $model = new EntryModel; + $model->id = 1; + $model->site = 'en'; + $model->published = true; + $model->collection = 'blog'; + $model->date = Carbon::parse('2025-01-01 12:11:10', 'UTC'); + $model->data = []; + $model->save(); + + $this->assertDatabaseHas('entries', [ + 'id' => 1, + 'date' => '2025-01-01 12:11:10', + ]); + } + + #[Test] + public function it_sets_non_utc_date_from_carbon() + { + config()->set('app.timezone', 'America/New_York'); // -05:00 + date_default_timezone_set('America/New_York'); + + $model = new EntryModel; + $model->id = 1; + $model->site = 'en'; + $model->published = true; + $model->collection = 'blog'; + $model->date = Carbon::parse('2025-01-01 12:11:10'); + $model->data = []; + $model->save(); + + $this->assertDatabaseHas('entries', [ + 'id' => 1, + 'date' => '2025-01-01 17:11:10', + ]); + } }