uxf/hydrator

Maintainers

Details

gitlab.com/uxf/hydrator

Source

Issues

Installs: 23 106

Dependents: 1

Suggesters: 0

Security: 0

Stars: 1

Forks: 0

3.41.0 2024-04-28 09:16 UTC

README

The fastest PHP object hydrator....

Install

$ composer req uxf/hydrator

Config

// config/packages/uxf.php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use UXF\Core\Http\Request\NotSet;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('uxf_hydrator', [       
        'ignored_types' => [NotSet::class], // optional
        'overwrite' => true,                // optional (default %kernel.debug%)
        'default_options' => [
            'allow_lax_string'  => true,     // default false
            'allow_trim_string' => true,     // default false
            'allow_fallback'    => true,     // default false
        ],
    ]);
};

Basic usage

ObjectHydrator create object from

class Person
{
    public function __construct(
        public readonly string $name,
        public readonly int $age,
        public readonly Sex $sex, // enum
        public readonly DateTimeImmutable $createdAt,
        public readonly ?string $note = null, // optional
    ) {
    }
}

$hydrator = $container->get(UXF\Hydrator\ObjectHydrator::class);

$data = [
    'name' => 'Joe Doe',
    'age' => 55,
    'sex' => 'MALE',
    'createdAt' => '2000-01-02T13:03:01+00:00',
];

// single object
/** @var Person $person */
$person = $this->hydrator->hydrateArray($data, Person::class);

var_dump($person);
/*
Person {
    name: "Joe Doe" (string)
    age: 55 (int)
    sex: Sex::MALE, (enum)
    createdAt: "2000-01-02T13:03:01+00:00" (DateTimeImmutable)
}
*/

// array of objects
/** @var Person[] $people */
$people = $this->hydrator->hydrateArrays([$data], Person::class);

Exceptions

try {
    $badPerson = $this->hydrator->hydrateArray($badData, Person::class);        
} catch (HydratorException $e) {
    /** @var array<string, array<string>> $errors */
    $errors = $e->errors;
}

Options

  • You can set default_options in bundle configuration or as ObjectHydrator constructor parameter.
  • Or pass Options parameter with unique name to hydrateArray/hydrateArrays method.
  • Use unique option name!!! Same option name with different values can lead to unexpected results...

allow_lax_string: true

Convert all scalars or stringable objects to string.

class Test
{
    public function __construct(public readonly string $helloWorld) {}
}

$a = ['helloWorld' => new Uuid()];   // Uuid is Stringable
$b = ['helloWorld' => 1];            // 1 => '1'

allow_trim_string: true

Trim all strings.

class Test
{
    public function __construct(public readonly string $helloWorld) {}
}

$a = ['helloWorld' => ' A ']; // helloWorld => 'A'

allow_fallback: true

Use FallbackParameterGenerator as fallback hydrator variant.

class Test
{
    public function __construct(public readonly mixed $helloWorld) {}
}

$a = ['helloWorld' => ['every value is possible', 1, new DateTime(), ['hello' => 'kitty']];

HydratorProperty

use UXF\Hydrator\Attribute\HydratorProperty;

class Cart
{
    public function __construct(
        #[HydratorProperty('@id')]
        public readonly int $id,
    ) {
    }
}
{
    "@id": 1
}

HydratorMap

Interface

use UXF\Hydrator\Attribute\HydratorMap;

// interface
#[HydratorMap(property: 'type', matrix: [
    'o' => Orienteering::class,
    'p' => Paragliding::class,
])]
interface Activity
{
}

// children
class Orienteering implements Activity
{
    public function __construct(
        public readonly int $card,
    ) {
    }
}

class Paragliding implements Activity
{
    public function __construct(
        public readonly string $glider,
    ) {
    }
}

// usage
class Club
{
    /**
     * @param Activity[] $activities
     */
    public function __construct(
        public readonly array $activities,
        public readonly Activity $activity,
    ) {
    }
}

Abstract class

use UXF\Hydrator\Attribute\HydratorMap;

// abstract class
#[HydratorMap(property: 'type', matrix: [
    'c' => CrossCountrySkiing::class,
    'o' => Orienteering::class,
    'p' => Paragliding::class,
])]
abstract class Sport
{
}

// children
class CrossCountrySkiing extends Sport
{
    public function __construct(
        public readonly string $ski,
    ) {
    }
}

class Orienteering extends Sport
{
    public function __construct(
        public readonly int $card,
    ) {
    }
}

class Paragliding extends Sport
{
    public function __construct(
        public readonly string $glider,
    ) {
    }
}

// usage
class Club
{
    /**
     * @param Sport[] $sports
     */
    public function __construct(
        public readonly array $sports,
        public readonly Sport $sport,
    ) {
    }
}