Skip to content

Commit

Permalink
Add dependency checker
Browse files Browse the repository at this point in the history
  • Loading branch information
bakura10 committed Mar 16, 2014
1 parent 7b678b5 commit 67bd733
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 9 deletions.
23 changes: 21 additions & 2 deletions src/ZfrRest/View/Renderer/DefaultResourceRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class DefaultResourceRenderer extends AbstractResourceRenderer
*/
protected $hydratorPluginManager;

/**
* @var array
*/
protected $circularChecker = [];

/**
* @param ResourceMetadataFactory $resourceMetadataFactory
* @param HydratorPluginManager $hydratorManager
Expand All @@ -70,6 +75,10 @@ public function render($nameOrModel, $values = null)
$data = $resource->getData();
$resourceMetadata = $resource->getMetadata();

// We start a new extraction context, to avoid circular extraction
$extractedClass = $resourceMetadata->getReflectionClass()->getName();
$this->circularChecker[$extractedClass] = true;

$payload = [];

// If the resource is a collection, we render each item individually
Expand All @@ -83,6 +92,9 @@ public function render($nameOrModel, $values = null)

$payload = array_merge($this->renderMeta($resource), $payload);

// We're done with the context of this class
unset($this->circularChecker[$extractedClass]);

return $payload;
}

Expand Down Expand Up @@ -139,6 +151,7 @@ protected function renderAssociations(array $data, ResourceMetadataInterface $re
$isCollectionValued = $classMetadata->isCollectionValuedAssociation($association);
$data[$association] = $this->renderAssociation(
$data[$association],
$classMetadata->getAssociationTargetClass($association),
$extractionStrategy,
$isCollectionValued
);
Expand All @@ -151,13 +164,14 @@ protected function renderAssociations(array $data, ResourceMetadataInterface $re
* Render a single association of a resource
*
* @param object $object
* @param string $targetClass
* @param string $extractionStrategy
* @param bool $isCollectionValued
* @return array|null
*/
protected function renderAssociation($object, $extractionStrategy, $isCollectionValued)
protected function renderAssociation($object, $targetClass, $extractionStrategy, $isCollectionValued)
{
$associationResourceMetadata = $this->resourceMetadataFactory->getMetadataForClass(get_class($object));
$associationResourceMetadata = $this->resourceMetadataFactory->getMetadataForClass($targetClass);
$classMetadata = $associationResourceMetadata->getClassMetadata();

// If the association is not a collection valued, we wrap the object around an array so that we do
Expand All @@ -166,6 +180,11 @@ protected function renderAssociation($object, $extractionStrategy, $isCollection
$object = [$object];
}

// Avoid circular extraction
if (isset($this->circularChecker[$targetClass])) {
$extractionStrategy = ResourceInterface::ASSOCIATION_EXTRACTION_ID;
}

$association = null;

switch($extractionStrategy) {
Expand Down
22 changes: 22 additions & 0 deletions tests/ZfrRestTest/Asset/Resource/Metadata/Annotation/Tweet.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class Tweet
*/
protected $id;

/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="tweets")
* @REST\Association(extraction="EMBED")
*/
protected $user;

/**
* @ORM\Column(type="string")
*/
Expand All @@ -54,6 +60,22 @@ public function getId()
return $this->id;
}

/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}

/**
* @return User
*/
public function getUser()
{
return $this->user;
}

/**
* @param string $content
*/
Expand Down
9 changes: 5 additions & 4 deletions tests/ZfrRestTest/Asset/Resource/Metadata/Annotation/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ class User
protected $address;

/**
* @ORM\OneToMany(targetEntity="Tweet")
* @ORM\OneToMany(targetEntity="Tweet", mappedBy="user")
* @REST\Association(extraction="ID")
*/
//protected $tweets;
protected $tweets;

public function __construct()
{
Expand Down Expand Up @@ -110,14 +110,15 @@ public function getAddress()
*/
public function addTweet(Tweet $tweet)
{
$tweet->setUser($this);
$this->tweets->add($tweet);
}

/**
* @return ArrayCollection
*/
/*public function getTweets()
public function getTweets()
{
return $this->tweets;
}*/
}
}
88 changes: 85 additions & 3 deletions tests/ZfrRestTest/View/Renderer/DefaultResourceRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use ZfrRest\View\Model\ResourceModel;
use ZfrRest\View\Renderer\DefaultResourceRenderer;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\Address;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\Tweet;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\User;
use ZfrRestTest\Util\ServiceManagerFactory;

Expand Down Expand Up @@ -78,6 +79,7 @@ public function testCanRenderSingleResourceWithoutAssociation()

// In this test, we enforce that association extraction is set to NONE
$metadata->propertyMetadata['associations']['address']['extraction'] = 'NONE';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'NONE';

$resourceModel = new ResourceModel(new Resource($user, $metadata));
$payload = $this->resourceRenderer->render($resourceModel);
Expand All @@ -95,25 +97,35 @@ public function testCanRenderSingleResourceWithAssociationAsId()
$address = new Address();
$address->setId(43);

$tweet1 = new Tweet();
$tweet1->setId(565);

$tweet2 = new Tweet();
$tweet2->setId(5446);

$user = new User();
$user->setId(2);
$user->setUsername('bakura');
$user->setAddress($address);
$user->addTweet($tweet1);
$user->addTweet($tweet2);

$metadata = $this->resourceMetadataFactory->getMetadataForClass(
'ZfrRestTest\Asset\Resource\Metadata\Annotation\User'
);

// In this test, we enforce that association extraction is set to ID
$metadata->propertyMetadata['associations']['address']['extraction'] = 'ID';
$metadata->propertyMetadata['tweets']['address']['extraction'] = 'ID';

$resourceModel = new ResourceModel(new Resource($user, $metadata));
$payload = $this->resourceRenderer->render($resourceModel);

$expectedPayload = [
'id' => 2,
'username' => 'bakura',
'address' => 43
'address' => 43,
'tweets' => [565, 5446]
];

$this->assertEquals($expectedPayload, $payload);
Expand All @@ -125,17 +137,28 @@ public function testCanRenderSingleResourceWithAssociationAsEmbed()
$address->setId(43);
$address->setCountry('France');

$tweet1 = new Tweet();
$tweet1->setId(565);
$tweet1->setContent('Kung-fu fighting');

$tweet2 = new Tweet();
$tweet2->setId(5446);
$tweet2->setContent('Ohayou gozaimasu');

$user = new User();
$user->setId(2);
$user->setUsername('bakura');
$user->setAddress($address);
$user->addTweet($tweet1);
$user->addTweet($tweet2);

$metadata = $this->resourceMetadataFactory->getMetadataForClass(
'ZfrRestTest\Asset\Resource\Metadata\Annotation\User'
);

// In this test, we enforce that association extraction is set to EMBED
$metadata->propertyMetadata['associations']['address']['extraction'] = 'EMBED';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'EMBED';

$resourceModel = new ResourceModel(new Resource($user, $metadata));
$payload = $this->resourceRenderer->render($resourceModel);
Expand All @@ -146,6 +169,10 @@ public function testCanRenderSingleResourceWithAssociationAsEmbed()
'address' => [
'id' => 43,
'country' => 'France'
],
'tweets' => [
['id' => 565, 'content' => 'Kung-fu fighting', 'user' => 2],
['id' => 5446, 'content' => 'Ohayou gozaimasu', 'user' => 2]
]
];

Expand All @@ -157,22 +184,35 @@ public function testCanRenderCollectionResourceWithoutAssociation()
$address1 = new Address();
$address2 = new Address();

$tweet1 = new Tweet();
$tweet1->setId(565);

$tweet2 = new Tweet();
$tweet2->setId(5446);

$tweet3 = new Tweet();
$tweet3->setId(5565);

$user1 = new User();
$user1->setId(2);
$user1->setUsername('bakura');
$user1->setAddress($address1);
$user1->addTweet($tweet1);
$user1->addTweet($tweet2);

$user2 = new User();
$user2->setId(3);
$user2->setUsername('ocramius');
$user2->setAddress($address2);
$user2->addTweet($tweet3);

$metadata = $this->resourceMetadataFactory->getMetadataForClass(
'ZfrRestTest\Asset\Resource\Metadata\Annotation\User'
);

// In this test, we enforce that association extraction is set to NONE
$metadata->propertyMetadata['associations']['address']['extraction'] = 'NONE';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'NONE';

$resourceModel = new ResourceModel(new Resource([$user1, $user2], $metadata));
$payload = $this->resourceRenderer->render($resourceModel);
Expand Down Expand Up @@ -201,22 +241,38 @@ public function testCanRenderCollectionResourceWithAssociationAsId()
$address2 = new Address();
$address2->setId(344);

$tweet1 = new Tweet();
$tweet1->setId(565);
$tweet1->setContent('Kung-fu fighting');

$tweet2 = new Tweet();
$tweet2->setId(5446);
$tweet2->setContent('Ohayou gozaimasu');

$tweet3 = new Tweet();
$tweet3->setId(5565);
$tweet3->setContent('Sayounara');

$user1 = new User();
$user1->setId(2);
$user1->setUsername('bakura');
$user1->setAddress($address1);
$user1->addTweet($tweet1);
$user1->addTweet($tweet2);

$user2 = new User();
$user2->setId(3);
$user2->setUsername('ocramius');
$user2->setAddress($address2);
$user2->addTweet($tweet3);

$metadata = $this->resourceMetadataFactory->getMetadataForClass(
'ZfrRestTest\Asset\Resource\Metadata\Annotation\User'
);

// In this test, we enforce that association extraction is set to ID
$metadata->propertyMetadata['associations']['address']['extraction'] = 'ID';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'ID';

$resourceModel = new ResourceModel(new Resource([$user1, $user2], $metadata));
$payload = $this->resourceRenderer->render($resourceModel);
Expand All @@ -226,12 +282,14 @@ public function testCanRenderCollectionResourceWithAssociationAsId()
[
'id' => 2,
'username' => 'bakura',
'address' => 45
'address' => 45,
'tweets' => [565, 5446]
],
[
'id' => 3,
'username' => 'ocramius',
'address' => 344
'address' => 344,
'tweets' => [5565]
]
]
];
Expand All @@ -249,22 +307,38 @@ public function testCanRenderCollectionResourceWithAssociationAsEmbed()
$address2->setId(344);
$address2->setCountry('Italia');

$tweet1 = new Tweet();
$tweet1->setId(565);
$tweet1->setContent('Kung-fu fighting');

$tweet2 = new Tweet();
$tweet2->setId(5446);
$tweet2->setContent('Ohayou gozaimasu');

$tweet3 = new Tweet();
$tweet3->setId(5565);
$tweet3->setContent('Sayounara');

$user1 = new User();
$user1->setId(2);
$user1->setUsername('bakura');
$user1->setAddress($address1);
$user1->addTweet($tweet1);
$user1->addTweet($tweet2);

$user2 = new User();
$user2->setId(3);
$user2->setUsername('ocramius');
$user2->setAddress($address2);
$user2->addTweet($tweet3);

$metadata = $this->resourceMetadataFactory->getMetadataForClass(
'ZfrRestTest\Asset\Resource\Metadata\Annotation\User'
);

// In this test, we enforce that association extraction is set to EMBED
$metadata->propertyMetadata['associations']['address']['extraction'] = 'EMBED';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'EMBED';

$resourceModel = new ResourceModel(new Resource([$user1, $user2], $metadata));
$payload = $this->resourceRenderer->render($resourceModel);
Expand All @@ -277,6 +351,10 @@ public function testCanRenderCollectionResourceWithAssociationAsEmbed()
'address' => [
'id' => 45,
'country' => 'France'
],
'tweets' => [
['id' => 565, 'content' => 'Kung-fu fighting', 'user' => 2],
['id' => 5446, 'content' => 'Ohayou gozaimasu', 'user' => 2]
]
],
[
Expand All @@ -285,6 +363,9 @@ public function testCanRenderCollectionResourceWithAssociationAsEmbed()
'address' => [
'id' => 344,
'country' => 'Italia'
],
'tweets' => [
['id' => 5565, 'content' => 'Sayounara', 'user' => 3]
]
]
]
Expand Down Expand Up @@ -314,6 +395,7 @@ public function testCanRenderCollectionResourceAsPaginator()

// In this test, we enforce that association extraction is set to NONE
$metadata->propertyMetadata['associations']['address']['extraction'] = 'NONE';
$metadata->propertyMetadata['associations']['tweets']['extraction'] = 'NONE';

$paginator = new Paginator(new ArrayAdapter([$user1, $user2]));

Expand Down

0 comments on commit 67bd733

Please sign in to comment.