Skip to content

Commit

Permalink
Add PASS_THRU extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
bakura10 committed Apr 19, 2014
1 parent 335a424 commit 55943a6
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 6 deletions.
4 changes: 2 additions & 2 deletions docs/08. Mapping reference.md
Expand Up @@ -39,8 +39,8 @@ Otherwise, this URI will returns a 404. By default, this is set to false for bet
works if `routable` is set to true.
* `extraction`: defines how an association is rendered by the resource renderer. This can take the values `NONE` (the
association is not rendered and completely removes from the payload), `EMBED` (the association is recursively extracted
using the bound hydrator in the associated resource metadata) and `ID` (only the identifier(s) is/are rendered). The
default value is `ID`.
using the bound hydrator in the associated resource metadata), `ID` (only the identifier(s) is/are rendered) and
`PASS_THRU` (it reuses what is rendered by the hydrator of the parent object). The default value is `ID`.

### Navigation

Expand Down
2 changes: 1 addition & 1 deletion src/ZfrRest/Resource/Metadata/Annotation/Association.php
Expand Up @@ -39,7 +39,7 @@ final class Association implements AnnotationInterface
/**
* @var string
*
* @Enum({"NONE", "EMBED", "ID"})
* @Enum({"NONE", "EMBED", "ID", "PASS_THRU"})
*/
public $extraction = ResourceMetadataInterface::ASSOCIATION_EXTRACTION_ID;

Expand Down
7 changes: 4 additions & 3 deletions src/ZfrRest/Resource/Metadata/ResourceMetadataInterface.php
Expand Up @@ -28,9 +28,10 @@ interface ResourceMetadataInterface
/**
* Extraction constants that define how extraction associations are rendered
*/
const ASSOCIATION_EXTRACTION_NONE = 'NONE';
const ASSOCIATION_EXTRACTION_EMBED = 'EMBED';
const ASSOCIATION_EXTRACTION_ID = 'ID';
const ASSOCIATION_EXTRACTION_NONE = 'NONE';
const ASSOCIATION_EXTRACTION_EMBED = 'EMBED';
const ASSOCIATION_EXTRACTION_ID = 'ID';
const ASSOCIATION_EXTRACTION_PASS_THRU = 'PASS_THRU';

/**
* Create a new resource from the metadata
Expand Down
5 changes: 5 additions & 0 deletions src/ZfrRest/View/Renderer/DefaultResourceRenderer.php
Expand Up @@ -208,6 +208,11 @@ protected function renderAssociations(array $data, ResourceMetadataInterface $re
continue;
}

// If set to PASS_THRU, we let the parent hydrator do its own transform
if ($extractionStrategy === ResourceMetadataInterface::ASSOCIATION_EXTRACTION_PASS_THRU) {
continue;
}

// Otherwise, we render the association
$isCollectionValued = $classMetadata->isCollectionValuedAssociation($association);
$data[$association] = $this->renderAssociation(
Expand Down
43 changes: 43 additions & 0 deletions tests/ZfrRestTest/Asset/Hydrator/UserWithRoleHydrator.php
@@ -0,0 +1,43 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrRestTest\Asset\Hydrator;

use Zend\Stdlib\Exception;
use Zend\Stdlib\Hydrator\ClassMethods;

/**
* @author Michaël Gallego <mic.gallego@gmail.com>
* @licence MIT
*/
class UserWithRoleHydrator extends ClassMethods
{
public function extract($object)
{
$payload = parent::extract($object);
$roles = $object->getRoles();

$payload['roles'] = []; // Clear automatic extraction from ClassMethods

foreach ($roles as $role) {
$payload['roles'][] = $role->getName();
}

return $payload;
}
}
71 changes: 71 additions & 0 deletions tests/ZfrRestTest/Asset/Resource/Metadata/Annotation/Role.php
@@ -0,0 +1,71 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrRestTest\Asset\Resource\Metadata\Annotation;

use Doctrine\ORM\Mapping as ORM;
use ZfrRest\Resource\Metadata\Annotation as REST;

/**
* @ORM\Entity
*/
class Role
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
*/
protected $id;

/**
* @ORM\Column(type="string")
*/
protected $name;

/**
* @param (int) $id
*/
public function setId($id)
{
$this->id = (int) $id;
}

/**
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* @param string $name
*/
public function setName($name)
{
$this->name = (string) $name;
}

/**
* @return string
*/
public function getName()
{
return $this->name;
}
}
106 changes: 106 additions & 0 deletions tests/ZfrRestTest/Asset/Resource/Metadata/Annotation/UserWithRoles.php
@@ -0,0 +1,106 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrRestTest\Asset\Resource\Metadata\Annotation;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use ZfrRest\Resource\Metadata\Annotation as REST;

/**
* @ORM\Entity
* @REST\Resource(hydrator="ZfrRestTest\Asset\Hydrator\UserWithRoleHydrator")
*/
class UserWithRoles
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
*/
protected $id;

/**
* @ORM\Column(type="string")
*/
protected $username;

/**
* @ORM\ManyToMany(targetEntity="Role")
* @REST\Association(extraction="PASS_THRU")
*/
protected $roles;

public function __construct()
{
$this->roles = new ArrayCollection();
}

/**
* @param (int) $id
*/
public function setId($id)
{
$this->id = (int) $id;
}

/**
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* @param string $username
*/
public function setUsername($username)
{
$this->username = (string) $username;
}

/**
* @return string
*/
public function getUsername()
{
return $this->username;
}

/**
* @param Collection $roles
* @return void
*/
public function setRoles(Collection $roles)
{
$this->roles->clear();

foreach ($roles as $role) {
$this->roles->add($role);
}
}

/**
* @return ArrayCollection
*/
public function getRoles()
{
return $this->roles;
}
}
33 changes: 33 additions & 0 deletions tests/ZfrRestTest/View/Renderer/DefaultResourceRendererTest.php
Expand Up @@ -18,6 +18,7 @@

namespace ZfrRestTest\View\Renderer;

use Doctrine\Common\Collections\ArrayCollection;
use Zend\Paginator\Adapter\ArrayAdapter;
use Zend\Paginator\Paginator;
use Zend\Stdlib\Hydrator\HydratorPluginManager;
Expand All @@ -26,8 +27,10 @@
use ZfrRest\View\Model\ResourceModel;
use ZfrRest\View\Renderer\DefaultResourceRenderer;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\Address;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\Role;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\Tweet;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\User;
use ZfrRestTest\Asset\Resource\Metadata\Annotation\UserWithRoles;
use ZfrRestTest\Util\ServiceManagerFactory;

/**
Expand Down Expand Up @@ -422,4 +425,34 @@ public function testCanRenderCollectionResourceAsPaginator()

$this->assertEquals($expectedPayload, $payload);
}

public function testCanRenderResourceWithPassThruExtraction()
{
$role = new Role();
$role->setId(1);
$role->setName('member');

$user = new UserWithRoles();
$user->setId(2);
$user->setUsername('bakura');
$user->setRoles(new ArrayCollection([$role]));

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

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

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

$expectedPayload = [
'id' => 2,
'username' => 'bakura',
'roles' => ['member']
];

$this->assertEquals($expectedPayload, $payload);
}
}

0 comments on commit 55943a6

Please sign in to comment.