Nested Classes

Automatic Connection

Hydration allows an application to connect Hydratable classes together. If an object contains a property that contains another hydratable object, that property will also be hydrated.

Example:

class A implements Hydratable
{
    public B $b;
    public bool $foo;
    private static Hydrator $hydrator;

    public function hydrate($json, $options = []): bool {
        if (!isset(self::$hydrator)) {
            self::$hydrator = Hydrator::make(self::class);
        }
        return self::$hydrator->hydrate($this, $json, $options);
    }

}

class B implements Hydratable
{
    private static Hydrator $hydrator;
    public string $bar;

    public function hydrate($json, $options = []): bool
    {
        if (!isset(self::$hydrator)) {
            self::$hydrator = Hydrator::make(self::class);
        }
        return self::$hydrator->hydrate($this, $json, $options);
    }

}

$a = new A();
$a->hydrate('{"b": {"bar": "this is bar"}, "foo": true}');

This will result in $a->b being initialized with an object of class B with $a->b->bar set to 'this is bar' and $a->foo set true.

Note: If Hydrator::hydrate() is invoked with no options, it is assumed that the first parameter is a JSON-format string. This string is decoded at the top entry point and the decoded data is passed to nested calls with the source option set to "object". See options for more information.

Manual Connection

If the property that contains another hydrated object is not typed, the application can explicitly make the connection:

class A implements Hydratable
{
    public object $b;
    public bool $foo;
    private static Hydrator $hydrator;

    public function hydrate($json, $options = []): bool
    {
        if (!isset(self::$hydrator)) {
            self::$hydrator = Hydrator::make(self::class)
                ->addProperty(
                    Property::make('b')
                        ->bind(SomeClass::class, 'factory')
                );
        }
        return self::$hydrator->hydrate($this, $json, $options);
    }

}

The data for the property $b will be passed to SomeClass::factory() with the source data as the first argument and the options array as the second. If the class method is not explicitly provided, then the hydrate() method will be called.

Hydrating external classes

Hydration can also be used to create classes outside the application itself. The factory() method can be used to construct and hydrate these classes. factory() takes a Closure argument, The closure will be called with the hydration value and the Property.

class A implements Hydratable
{
    public DateTime $date;
    private static Hydrator $hydrator;

    public function hydrate($json, $options = []): bool
    {
        if (!isset(self::$hydrator)) {
            self::$hydrator = Hydrator::make(self::class)
                ->addProperty(
                    Property::make('date')
                        ->factory(function ($value, Property $property) {
                            return new DateTime($value[0], new DateTimeZone($value[1]));
                        })
                );
        }
        return self::$hydrator->hydrate($this, $json, $options);
    }

}

$obj = new A();
$obj->hydrate('{"date": ["2000-01-01", "America/Toronto"]}');

This will cause $obj->date to be initialized as a DateTime object.