This bundle integrates Hateoas into Symfony.
Open a command console, enter your project directory and execute the following command to download the latest stable version of this bundle:
$ composer require willdurand/hateoas-bundle
This command requires you to have Composer installed globally, as explained in the installation chapter of the Composer documentation.
Note: this step is not required if you are using Symfony Flex
Then, enable the bundle by adding the following line in the app/AppKernel.php
file of your project:
<?php
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
);
// ...
}
}
Note: The bundle requires the JMSSerializerBundle to be registered. If you haven't done that already, you should register it in the kernel aswell:
// app/AppKernel.php // ... public function registerBundles() { $bundles = array( // ... new JMS\SerializerBundle\JMSSerializerBundle(), ); // ... }
Refer to the Hateoas documentation to find out how to map your objects.
The BazingaHateoasBundle transparently hooks into the JMS serializer, there are no special considerations:
// My/Controller.php
class SomeController extends Controller
{
public function resourceAction(Request $request)
{
$post = $repository->find('BlogBundle:post');
$json = $this->container->get('jms_serializer')->serialize($post, 'json');
return new Response($json, 200, array('Content-Type' => 'application/json'));
}
}
An example using dependency injection:
// My/Controller.php
use JMS\Serializer\SerializerInterface;
class SomeController extends Controller
{
private $serializer;
public function __consttruct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
public function resourceAction(Request $request)
{
$post = $repository->find('BlogBundle:post');
$json = $this->serializer->serialize($post, 'json');
return new Response($json, 200, array('Content-Type' => 'application/json'));
}
}
This bundle provides three extra functions to the expression language:
Allows you to exclude certain routes by checking whether the currently authenticated user has certain permissions or not. For example:
use Hateoas\Configuration\Annotation as Hateoas;
/**
* @Hateoas\Relation(
* "delete",
* href = @Hateoas\Route(
* "post_delete",
* parameters = { "id" = "expr(object.getId())" }
* ),
* exclusion = @Hateoas\Exclusion(
* excludeIf = "expr(not is_granted('ROLE_ADMIN'))"
* )
* )
*/
class Post
{
// ...
}
If the authenticated user has the ROLE_ADMIN
role the route will be exposed, otherwise
the route will be excluded.
Allows you to fetch a parameter from the service container:
/**
* @Hateoas\Relation(
* "delete",
* href = @Hateoas\Route(
* "post_delete",
* parameters = { "foo" = "expr(parameter('foo'))" }
* )
* )
*/
class Post
{
// ...
}
Allows you to fetch a service from the service container.
A relation provider provide relations (links) for a given class.
You can add new relation providers by implementing the
Hateoas\Configuration\Provider\RelationProviderInterface
interface and adding a definition to the dependency injection configuration
with the tag hateoas.relation_provider
:
<?xml version="1.0" ?>
<container ...>
<!-- ... -->
<services>
<!-- ... -->
<service id="acme_foo.hateoas.relation_provider.foobar" class="Acme\FooBundle\Hateoas\RelationProvider\Foobar">
<tag name="hateoas.relation_provider" />
</service>
</services>
</container>
A configuration extension allows you to override already configured relations.
You can add an extension configuration by adding a definition to the dependency
injection configuration with the tag hateoas.configuration_extension
:
<?xml version="1.0" ?>
<container ...>
<!-- ... -->
<services>
<!-- ... -->
<service id="acme_foo.hateoas.configuration_extension.foobar" class="Acme\FooBundle\Hateoas\ConfigurationExtension\AcmeFooConfigurationExtension">
<tag name="hateoas.configuration_extension" />
</service>
</services>
</container>
<?php
namespace Acme\FooBundle\Hateoas\ConfigurationExtension;
use Hateoas\Configuration\Metadata\ConfigurationExtensionInterface;
use Hateoas\Configuration\Metadata\ClassMetadataInterface;
use Hateoas\Configuration\Relation;
class AcmeFooConfigurationExtension implements ConfigurationExtensionInterface
{
/**
* {@inheritDoc}
*/
public function decorate(ClassMetadataInterface $classMetadata)
{
if (0 === strpos('Acme\Foo\Model', $classMetadata->getName())) {
// Add a "root" relation to all classes in the `Acme\Foo\Model` namespace
$classMetadata->addRelation(
new Relation(
'root',
'/'
)
);
}
}
}
# app/config/config*.yml
bazinga_hateoas:
metadata:
cache: file
file_cache:
dir: '%kernel.cache_dir%/hateoas'
serializer:
json: hateoas.serializer.json_hal
xml: hateoas.serializer.xml
twig_extension:
enabled: true
Setup the test suite using Composer:
$ composer install --dev
Run it using PHPUnit:
$ phpunit