On this page

Links and Resources

The basic building blocks of this component are links and resources:

  • Mezzio\Hal\Link
  • Mezzio\Hal\HalResource

Note on naming

Why HalResource and not the simpler Resource? The answer: PHP. As of PHP 7, resource has been designated a potential future language keyword. In order to be forwards compatible, we opted to name our class HalResource.

PSR-13

mezzio/mezzio-hal implements PSR-13, which provides interfaces for relational links and collections of relational links. Mezzio\Hal\Link implements Psr\Link\EvolvableLinkInterface, and Mezzio\Hal\HalResource implements Psr\Link\EvolvableLinkProviderInterface.

Resources compose links, so we'll cover links first.

Links provide URIs to related resources.

Any given link, therefore, needs to compose the relation and a URI. Additionally, links:

  • can be templated. Templated links have one or more {variable} placeholders in them that clients can then fill in in order to generate a fully qualified URI.
  • can contain a number of other attributes: type, title, name, etc.

To model these, we provide the Mezzio\Hal\Link class. It has the following constructor:

public function __construct(
    $relation,
    string $uri = '',
    bool $isTemplated = false,
    array $attributes = []
)

$relation can be a string value, or an array of string values, representing the relation.

To access these various properties, you can use the following methods:

$link->getRels()       // get the list of relations for the link
$link->getHref()       // retrieve the URI
$link->isTemplated()   // is the link templated?
$link->getAttributes() // get any additional link attributes

A Link is immutable; you cannot change it after the fact. If you need a modified version of the link, we provide several methods that will return new instances containing the changes:

$link = $link->withRel($rel);    // or provide an array of relations
$link = $link->withoutRel($rel); // or provide an array of relations
$link = $link->withHref($href);
$link = $link->withAttribute($attribute, $value);
$link = $link->withoutAttribute($attribute);

With these tools, you can describe any relational link.

Most frameworks provide routing capabilities, and delegate URI generation to their routers to ensure that generated links conform to known routing specifications. Link expects only a string URI, however; how can you prevent hard-coding that URI?

This component provides a tool for that: Mezzio\Hal\LinkGenerator. This class composes a Mezzio\Hal\LinkGenerator\UrlGeneratorInterface instance, which defines the following:

namespace Mezzio\Hal\LinkGenerator;

use Psr\Http\Message\ServerRequestInterface;

interface UrlGeneratorInterface
{
    /**
     * Generate a URL for use as the HREF of a link.
     *
     * - The request is provided, to allow the implementation to pull any
     *   request-specific items it may need (e.g., results of routing, original
     *   URI for purposes of generating a fully-qualified URI, etc.).
     *
     * - `$routeParams` are any replacements to make in the route string.
     *
     * - `$queryParams` are any query string parameters to include in the
     *   generated URL.
     */
    public function generate(
        ServerRequestInterface $request,
        string $routeName,
        array $routeParams = [],
        array $queryParams = []
    ) : string;
}

We provide a default implementation for Mezzio users, Mezzio\Hal\LinkGenerator\MezzioUrlGenerator, that uses the UrlHelper and ServerUrlHelper from mezzio-helpers in order to generate URIs.

The LinkGenerator itself defines two methods:

$link = $linkGenerator->fromRoute(
    $relation,
    $request,
    $routeName,
    $routeParams, // Array of additional route parameters to inject
    $queryParams, // Array of query string arguments to inject
    $attributes   // Array of Link attributes to use
);

$link = $linkGenerator->templatedFromRoute(
    $relation,
    $request,
    $routeName,
    $routeParams, // Array of additional route parameters to inject
    $queryParams, // Array of query string arguments to inject
    $attributes   // Array of Link attributes to use
);

fromRoute() will generate a non-templated Link instance, while templatedFromRoute() generates a templated instance.

If you need to generate custom links based on routing, we recommend composing the LinkGenerator in your own classes to do so.

Limitation

There is a known limitation with laminas-router when using routes with optional parameters (e.g., /books[/:id], where :id is optional). In such cases, if no matching parameter is provided (such as when generating a URI without an :id), the router will raise an exception due to the missing parameter.

If you encounter this issue, create separate routing entries for each optional parameter. See the issue for a comprehensive example.

Resources

A HAL resource is simply the representation you want to return for your API. Mezzio\Hal\HalResource allows you to model these representations, along with any relational links and child resources.

It defines the following constructor:

public function __construct(
    array $data = [],
    array $links = [],
    array $embedded = []
)

$data should be an associative array of data you wish to include in your representation; the only limitation is you may not use the keys _links or _embedded, as these are reserved keywords.

$links should be an array of Mezzio\Hal\Link instances.

$embedded should be an array of Mezzio\Hal\HalResource instances. Most often, however, you will include these with $data, as the class contains logic for identifying them.

Once you have created an instance, you can access its properties:

$resource->getElement($name) // retrieve an element or embedded resource by name
$resource->getElements()     // retrieve all elements and embedded resources
$resource->getLinks()        // retrieve all relational links
$resource->getLinksByRel()   // retrieve links for a specific relation
$resource->toArray()         // retrieve associative array representation

HalResource instances are immutable. We provide a number of methods that allow you to create new instances with changes:

$resource = $resource->withElement($name, $value);
$resource = $resource->withoutElement($name);
$resource = $resource->withElements($elements);
$resource = $resource->embed($name, $resource);
$resource = $resource->withLink($link);
$resource = $resource->withoutLink($link);

With these tools, you can describe any resource you want to represent.