From 6af0a53e8297499b48fa4c2038c7477a0941a95a Mon Sep 17 00:00:00 2001 From: Steve Bauman Date: Fri, 4 Oct 2024 12:25:07 -0400 Subject: [PATCH] Add Jsonable interface --- src/Exceptions/JsonEncodingException.php | 16 ++++++++------ src/Model.php | 27 +++++++++++++++++++++++- tests/ModelTest.php | 8 +++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/Exceptions/JsonEncodingException.php b/src/Exceptions/JsonEncodingException.php index 20323267..25c1158f 100644 --- a/src/Exceptions/JsonEncodingException.php +++ b/src/Exceptions/JsonEncodingException.php @@ -8,15 +8,17 @@ class JsonEncodingException extends RuntimeException { /** * Create a new JSON encoding exception for an attribute. - * - * @param mixed $model - * @param mixed $key - * @return static */ - public static function forAttribute(string $model, string $key, string $message) + public static function forAttribute(mixed $model, string $key, string $message): static { - $class = get_class($model); + return new static('Unable to encode attribute ['.$key.'] for model ['.get_class($model).'] to JSON: '.$message); + } - return new static("Unable to encode attribute [{$key}] for model [{$class}] to JSON: {$message}."); + /** + * Create a new JSON encoding exception for the model. + */ + public static function forModel(mixed $model, string $message): static + { + return new static('Error encoding model ['.get_class($model).'] with ID ['.$model->getKey().'] to JSON: '.$message); } } diff --git a/src/Model.php b/src/Model.php index 4554ac12..dea32871 100644 --- a/src/Model.php +++ b/src/Model.php @@ -13,19 +13,22 @@ use DirectoryTree\ActiveRedis\Concerns\Routable; use DirectoryTree\ActiveRedis\Exceptions\DuplicateKeyException; use DirectoryTree\ActiveRedis\Exceptions\InvalidKeyException; +use DirectoryTree\ActiveRedis\Exceptions\JsonEncodingException; use DirectoryTree\ActiveRedis\Repositories\RedisRepository; use DirectoryTree\ActiveRedis\Repositories\Repository; use Illuminate\Contracts\Redis\Connection; use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Support\Jsonable; use Illuminate\Redis\RedisManager; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; +use JsonException; -abstract class Model implements Arrayable, ArrayAccess, UrlRoutable +abstract class Model implements Arrayable, ArrayAccess, Jsonable, UrlRoutable { use Bootable; use ForwardsCalls; @@ -563,6 +566,28 @@ public function toArray(): array return $this->attributesToArray(); } + /** + * Convert the model instance to JSON. + */ + public function toJson(mixed $options = 0): string + { + try { + $json = json_encode($this->jsonSerialize(), $options | JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + throw JsonEncodingException::forModel($this, $e->getMessage()); + } + + return $json; + } + + /** + * Convert the object into something JSON serializable. + */ + public function jsonSerialize(): mixed + { + return $this->toArray(); + } + /** * Dynamically retrieve attributes on the model. */ diff --git a/tests/ModelTest.php b/tests/ModelTest.php index 6d4c8947..c08b464f 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -306,3 +306,11 @@ 'id', 'name', 'created_at', 'updated_at', ]); }); + +it('can be converted to json', function () { + $model = ModelStub::create([ + 'name' => 'John Doe', + ]); + + expect($model->toJson())->toBe(json_encode($model->toArray())); +});