diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c44b67..0a7d33c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: stability: [prefer-stable] - php: [8.1, 8.2] + php: [8.1, 8.2, 8.3, 8.4] laravel: [10] name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} diff --git a/composer.json b/composer.json index c9740a3..ec0d71f 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "api-ecosystem-for-laravel/dingo-api": "^4.1", "php-open-source-saver/jwt-auth": "^2.1", "illuminate/support": "^10.0", - "ramsey/uuid": "^4.3" + "ramsey/uuid": "^4.3", + "nesbot/carbon": "^2.0|^3.0" }, "require-dev": { "ext-json": "*", diff --git a/src/Transformers/RestfulTransformer.php b/src/Transformers/RestfulTransformer.php index af7fc11..0879aa3 100644 --- a/src/Transformers/RestfulTransformer.php +++ b/src/Transformers/RestfulTransformer.php @@ -2,6 +2,8 @@ namespace Specialtactics\L5Api\Transformers; +use DateTimeInterface; +use Carbon\Carbon; use League\Fractal\TransformerAbstract; use Specialtactics\L5Api\APIBoilerplate; use Specialtactics\L5Api\Models\RestfulModel; @@ -9,6 +11,8 @@ class RestfulTransformer extends TransformerAbstract { + public const DATE_CAST_TYPES = ['date', 'datetime', 'immutable_date', 'immutable_datetime']; + /** * @var RestfulModel The model to be transformed */ @@ -82,11 +86,19 @@ public function transformRestfulModel(EloquentModel $model) }, ARRAY_FILTER_USE_KEY); /* - * Format all dates as Iso8601 strings, this includes the created_at and updated_at columns + * Format all dates as Iso8601 strings, this includes timestamped columns */ - foreach ($model->getDates() as $dateColumn) { + foreach ($this->getModelDateFields($model) as $dateColumn) { if (! empty($model->$dateColumn) && ! in_array($dateColumn, $filterOutAttributes)) { - $transformed[$dateColumn] = $model->$dateColumn->toIso8601String(); + if ($model->$dateColumn instanceof DateTimeInterface) { + $transformed[$dateColumn] = Carbon::instance($model->$dateColumn)->toIso8601String(); + } else { + try { + $transformed[$dateColumn] = Carbon::parse($model->$dateColumn)->toIso8601String(); + } catch (\Error $e) { + $transformed[$dateColumn] = $model->$dateColumn; + } + } } } @@ -253,4 +265,26 @@ protected function transformRelations(array $transformed) return $transformed; } + + protected function getModelDateFields(EloquentModel $model): array + { + $dateFields = []; + + foreach ($model->getDates() as $dateColumn) { + $dateFields[] = $dateColumn; + } + + // For previous versions of Eloquent, dates were stored as arrays + if ($model->dates && is_array($model->dates)) { + $dateFields = array_merge($model->dates, $dateFields); + } + + foreach ($model->getCasts() as $field => $castType) { + if (in_array($castType, static::DATE_CAST_TYPES)) { + $dateFields[] = $field; + } + } + + return array_unique($dateFields); + } }