diff --git a/src/ResourceTrait.php b/src/ResourceTrait.php index 9b4685c..ae26649 100644 --- a/src/ResourceTrait.php +++ b/src/ResourceTrait.php @@ -64,11 +64,27 @@ public function getResourceRelationships(array $linked = []) $keys = array_keys($resolvedFields); $relationships = array_fill_keys($keys, null); + + $closureFields = array_filter($resolvedFields, function($value, $key) { + return is_callable($value); + }, ARRAY_FILTER_USE_BOTH); + + foreach ($closureFields as $name => $value) { + $result = call_user_func($value, $this, $name); + if (isset($result['data'])) { + $relationships[$name] = $result['data']; + } + } + $linkedFields = array_intersect($keys, $linked); foreach ($linkedFields as $name) { $definition = $resolvedFields[$name]; - $relationships[$name] = is_string($definition) ? $this->$definition : call_user_func($definition, $this, $name); + $result = is_string($definition) ? $this->$definition : call_user_func($definition, $this, $name); + + $relationships[$name] = (is_array($result) && isset($result['resource'])) + ? $result['resource'] + : $result; } return $relationships; diff --git a/tests/SerializerTest.php b/tests/SerializerTest.php index eba491d..13f81f4 100644 --- a/tests/SerializerTest.php +++ b/tests/SerializerTest.php @@ -4,11 +4,29 @@ */ namespace tuyakhov\jsonapi\tests; +use tuyakhov\jsonapi\ResourceIdentifierInterface; use tuyakhov\jsonapi\tests\data\ResourceModel; use tuyakhov\jsonapi\Serializer; use yii\base\InvalidValueException; use yii\data\ArrayDataProvider; +class ResourceModelIdentifier implements ResourceIdentifierInterface { + private $_id; + private $_type; + + public function __construct($id, $type) { + $this->_id = $id; + $this->_type = $type; + } + public function getId() { + return $this->_id; + } + + public function getType() { + return $this->_type; + } +} + class SerializerTest extends TestCase { protected function setUp() @@ -55,6 +73,145 @@ public function testSerializeModelErrors() ], $serializer->serialize($model)); } + public function testSerializeModelDataAddingNoDataValuesIfNotSpecified() + { + $serializer = new Serializer(); + ResourceModel::$id = 123; + $model = new ResourceModel(); + $this->assertSame([ + 'data' => [ + 'id' => '123', + 'type' => 'resource-models', + 'attributes' => [ + 'field1' => 'test', + 'field2' => 2, + ], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123'] + ] + ] + ], $serializer->serialize($model)); + + ResourceModel::$fields = ['first_name']; + ResourceModel::$extraFields = ['extraField1']; + $model->extraField1 = new ResourceModel(); + $relationship = [ + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123/relationships/extra-field1'], + 'related' => ['href' => 'http://example.com/resource/123/extra-field1'], + ] + ]; + $resource = [ + 'id' => '123', + 'type' => 'resource-models', + 'attributes' => [ + 'first-name' => 'Bob', + ], + 'relationships' => [ + 'extra-field1' => [ + 'links' => $relationship['links'] + ] + ], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123'] + ] + ]; + $expected = [ + 'data' => $resource + ]; + $expected['data']['relationships']['extra-field1'] = $relationship; + $this->assertSame($expected, $serializer->serialize($model)); + } + + public function testSerializeModelDataAddDataValuesIfOptIn() + { + $serializer = new Serializer(); + ResourceModel::$id = 123; + $model = new ResourceModel(); + $this->assertSame([ + 'data' => [ + 'id' => '123', + 'type' => 'resource-models', + 'attributes' => [ + 'field1' => 'test', + 'field2' => 2, + ], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123'] + ] + ] + ], $serializer->serialize($model)); + + ResourceModel::$fields = ['first_name']; + ResourceModel::$extraFields = [ + 'extraField1' => function() { return new ResourceModel(); }, + ]; + + $model->extraField1 = function() { return new ResourceModel(); }; + $relationship = [ + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123/relationships/extra-field1'], + 'related' => ['href' => 'http://example.com/resource/123/extra-field1'], + ] + ]; + $resource = [ + 'id' => '123', + 'type' => 'resource-models', + 'attributes' => [ + 'first-name' => 'Bob', + ], + 'relationships' => [ + 'extra-field1' => [ + 'links' => $relationship['links'] + ] + ], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123'] + ] + ]; + $expected = [ + 'data' => $resource + ]; + $expected['data']['relationships']['extra-field1'] = $relationship; + $this->assertSame($expected, $serializer->serialize($model)); + + ResourceModel::$extraFields = [ + 'extraField1' => function() { + return [ + 'resource' => new ResourceModel(), + 'data' => new ResourceModelIdentifier( "123",'resource-models'), + ]; + } + ]; + $relationship = [ + 'data' => ['id' => '123', 'type' => 'resource-models'], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123/relationships/extra-field1'], + 'related' => ['href' => 'http://example.com/resource/123/extra-field1'], + ] + ]; + $resource = [ + 'id' => '123', + 'type' => 'resource-models', + 'attributes' => [ + 'first-name' => 'Bob', + ], + 'relationships' => [ + 'extra-field1' => [ + 'links' => $relationship['links'] + ] + ], + 'links' => [ + 'self' => ['href' => 'http://example.com/resource/123'] + ] + ]; + $expected = [ + 'data' => $resource + ]; + $expected['data']['relationships']['extra-field1'] = $relationship; + $this->assertSame($expected, $serializer->serialize($model)); + } + public function testSerializeModelData() { $serializer = new Serializer(); @@ -108,6 +265,11 @@ public function testSerializeModelData() $expected['included'][] = $resource; $expected['data']['relationships']['extra-field1'] = $relationship; $this->assertSame($expected, $serializer->serialize($model)); + + $model->extraField1 = [ + 'resource' => new ResourceModel(), + ]; + $this->assertSame($expected, $serializer->serialize($model)); } public function testExpand()