Installation
composer require arte/hateoas-bundle
Add the bundle to your config/bundles.php (Symfony):
Arte\HateoasBundle\ArteHateoasBundle::class => ['all' => true],
Generate a Hateoas Adder Class
Use the provided command to scaffold a Hateoas adder for your entity (e.g., Product):
php bin/console arte:hateoas:generate Product
This creates a class like ProductHateoasAdder in src/Entity/Product/Hateoas/.
First Use Case Inject the adder into your controller or service and apply it to a resource:
use Arte\HateoasBundle\Hateoas\HateoasAdderInterface;
class ProductController
{
public function show(Product $product, ProductHateoasAdder $adder)
{
$resource = new Resource($product);
$adder->add($resource);
return $this->jsonSerializer->serialize($resource, 'jsonld');
}
}
Entity-Centric Hateoas
Generate a dedicated adder per entity (e.g., UserHateoasAdder, OrderHateoasAdder). Place them in a Hateoas sub-namespace under your entity.
Reusable Adders
Extend base adders for shared logic (e.g., BaseCollectionHateoasAdder) and reuse them across multiple entities.
Dynamic Link Generation Use dependency injection to fetch routes dynamically:
public function add(Resource $resource)
{
$resource->getItem()->getId(); // Access entity ID
$resource->getUri() = $this->router->generate('product_show', ['id' => $id]);
}
Integration with Serializers
Chain the adder with your serializer (e.g., JsonLdSerializer):
$serializer = $this->serializer->serialize($resource, 'jsonld', [
'groups' => ['product:read'],
]);
arte/hateoas-bundle is registered as a serializer normalizer.ApiResource classes via serialize() or denormalize().$adder = $this->createMock(ProductHateoasAdder::class);
$adder->expects($this->once())->method('add');
Circular References
Avoid infinite loops when adding links to nested resources. Use Resource::getItem() carefully to check entity types.
Route Existence
Ensure routes referenced in adders exist. Use RouteExistsListener or validate routes in tests:
$this->assertTrue($this->router->getRouteCollection()->get('product_show'));
Overriding Defaults
If extending BazingaHateoasBundle, ensure method signatures match (e.g., add() vs. addLinks()).
$this->router->getRouteCollection()->get('undefined_route'); // Throws exception
groups in your serializer context match the entity’s metadata.Custom Link Providers
Implement LinkProviderInterface for dynamic links (e.g., OAuth tokens):
class AuthLinkProvider implements LinkProviderInterface
{
public function getLinks(Resource $resource): array
{
return ['auth' => ['href' => '/oauth/token']];
}
}
Event Listeners
Trigger events before/after adding links (e.g., hateoas.add.links):
$eventDispatcher->addListener('hateoas.add.links', function (HateoasEvent $event) {
$event->getResource()->add(['custom' => ['href' => '/custom']]);
});
Configuration
Override default templates in config/packages/arte_hateoas.yaml:
arte_hateoas:
templates:
link: '@ArteHateoas/link.html.twig'
How can I help you explore Laravel packages today?