zf2 - Nested Aggregate Hydrators

177 Views Asked by At

Is it possible to nest aggregate hydrators? If i have the following classes:

class Appointment{
    public date;
    public startTime;
    public endTime;
    public User; //* @var User */
}

class User{
    public Location; //* @var Location*/ 
}

...being populated with the following AggregateHydrator (created from a factory):

class AppointmentModelHydratorFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator) {
        $serviceManager = $serviceLocator->getServiceLocator();
        $arrayHydrator = new ArraySerializable();
        $arrayHydrator->addStrategy('date', new DateTimeStrategy())
            ->addStrategy('endTime', new TimeStrategy())
            ->addStrategy('startTime', new TimeStrategy());

        $aggregateHydrator = new AggregateHydrator();
        $aggregateHydrator->add($arrayHydrator);
        $aggregateHydrator->add($serviceLocator->get('Hydrator\User'));
        return $aggregateHydrator;
    }
}

With the UserHydratorFactory looking like:

class UserHydratorFactory implements FactoryInterface
{
     public function createService(ServiceLocatorInterface $serviceLocator) {
        $sm = $serviceLocator->getServiceLocator();
        $userHydrator = new UserHydrator($sm->get('User\Mapper'));
        $aggregateHydrator = new AggregateHydrator();
        $aggregateHydrator->add($userHydrator );
        $aggregateHydrator->add($sm->get('HydratorManager')->get('Hydrator\User\Location'));
        return $aggregateHydrator;
}

}

This is throwing an expection as the model is being returned as null, but if i comment out adding the Location hydrator to the User hydrator, it works fine (albeit without location data loaded). So i was wondering if aggregate hydrators are able to be nested?

1

There are 1 best solutions below

0
On

It is not built-in, but doable.

namespace Hydrator;
use Zend\Stdlib\Hydrator\HydratorInterface;
class NestedHydrator implements HydratorInterface
{
    protected $inner_hydrator;
    private $empty;


    public function __construct ($inner_hydrator, $empty)
    {
        $this->inner_hydrator = $inner_hydrator;
        $this->empty = $empty;
    }


    public function extract ($object)
    {
        return [
            $this->getPath() => $this->inner_hydrator->extract ($object->{$this->getPath()})
        ];
    }


    public function hydrate (array $data, $object)
    {
        $object->{$this->getPath()} = $this->inner_hydrator->hydrate ($data [$this->getPath()], $this->empty);

        return $object;
    }


    protected function getPath ()
    {
        return get_class ($this->empty);
    }
}

And then:

$u = new User();
$u->Location = "4 Clinton Rd.";

$a = new Appointment();
$a->date = "yesterday";
$a->startTime = "7:00";
$a->endTime = "8:00";
$a->User = $u;

$h = new AggregateHydrator();
$h->add (new ObjectProperty());
$nested = new \Hydrator\NestedHydrator(new ObjectProperty(), new User());
$h->add ($nested);
$data = $h->extract ($a);

$b = $h->hydrate ($data, new Appointment());
$this->assertEquals ($a, $b);