From 70883fd0e0228d3bb208afcb5857204c582efaec Mon Sep 17 00:00:00 2001 From: a-komarev Date: Sun, 9 Dec 2018 19:51:37 +0300 Subject: [PATCH 1/4] Initial implementation --- src/AbstractSerializerRegistry.php | 39 +++++++++ src/PolymorphicCollection.php | 125 ++++++++++++++++++++++++++++ src/PolymorphicResource.php | 26 ++++++ src/SerializerRegistryInterface.php | 23 +++++ 4 files changed, 213 insertions(+) create mode 100644 src/AbstractSerializerRegistry.php create mode 100644 src/PolymorphicCollection.php create mode 100644 src/PolymorphicResource.php create mode 100644 src/SerializerRegistryInterface.php diff --git a/src/AbstractSerializerRegistry.php b/src/AbstractSerializerRegistry.php new file mode 100644 index 0000000..bfccd73 --- /dev/null +++ b/src/AbstractSerializerRegistry.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\JsonApi; + +use RuntimeException; + +class AbstractSerializerRegistry implements SerializerRegistryInterface +{ + /** + * @var array + */ + protected $serializers = []; + + /** + * Instantiate serializer from the serializable object. + * + * @param object $serializable + * @return \Tobscure\JsonApi\SerializerInterface + */ + public function getFromSerializable($serializable) + { + $class = get_class($serializable); + + if (!isset($this->serializers[$class])) { + throw new RuntimeException("Serializer with name `{$class}` is not exists"); + } + + return new $this->serializers[$class](); + } +} diff --git a/src/PolymorphicCollection.php b/src/PolymorphicCollection.php new file mode 100644 index 0000000..54b9b2c --- /dev/null +++ b/src/PolymorphicCollection.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\JsonApi; + +class PolymorphicCollection implements ElementInterface +{ + /** + * @var array + */ + protected $resources = []; + + /** + * Create a new collection instance. + * + * @param mixed $data + * @param \Tobscure\JsonApi\SerializerRegistryInterface $serializers + */ + public function __construct($data, SerializerRegistryInterface $serializers) + { + $this->resources = $this->buildResources($data, $serializers); + } + + /** + * Convert an array of raw data to Resource objects. + * + * @param mixed $data + * @param \Tobscure\JsonApi\SerializerRegistryInterface $serializers + * @return \Tobscure\JsonApi\Resource[] + */ + protected function buildResources($data, SerializerRegistryInterface $serializers) + { + $resources = []; + + foreach ($data as $resource) { + if (! ($resource instanceof Resource)) { + $resource = new Resource($resource, $serializers->getFromSerializable($resource)); + } + + $resources[] = $resource; + } + + return $resources; + } + + /** + * {@inheritdoc} + */ + public function getResources() + { + return $this->resources; + } + + /** + * Set the resources array. + * + * @param array $resources + * + * @return void + */ + public function setResources($resources) + { + $this->resources = $resources; + } + + /** + * Request a relationship to be included for all resources. + * + * @param string|array $relationships + * + * @return $this + */ + public function with($relationships) + { + foreach ($this->resources as $resource) { + $resource->with($relationships); + } + + return $this; + } + + /** + * Request a restricted set of fields. + * + * @param array|null $fields + * + * @return $this + */ + public function fields($fields) + { + foreach ($this->resources as $resource) { + $resource->fields($fields); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return array_map(function (Resource $resource) { + return $resource->toArray(); + }, $this->resources); + } + + /** + * {@inheritdoc} + */ + public function toIdentifier() + { + return array_map(function (Resource $resource) { + return $resource->toIdentifier(); + }, $this->resources); + } +} diff --git a/src/PolymorphicResource.php b/src/PolymorphicResource.php new file mode 100644 index 0000000..8c3128e --- /dev/null +++ b/src/PolymorphicResource.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\JsonApi; + +use Tobscure\JsonApi\Resource as JsonApiResource; + +class PolymorphicResource extends JsonApiResource +{ + /** + * @param mixed $data + * @param \Tobscure\JsonApi\SerializerRegistryInterface $serializers + */ + public function __construct($data, SerializerRegistryInterface $serializers) + { + parent::__construct($data, $serializers->getFromSerializable($data)); + } +} diff --git a/src/SerializerRegistryInterface.php b/src/SerializerRegistryInterface.php new file mode 100644 index 0000000..e77b1e2 --- /dev/null +++ b/src/SerializerRegistryInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\JsonApi; + +interface SerializerRegistryInterface +{ + /** + * Instantiate serializer from the serializable object. + * + * @param object $serializable + * @return \Tobscure\JsonApi\SerializerInterface + */ + public function getFromSerializable($serializable); +} From 82cfcdb9eb0178e9c2fe4804ce8de9f7549e854f Mon Sep 17 00:00:00 2001 From: a-komarev Date: Sun, 9 Dec 2018 19:53:33 +0300 Subject: [PATCH 2/4] Make abstract serializer abstract --- src/AbstractSerializerRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractSerializerRegistry.php b/src/AbstractSerializerRegistry.php index bfccd73..ee4d2dd 100644 --- a/src/AbstractSerializerRegistry.php +++ b/src/AbstractSerializerRegistry.php @@ -13,7 +13,7 @@ use RuntimeException; -class AbstractSerializerRegistry implements SerializerRegistryInterface +abstract class AbstractSerializerRegistry implements SerializerRegistryInterface { /** * @var array From c91d941d7c4ae11f9a242b456966114cbfda0b65 Mon Sep 17 00:00:00 2001 From: a-komarev Date: Sun, 9 Dec 2018 21:02:20 +0300 Subject: [PATCH 3/4] Add tests --- tests/PolymorphicCollectionTest.php | 65 +++++++++++++++++++ tests/PolymorphicResourceTest.php | 34 ++++++++++ tests/Stubs/Serializables/Bike.php | 24 +++++++ tests/Stubs/Serializables/Car.php | 24 +++++++ tests/Stubs/Serializables/Garage.php | 25 +++++++ .../Stubs/Serializables/GarageSerializer.php | 37 +++++++++++ tests/Stubs/Serializers/BikeSerializer.php | 26 ++++++++ tests/Stubs/Serializers/CarSerializer.php | 26 ++++++++ .../Serializers/VehicleSerializerRegistry.php | 24 +++++++ 9 files changed, 285 insertions(+) create mode 100644 tests/PolymorphicCollectionTest.php create mode 100644 tests/PolymorphicResourceTest.php create mode 100644 tests/Stubs/Serializables/Bike.php create mode 100644 tests/Stubs/Serializables/Car.php create mode 100644 tests/Stubs/Serializables/Garage.php create mode 100644 tests/Stubs/Serializables/GarageSerializer.php create mode 100644 tests/Stubs/Serializers/BikeSerializer.php create mode 100644 tests/Stubs/Serializers/CarSerializer.php create mode 100644 tests/Stubs/Serializers/VehicleSerializerRegistry.php diff --git a/tests/PolymorphicCollectionTest.php b/tests/PolymorphicCollectionTest.php new file mode 100644 index 0000000..c26ad4d --- /dev/null +++ b/tests/PolymorphicCollectionTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Element; + +use Tobscure\JsonApi\PolymorphicCollection; +use Tobscure\JsonApi\PolymorphicResource; +use Tobscure\Tests\JsonApi\AbstractTestCase; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Bike; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Car; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Garage; +use Tobscure\Tests\JsonApi\Stubs\Serializers\VehicleSerializerRegistry; + +class PolymorphicCollectionTest extends AbstractTestCase +{ + public function testToArrayReturnsArrayOfResources() + { + $car = new Car(1); + $bike = new Bike(2); + $garage = new Garage(4, [$car, $bike]); + $serializerRegistry = new VehicleSerializerRegistry(); + + $collection = new PolymorphicCollection($garage->vehicles, $serializerRegistry); + + $resource1 = new PolymorphicResource($car, $serializerRegistry); + $resource2 = new PolymorphicResource($bike, $serializerRegistry); + $this->assertSame([$resource1->toArray(), $resource2->toArray()], $collection->toArray()); + } + + public function testToArrayReturnsArrayOfPolymorphicResources() + { + $car = new Car(1); + $bike = new Bike(2); + $garage = new Garage(4, [$car, $bike]); + $serializerRegistry = new VehicleSerializerRegistry(); + + $collection = new PolymorphicCollection($garage->vehicles, $serializerRegistry); + + $resources = $collection->getResources(); + $this->assertSame('cars', $resources[0]->getType()); + $this->assertSame('bikes', $resources[1]->getType()); + } + + public function testToIdentifierReturnsArrayOfResourceIdentifiers() + { + $car = new Car(1); + $bike = new Bike(2); + $garage = new Garage(4, [$car, $bike]); + $serializerRegistry = new VehicleSerializerRegistry(); + + $collection = new PolymorphicCollection($garage->vehicles, $serializerRegistry); + + $resource1 = new PolymorphicResource($car, $serializerRegistry); + $resource2 = new PolymorphicResource($bike, $serializerRegistry); + $this->assertSame([$resource1->toIdentifier(), $resource2->toIdentifier()], $collection->toIdentifier()); + } +} diff --git a/tests/PolymorphicResourceTest.php b/tests/PolymorphicResourceTest.php new file mode 100644 index 0000000..d3f5737 --- /dev/null +++ b/tests/PolymorphicResourceTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Element; + +use Tobscure\JsonApi\PolymorphicResource; +use Tobscure\Tests\JsonApi\AbstractTestCase; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Bike; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Car; +use Tobscure\Tests\JsonApi\Stubs\Serializers\VehicleSerializerRegistry; + +class PolymorphicResourceTest extends AbstractTestCase +{ + public function testPolymorphicResourceType() + { + $car = new Car(123); + $bike = new Bike(234); + $serializerRegistry = new VehicleSerializerRegistry(); + + $resource1 = new PolymorphicResource($car, $serializerRegistry); + $resource2 = new PolymorphicResource($bike, $serializerRegistry); + + $this->assertSame('cars', $resource1->getType()); + $this->assertSame('bikes', $resource2->getType()); + } +} diff --git a/tests/Stubs/Serializables/Bike.php b/tests/Stubs/Serializables/Bike.php new file mode 100644 index 0000000..fd1a6f3 --- /dev/null +++ b/tests/Stubs/Serializables/Bike.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializables; + +class Bike +{ + public $id; + + public $name = 'Bike'; + + public function __construct($id) + { + $this->id = $id; + } +} diff --git a/tests/Stubs/Serializables/Car.php b/tests/Stubs/Serializables/Car.php new file mode 100644 index 0000000..e80b488 --- /dev/null +++ b/tests/Stubs/Serializables/Car.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializables; + +class Car +{ + public $id; + + public $name = 'Car'; + + public function __construct($id) + { + $this->id = $id; + } +} diff --git a/tests/Stubs/Serializables/Garage.php b/tests/Stubs/Serializables/Garage.php new file mode 100644 index 0000000..efa87f0 --- /dev/null +++ b/tests/Stubs/Serializables/Garage.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializables; + +class Garage +{ + public $id; + + public $vehicles = []; + + public function __construct($id, array $vehicles = []) + { + $this->id = $id; + $this->vehicles = $vehicles; + } +} diff --git a/tests/Stubs/Serializables/GarageSerializer.php b/tests/Stubs/Serializables/GarageSerializer.php new file mode 100644 index 0000000..553de8c --- /dev/null +++ b/tests/Stubs/Serializables/GarageSerializer.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializers; + +use Tobscure\JsonApi\AbstractSerializer; +use Tobscure\JsonApi\PolymorphicCollection; +use Tobscure\JsonApi\Relationship; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Garage; + +class GarageSerializer extends AbstractSerializer +{ + protected $type = 'garages'; + + public function getAttributes($garage, array $fields = null) + { + return []; + } + + public function vehicles(Garage $garage) + { + $element = new PolymorphicCollection( + $garage->vehicles, + new VehicleSerializerRegistry() + ); + + return new Relationship($element); + } +} diff --git a/tests/Stubs/Serializers/BikeSerializer.php b/tests/Stubs/Serializers/BikeSerializer.php new file mode 100644 index 0000000..ca7451a --- /dev/null +++ b/tests/Stubs/Serializers/BikeSerializer.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializers; + +use Tobscure\JsonApi\AbstractSerializer; + +class BikeSerializer extends AbstractSerializer +{ + protected $type = 'bikes'; + + public function getAttributes($bike, array $fields = null) + { + return [ + 'name' => $bike->name, + ]; + } +} diff --git a/tests/Stubs/Serializers/CarSerializer.php b/tests/Stubs/Serializers/CarSerializer.php new file mode 100644 index 0000000..005f72f --- /dev/null +++ b/tests/Stubs/Serializers/CarSerializer.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializers; + +use Tobscure\JsonApi\AbstractSerializer; + +class CarSerializer extends AbstractSerializer +{ + protected $type = 'cars'; + + public function getAttributes($car, array $fields = null) + { + return [ + 'name' => $car->name, + ]; + } +} diff --git a/tests/Stubs/Serializers/VehicleSerializerRegistry.php b/tests/Stubs/Serializers/VehicleSerializerRegistry.php new file mode 100644 index 0000000..23d9a65 --- /dev/null +++ b/tests/Stubs/Serializers/VehicleSerializerRegistry.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobscure\Tests\JsonApi\Stubs\Serializers; + +use Tobscure\JsonApi\AbstractSerializerRegistry; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Bike; +use Tobscure\Tests\JsonApi\Stubs\Serializables\Car; + +class VehicleSerializerRegistry extends AbstractSerializerRegistry +{ + protected $serializers = [ + Car::class => CarSerializer::class, + Bike::class => BikeSerializer::class, + ]; +} From 68cdc39a5b8cfc548fa7c075caa1ba0ae756607b Mon Sep 17 00:00:00 2001 From: a-komarev Date: Sun, 9 Dec 2018 21:06:02 +0300 Subject: [PATCH 4/4] [skip ci] Code style fix --- src/AbstractSerializerRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AbstractSerializerRegistry.php b/src/AbstractSerializerRegistry.php index ee4d2dd..ddc05d2 100644 --- a/src/AbstractSerializerRegistry.php +++ b/src/AbstractSerializerRegistry.php @@ -30,7 +30,7 @@ public function getFromSerializable($serializable) { $class = get_class($serializable); - if (!isset($this->serializers[$class])) { + if (! isset($this->serializers[$class])) { throw new RuntimeException("Serializer with name `{$class}` is not exists"); }