From 7061312365171b45141531c90b6f6376d07f7fe4 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Thu, 20 Feb 2025 17:10:58 +0000 Subject: [PATCH 1/4] Cast entry dates to UTC --- src/Entries/EntryModel.php | 23 ++++++++- tests/Entries/EntryModelTest.php | 89 ++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/Entries/EntryModel.php b/src/Entries/EntryModel.php index 77e89122..6b824c7c 100644 --- a/src/Entries/EntryModel.php +++ b/src/Entries/EntryModel.php @@ -3,6 +3,8 @@ namespace Statamic\Eloquent\Entries; use Illuminate\Support\Arr; +use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Carbon; use Statamic\Eloquent\Database\BaseModel; class EntryModel extends BaseModel @@ -12,11 +14,30 @@ class EntryModel extends BaseModel protected $table = 'entries'; protected $casts = [ - '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..aa982c7c 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', + ]); + } } From c70b5ffe1a01ca92de03638ab59649cf0467c940 Mon Sep 17 00:00:00 2001 From: duncanmcclean Date: Thu, 20 Feb 2025 17:11:40 +0000 Subject: [PATCH 2/4] Fix styling --- src/Entries/EntryModel.php | 2 +- tests/Entries/EntryModelTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Entries/EntryModel.php b/src/Entries/EntryModel.php index 6b824c7c..dd06d28e 100644 --- a/src/Entries/EntryModel.php +++ b/src/Entries/EntryModel.php @@ -2,8 +2,8 @@ namespace Statamic\Eloquent\Entries; -use Illuminate\Support\Arr; use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Statamic\Eloquent\Database\BaseModel; diff --git a/tests/Entries/EntryModelTest.php b/tests/Entries/EntryModelTest.php index aa982c7c..cb14ddf6 100644 --- a/tests/Entries/EntryModelTest.php +++ b/tests/Entries/EntryModelTest.php @@ -55,7 +55,7 @@ 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 = new EntryModel; $model->id = 1; $model->site = 'en'; $model->published = true; @@ -76,7 +76,7 @@ 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 = new EntryModel; $model->id = 1; $model->site = 'en'; $model->published = true; @@ -97,7 +97,7 @@ 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 = new EntryModel; $model->id = 1; $model->site = 'en'; $model->published = true; From d842c04ad5f0448b65d84840fa6726c5f5d0ead4 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 25 Feb 2025 11:16:31 +0000 Subject: [PATCH 3/4] Remove date cast from example in the docs --- README.md | 1 - 1 file changed, 1 deletion(-) 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', From baa4ece082eee11eb3544cfca206716ec8869539 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 25 Feb 2025 11:17:43 +0000 Subject: [PATCH 4/4] whoops, didn't mean to get rid of this in the merge --- src/Entries/EntryModel.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Entries/EntryModel.php b/src/Entries/EntryModel.php index 713369e8..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 @@ -19,6 +21,26 @@ protected function casts(): array ]; } + 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');