Skip to content

Commit

Permalink
Merge pull request #84 from HennerM/master
Browse files Browse the repository at this point in the history
Support to-many relations in included resources.
  • Loading branch information
nilportugues authored Mar 13, 2017
2 parents 89204a8 + 2f97f49 commit f2c6772
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 41 deletions.
65 changes: 53 additions & 12 deletions src/Helpers/DataIncludedHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ protected static function addToRelationshipsArray(
foreach ($value as $propertyName => $attribute) {
if (PropertyHelper::isAttributeProperty($mappings, $propertyName, $type)) {
$propertyName = DataAttributesHelper::transformToValidMemberName($propertyName);
if (\array_key_exists(Serializer::MAP_TYPE, $attribute)
&& count(array_values($attribute[Serializer::SCALAR_VALUE])) > 0
&& \array_key_exists(Serializer::CLASS_IDENTIFIER_KEY, array_values($attribute[Serializer::SCALAR_VALUE])[0])) {
self::setResponseDataIncluded($mappings, $value, $data);
continue;
}

if (\array_key_exists(Serializer::CLASS_IDENTIFIER_KEY, $attribute)) {
self::setResponseDataIncluded($mappings, $value, $data);
Expand Down Expand Up @@ -155,17 +161,43 @@ protected static function addToIncludedArray(array &$mappings, array &$data, arr
$arrayData[JsonApiTransformer::RELATIONSHIPS_KEY] = $relationships;
}

$data[JsonApiTransformer::INCLUDED_KEY][] = \array_filter($arrayData);
$existingIndex = false;
if (array_key_exists(JsonApiTransformer::INCLUDED_KEY, $data)) {
$existingIndex = self::findIncludedIndex($data[JsonApiTransformer::INCLUDED_KEY], $arrayData[JsonApiTransformer::ID_KEY], $arrayData[JsonApiTransformer::TYPE_KEY]);
}
if ($existingIndex !== false) {
$data[JsonApiTransformer::INCLUDED_KEY][$existingIndex] = \array_filter(\array_merge($data[JsonApiTransformer::INCLUDED_KEY][$existingIndex],
\array_filter($arrayData, self::filterEmptyArray())), self::filterEmptyArray());
} else {
$data[JsonApiTransformer::INCLUDED_KEY][] = \array_filter($arrayData, self::filterEmptyArray());
}
}
}

if (!empty($data[JsonApiTransformer::INCLUDED_KEY])) {
$data[JsonApiTransformer::INCLUDED_KEY] = \array_values(
\array_unique($data[JsonApiTransformer::INCLUDED_KEY], SORT_REGULAR)
);
}
}

protected static function filterEmptyArray()
{
return function($value) {
return $value !== null && (!is_array($value) || count($value) > 0);
};
}

protected static function findIncludedIndex($includedData, $idNeedle, $typeNeedle)
{
foreach ($includedData as $key => $value) {
if ($value[JsonApiTransformer::ID_KEY] === $idNeedle && $value[JsonApiTransformer::TYPE_KEY] === $typeNeedle) {
return $key;
}
}

return false;
}

/**
* @param array $includedData
*
Expand Down Expand Up @@ -201,34 +233,43 @@ protected static function addRelationshipsToIncludedResources(

continue;
}

if (\is_array($attribute) && \array_key_exists(Serializer::MAP_TYPE, $attribute)) {
$relations = [];
$elements = $attribute[Serializer::SCALAR_VALUE];
foreach ($elements as $arrayValue) {
if (\array_key_exists(Serializer::CLASS_IDENTIFIER_KEY, $arrayValue)) {
$relations[] = PropertyHelper::setResponseDataTypeAndId($mappings, $arrayValue);
}
}
if (count($relations) > 0) {
$data[DataLinksHelper::camelCaseToUnderscore($propertyName)][JsonApiTransformer::DATA_KEY] = $relations;
}
continue;
}
}
}
}

/**
* Enforce with this check that each property leads to a data element.
*
* @param array $value
* @param array $arrayData
*
* @return array
*/
protected static function normalizeRelationshipData(array &$value, array $arrayData)
{
$relationships = [];
foreach ($arrayData[JsonApiTransformer::RELATIONSHIPS_KEY] as $attribute => $value) {
foreach ($arrayData[JsonApiTransformer::RELATIONSHIPS_KEY] as $attribute => $attributeValue) {
//if $value[data] is not found, get next level where [data] should exist.
if (!array_key_exists(JsonApiTransformer::DATA_KEY, $value)) {
array_shift($value);
if (!array_key_exists(JsonApiTransformer::DATA_KEY, $attributeValue)) {
array_shift($attributeValue);
}

//If one value in $value[data], remove the array and make it object only.
if (1 === count($value[JsonApiTransformer::DATA_KEY])) {
$value = reset($value[JsonApiTransformer::DATA_KEY]);
}

if (count($value[JsonApiTransformer::DATA_KEY]) > 0) {
$relationships[$attribute] = $value;
if (count($attributeValue[JsonApiTransformer::DATA_KEY]) > 0) {
$relationships[$attribute] = $attributeValue;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Helpers/DataLinksHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ protected static function toUnderScore($original, $idValues, $url)
*
* @return string
*/
protected static function camelCaseToUnderscore($camel, $splitter = '_')
public static function camelCaseToUnderscore($camel, $splitter = '_')
{
$camel = \preg_replace(
'/(?!^)[[:upper:]][[:lower:]]/',
Expand Down
7 changes: 6 additions & 1 deletion tests/Behaviour/Dummy/ComplexObject/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,24 @@ class Comment
*/
private $oneDate;

/**
* @var User[]
*/
private $likes;
/**
* @param CommentId $id
* @param $comment
* @param User $user
* @param array $dates
*/
public function __construct(CommentId $id, $comment, User $user, array $dates, \DateTime $d = null)
public function __construct(CommentId $id, $comment, User $user, array $dates, \DateTime $d = null, $likes = [])
{
$this->commentId = $id;
$this->comment = $comment;
$this->user = $user;
$this->dates = $dates;
$this->oneDate = $d;
$this->likes = $likes;
}

/**
Expand Down
12 changes: 11 additions & 1 deletion tests/Behaviour/HelperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,17 @@ public static function complexPost()
'created_at' => (new DateTime('2015-07-18T12:13:00+00:00'))->format('c'),
'accepted_at' => (new DateTime('2015-07-19T00:00:00+00:00'))->format('c'),
],
new DateTime('2015-07-18T12:13:00+00:00')
new DateTime('2015-07-18T12:13:00+00:00'),
[
new User(
new UserId(3),
'First Liker'
),
new User(
new UserId(4),
'Second Liker'
)
]
),
]
);
Expand Down
48 changes: 48 additions & 0 deletions tests/Behaviour/JsonApiTransformerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,42 @@ public function testItWillSerializeToJsonApiAComplexObject()
}
}
},
{
"type":"user",
"id":"3",
"attributes":{
"name":"First Liker"
},
"links":{
"self":{
"href":"http://example.com/users/3"
},
"friends":{
"href":"http://example.com/users/3/friends"
},
"comments":{
"href":"http://example.com/users/3/comments"
}
}
},
{
"type":"user",
"id":"4",
"attributes":{
"name":"Second Liker"
},
"links":{
"self":{
"href":"http://example.com/users/4"
},
"friends":{
"href":"http://example.com/users/4/friends"
},
"comments":{
"href":"http://example.com/users/4/comments"
}
}
},
{
"type":"user",
"id":"2",
Expand Down Expand Up @@ -174,6 +210,18 @@ public function testItWillSerializeToJsonApiAComplexObject()
"type":"user",
"id":"2"
}
},
"likes": {
"data": [
{
"type": "user",
"id":"3"
},
{
"type": "user",
"id":"4"
}
]
}
},
"links":{
Expand Down
32 changes: 6 additions & 26 deletions tests/Integrations/Doctrine/DoctrineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,12 @@ public function testSecondLevelNestingEntitySerialize()
"type":"post",
"id":"1",
"attributes":{
"description":"Description test"
"description":"Description test",
"date":{
"date":"2016-07-12 16:30:12.000000",
"timezone_type":3,
"timezone":"Europe/Madrid"
}
},
"relationships":{
"customer":{
Expand Down Expand Up @@ -228,31 +233,6 @@ public function testSecondLevelNestingEntitySerialize()
"href":"http://example.com/comment/1"
}
}
},
{
"type":"post",
"id":"1",
"attributes":{
"date":{
"date":"2016-07-12 16:30:12.000000",
"timezone_type":3,
"timezone":"Europe/Madrid"
},
"description":"Description test"
},
"relationships":{
"customer":{
"data":{
"type":"customer",
"id":"1"
}
}
},
"links":{
"self":{
"href":"http://example.com/post/1"
}
}
}
],
"links":{
Expand Down

0 comments on commit f2c6772

Please sign in to comment.