mixerapi / hal-view
A Hypertext Application Language (HAL+JSON) view for CakePHP.
Installs: 35 540
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Type:cakephp-plugin
Requires
- php: ^8.1
- cakephp/cakephp: ^5.0
- mixerapi/core: ^2.0
Requires (Dev)
- josegonzalez/dotenv: ^3.2
- phpunit/phpunit: ^10.0
README
A Hypertext Application Language (HAL+JSON) View for CakePHP. This plugin
supports links, pagination, and embedded resources. Once setup any request with application/hal+json
will be
rendered by this plugin.
Table of Contents
Installation
!!! note "" You can skip this step if MixerAPI is installed.
composer require mixerapi/hal-view bin/cake plugin load MixerApi/HalView
Alternatively after composer installing you can manually load the plugin in your Application:
# src/Application.php public function bootstrap(): void { // other logic... $this->addPlugin('MixerApi/HalView'); }
Setup
Your controllers must be using the RequestHandler
component. This is typically loaded in your AppController
.
# src/Controller/AppController.php public function initialize(): void { parent::initialize(); $this->loadComponent('RequestHandler'); // other logic... }
Usage
For _link.self.href
support you will need to implement MixerApi\HalView\HalResourceInterface
on entities that you
want to expose as HAL resources. This informs the plugin that the Entity should be treated as a HAL resource and
provides the mapper with a _link.self.href
URL:
<?php declare(strict_types=1); namespace App\Model\Entity; use Cake\ORM\Entity; use MixerApi\HalView\HalResourceInterface; use Cake\Datasource\EntityInterface; class Actor extends Entity implements HalResourceInterface { // your various properties and logic /** * @param EntityInterface $entity * @return array|\string[][] */ public function getHalLinks(EntityInterface $entity): array { return [ 'self' => [ 'href' => '/actors/' . $entity->get('id') ] ]; } }
Now an HTTP GET to the /actors/149
endpoint will render HAL using the CakePHP native serialization process:
#src/Controller/ActorsController.php public function view($id = null) { $this->request->allowMethod('get'); $actor = $this->Actors->get($id, [ 'contain' => ['Films'], ]); $this->set('actor', $actor); $this->viewBuilder()->setOption('serialize', 'actor'); }
Example
{ "_links": { "self": { "href": "/actors/149" } }, "id": 149, "first_name": "RUSSELL", "last_name": "TEMPLE", "modified": "2006-02-15T04:34:33+00:00", "_embedded": { "films": [ { "id": 53, "title": "BANG KWAI", "description": "A Epic Drama of a Madman And a Cat who must Face a A Shark in An Abandoned Amusement Park", "release_year": "2006", "language_id": 1, "rental_duration": 5, "rental_rate": "2.99", "length": 87, "replacement_cost": "25.99", "rating": "NC-17", "special_features": "Commentaries,Deleted Scenes,Behind the Scenes", "modified": "2006-02-15T05:03:42+00:00" "_links": { "self": { "href": "/films/53" } } } ] } }
If your Entity does not implement the interface it will still be returned as HAL resource when serialized, but minus
the _links
property. Collection requests will work without this interface as well, example:
#src/Controller/ActorsController.php public function index() { $this->request->allowMethod('get'); $actors = $this->paginate($this->Actors, [ 'contain' => ['Films'], ]); $this->set(compact('actors')); $this->viewBuilder()->setOption('serialize', 'actors'); }
Example
{ "_links": { "self": { "href": "/actors?page=3" }, "next": { "href": "/actors?page=4" }, "prev": { "href": "/actors?page=2" }, "first": { "href": "/actors?page=1" }, "last": { "href": "/actors?page=11" } }, "count": 20, "total": 207, "_embedded": { "actors": [ { "id": 1, "first_name": "PENELOPE", "last_name": "GUINESS", "modified": "2006-02-15T04:34:33+00:00" "_embedded": { "films": [ { "id": 1, "title": "ACADEMY DINOSAUR", "description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies", "release_year": "2006", "language_id": 1, "rental_duration": 6, "rental_rate": "0.99", "length": 86, "replacement_cost": "20.99", "rating": "PG", "special_features": "Deleted Scenes,Behind the Scenes", "modified": "2006-02-15T05:03:42+00:00" } ] } } ] } }
If the Actor and Film entities were implementing MixerApi\HalView\HalResourceInterface
then the example above would
include the _links
property for each serialized entity.
Try it out for yourself:
# json curl -X GET "http://localhost:8765/actors" -H "accept: application/hal+json"
Serializing
Optionally, you can manually serialize data into HAL using JsonSerializer
. This is the same class that the main HalJsonView uses. Example:
use MixerApi\HalView\JsonSerializer; # json $json = (new JsonSerializer($data))->asJson(JSON_PRETTY_PRINT); // asJson argument is optional # array $hal = (new JsonSerializer($data))->getData(); # json with `_links.self.href` and pagination meta data use Cake\Http\ServerRequest; use Cake\View\Helper\PaginatorHelper; $json = (new JsonSerializer($data, new ServerRequest(), new PaginatorHelper()))->asJson();