Permalink
256 lines (196 sloc) 5.64 KB

BazingaHateoasBundle

This bundle integrates Hateoas into Symfony2.

Installation

Step 1: Download the Bundle

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.

Step 2: Enable the Bundle

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(),
    );

    // ...
}

Usage

Mapping Objects

Refer to the Hateoas documentation to find out how to map your objects.

Serializing 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('serializer')->serialize($post, 'json');

        return new Response($json, 200, array('application/json'));
    }
}

Expression Language

This bundle provides three extra functions to the expression language:

is_granted

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.

parameter

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
{
    // ...
}

service

Allows you to fetch a service from the service container.

Extending

RelationProviderResolver

A relation provider resolver is a class which provides a PHP callable. This callable will provide relations (links) for a given object.

You can add new relation providers by implementing the Hateoas\Configuration\Provider\Resolver\RelationProviderResolverInterface 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_resolver.foobar" class="Acme\FooBundle\Hateoas\RelationProviderResolver\Foobar">
            <tag name="hateoas.relation_provider" />
        </service>
    </services>
</container>

Configuration Extension

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',
                    '/'
                )
            );
        }
    }
}

Reference Configuration

# app/config/config*.yml

bazinga_hateoas:
    metadata:
        cache:                file
        file_cache:
            dir:              %kernel.cache_dir%/hateoas

Testing

Setup the test suite using Composer:

$ composer install --dev

Run it using PHPUnit:

$ phpunit