Skip to content

Commit

Permalink
Add a RelationUrlGenerator, with a nice Controller trait :)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrienbrault committed Dec 10, 2012
1 parent 9f0ca96 commit 2ca67f8
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Controller/HateoasTrait.php
@@ -0,0 +1,16 @@
<?php

namespace FSC\HateoasBundle\Controller;

trait HateoasTrait
{
protected function generateRelationUrl($object, $rel)
{
return $this->container->get('fsc_hateoas.routing.relation_url_generator')->generateUrl($object, $rel);
}

protected function generateSelfUrl($object)
{
return $this->generateRelationUrl($object, 'self');
}
}
18 changes: 18 additions & 0 deletions Metadata/ClassMetadata.php
Expand Up @@ -11,16 +11,34 @@ class ClassMetadata extends MergeableClassMetadata implements ClassMetadataInter
*/
protected $relations = array();

/**
* {@inheritdoc}
*/
public function getRelations()
{
return $this->relations;
}

/**
* {@inheritdoc}
*/
public function addRelation(RelationMetadataInterface $relation)
{
$this->relations[] = $relation;
}

/**
* {@inheritdoc}
*/
public function getRelation($rel)
{
foreach ($this->relations as $relationMetadata) {
if ($relationMetadata->getRel() === $rel) {
return $relationMetadata;
}
}
}

public function serialize()
{
return serialize(array(
Expand Down
7 changes: 7 additions & 0 deletions Metadata/ClassMetadataInterface.php
Expand Up @@ -8,4 +8,11 @@ interface ClassMetadataInterface
* @return array<RelationMetadataInterface>
*/
public function getRelations();

/**
* @param string $rel
*
* @return RelationMetadataInterface
*/
public function getRelation($rel);
}
10 changes: 10 additions & 0 deletions Metadata/MetadataFactoryInterface.php
Expand Up @@ -6,6 +6,16 @@

interface MetadataFactoryInterface
{
/**
* @param object $object
*
* @return ClassMetadataInterface
*/
public function getMetadata($object);

/**
* @param object $object
* @param array $relations
*/
public function addObjectRelations($object, array $relations);
}
33 changes: 33 additions & 0 deletions README.md
Expand Up @@ -543,3 +543,36 @@ class UserController extends Controller
</select>
</form>
```

## RelationUrlGenerator

You can leverage the fact that the hateoas bundle knows how to create url to an object's relation. This is usefull if you
want generate the self url to an object:

```php
$user = ...
$userUrl = $container->get('fsc_hateoas.routing.relation_url_generator')->generateUrl($user, 'self')
```

You can even use the controller trait:

```php
<?php

use FSC\HateoasBundle\Controller\HateoasTrait;

class UserController extends Controller

This comment has been minimized.

Copy link
@lsmith77

lsmith77 Dec 10, 2012

Contributor

looks like you forgot to add the trait ..

{
public function createUserAction(Request $request)
{
$user = new User();

... // you own stuff

return Response('', 201, array(
'Location' => $this->generateSelfUrl($user),
));
}
}

```
8 changes: 8 additions & 0 deletions Resources/config/services.yml
Expand Up @@ -12,6 +12,7 @@ parameters:
fsc_hateoas.serializer.handler.form.class: FSC\HateoasBundle\Serializer\Handler\FormHandler
fsc_hateoas.factory.identity.class: FSC\HateoasBundle\Factory\IdentityFactory
fsc_hateoas.routing.generator.class: FSC\HateoasBundle\Routing\UrlGenerator
fsc_hateoas.routing.relation_url_generator.class: FSC\HateoasBundle\Routing\RelationUrlGenerator

fsc_hateoas.json.links_key: ~
fsc_hateoas.json.relations_key: ~
Expand Down Expand Up @@ -105,3 +106,10 @@ services:
class: %fsc_hateoas.routing.generator.class%
arguments:
- @router

fsc_hateoas.routing.relation_url_generator:
class: %fsc_hateoas.routing.relation_url_generator.class%
arguments:
- @fsc_hateoas.routing.generator
- @fsc_hateoas.metadata.factory
- @fsc_hateoas.factory.parameters
36 changes: 36 additions & 0 deletions Routing/RelationUrlGenerator.php
@@ -0,0 +1,36 @@
<?php

namespace FSC\HateoasBundle\Routing;

use FSC\HateoasBundle\Metadata\MetadataFactoryInterface;
use FSC\HateoasBundle\Factory\ParametersFactoryInterface;

class RelationUrlGenerator
{
protected $urlGenerator;
protected $metadataFactory;
protected $parametersFactory;

public function __construct(UrlGenerator $urlGenerator, MetadataFactoryInterface $metadataFactory,
ParametersFactoryInterface $parametersFactory)
{
$this->urlGenerator = $urlGenerator;
$this->metadataFactory = $metadataFactory;
$this->parametersFactory = $parametersFactory;
}

public function generateUrl($object, $rel)
{
$metadata = $this->metadataFactory->getMetadata($object);
$relationMetadata = $metadata->getRelation($rel);

if (null === $relationMetadata) {
throw new \RuntimeException(sprintf('Relation "%s" doesn\'t exist.', $rel));
}

return $this->urlGenerator->generate(
$relationMetadata->getRoute(),
$this->parametersFactory->createParameters($object, $relationMetadata->getParams())
);
}
}
10 changes: 10 additions & 0 deletions Tests/Functional/ControllerTest.php
Expand Up @@ -28,6 +28,16 @@ public function testGetPostXml()
, $response->getContent());
}

public function testPutPostXml()
{
$client = $this->createClient();
$client->request('PUT', '/api/posts/2');

$response = $client->getResponse(); /** */

$this->assertEquals('http://localhost/api/posts/2', $response->headers->get('Location'));
}

public function testGetUserPostsXml()
{
$client = $this->createClient();
Expand Down
9 changes: 9 additions & 0 deletions Tests/Functional/TestBundle/Controller/PostController.php
Expand Up @@ -46,4 +46,13 @@ public function getCreateFormatPostFormAction(Request $request)

return $this->getCreatePostFormAction($request);
}

public function putPostAction($id)
{
$post = $this->get('test.provider.post')->getPost($id);

return new Response('', 201, array(
'Location' => $this->get('fsc_hateoas.routing.relation_url_generator')->generateUrl($post, 'self'),
));
}
}
7 changes: 7 additions & 0 deletions Tests/Functional/config/routing.yml
Expand Up @@ -40,6 +40,13 @@ api_post_get:
pattern: /api/posts/{id}
defaults:
_controller: TestBundle:Post:getPost
requirements: { _method: GET }

api_post_put:
pattern: /api/posts/{id}
defaults:
_controller: TestBundle:Post:putPost
requirements: { _method: PUT }

api_user_posts_list:
pattern: /api/users/{id}/posts
Expand Down

0 comments on commit 2ca67f8

Please sign in to comment.