api-skeletons/laravel-hal-doctrine

Doctrine Metadata based HAL

0.8.2 2022-02-03 01:00 UTC

This package is auto-updated.

Last update: 2024-03-29 04:33:31 UTC


README

Build Status Code Coverage PHP Version Laravel Version Total Downloads License

This library provides a hydrator for laravel-hal for Doctrine. Instead of manually creating every hydrator for your entities, this library will introspect an entity and generate the HAL for it including links to other entities and collections for one to many relationships and embedding many to one and one to one entities.

A grouped minimal configuration file allows for excluded fields and associations and configures the routes for each entity.

Use

Create a hydrator manager

namespace App\HAL;

use ApiSkeletons\Laravel\HAL\HydratorManager as HALHydratorManager;

final class HydratorManager extends HALHydratorManager
{
    public function __construct() 
    {
        $this->classHydrators = [
            // This wildcard entry is used as an example and may not be exactly what you need
            '*' => \ApiSkeletons\Laravel\HAL\Doctrine\DoctrineHydrator::class,
        ];
    }
}

Extract an entity

use App\Hal\HydratorManager;

public function fetch(Entity\Artist $artist): array
{
    return (new HydratorManager())->extract($artist)->toArray();
}

will result in a HAL response like

{
  "_links": {
    "self": {
      "href": "https://website/artist/1"
    },
    "albums": {
      "href": "https://website/album?filter[artist]=1"
    }
  },
  "id": 1,
  "name": "Grateful Dead"
}

Configuration

A hal-doctrine.php configuration file is required. Publish the included config to your project:

php artisan vendor:publish --tag=config
$config = [
    'default' => [
        'entityManager' => EntityManager::class,
        'routeNamePatterns' => [
            'entity' => 'api.{entityName}::fetch',
            'collection' => 'api.{entityName}::fetchAll',
        ],
        // All entities configuration is optional
        'entities' => [
            \App\ORM\Entity\Artist::class => [
                // Override route patterns
                'routesNames' => [
                    'entity' => 'artist::fetch',
                    'collection' => 'artist::fetchAll',
                ],
                // List of fields and associations to exclude
                'exclude' => [
                    'alias',
                ],
            ],
        ],
    ],
];

Doctrine\Laminas\Hydrator\DoctrineObject

The Laminas Hydrator is used by this library to extract data directly from entities. You must add this configuration to your doctrine.php configuration file:

'custom_hydration_modes' = [
    'hal-doctrine' => \Doctrine\Laminas\Hydrator\DoctrineObject::class,
],

Naming Strategy

The default naming strategy uses the Inflector's urlize() method to change 'associationName' into 'association-name'. If this is not the way you want to name your relationsihps or routes then create your own naming strategy and assign it in the config file.

Route naming

When using the routeNamePatterns to create a route name, the entity name becomes $namingStrategy->route($entityName) such as api.short-name::fetch according to the example configuration.

Filtering Collections

For extracted related collections, links will be created with filter options compatible with ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator to filter the collection data to just the extracted entity. For example

  "_links": {
    ...
    "album": {
      "href": "https://website/album?filter[artist]=1"
    }

The link to the Album will be filtered where album.artist = 1. In order to process these URLs in your application, implement ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator in your controller action:

use ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator;

public function fetchAll(EntityManager $entityManager): array
{
    $applicator = new Applicator($entityManager, Entity\Album::class);
    $queryBuilder = $applicator($_REQUEST['filter']);
    
    return (new HydratorManager())
        ->paginate('albums', collect($queryBuilder->getQuery()->getResult()))->toArray();
}

See the documentation for doctrine-querybuilder-filter for more detailed examples.

Multiple Object Managers

To configure a hydrator for other than the default configuration section, extend the Doctrine Hydrator

class SecondDoctrineHydrator extends ApiSkeletons\Laravel\HAL\Doctrine\DoctrineHydrator
{
    protected string $configurationSection = 'secondary';
}

Then in your hal-doctrine.php configuration file, create a new section titled secondary and set the entityManager to your second Entity Manager.