zendframework/zf2 — pull request #2072 by WalterTamboer (2012-08-01 11:06:46+00:00)
Title: Hydration Strategies

The hydration component is very useful, especially in combination with forms. There is a small problem with it though. The hydrator only tells you __how__ hydration takes places but not __what__ gets hydrated. Normally this is not a problem but when one uses forms there will be trouble.

Take for example a Garage object that is filled with Car objects. Now one binds an instance of Garage to a form. In this form is a <select> element present in which multiple options can be selected (thus <select name="cars[]" multiple="multiple">). One probably creates the element as follow:

```php```
$element = new Select();
$element->setAttribute('multiple', 'multiple');
$element->setAttribute('size', '10');
$element->setAttribute('options', $dataProvider->getEntities());
$element->setName('cars');
$this->add($element);
```

Binding looks as folow:

```php```
$garage = new Garage();
$garage->addCar(new Car(1, 'Ford')); // id, name
$garage->addCar(new Car(3, 'Fiat')); // id, name

$form = new GarageForm();
$form->initElements();
$form->setHydrator(new ClassMethods());
$form->setInputFilter($garage->getInputFilter());

// Bind the garage object which makes the form populate its elements:
$form->bind($garage);
```

All good so far untill the hydrator starts to extract cars from the garage. The garage has a method _getCars_ that returns a list with Car objects. There also is a method _setCars_ that expects a list with car objects.

Since a list with car objects is returned, the Select element doesn't know how to deal with it and will thus error (for example like this: Notice: Object of class Application\Entity\Car could not be converted to int in Zend\Form\View\Helper\FormSelect.php on line 155)

The second problem is that when the form is posted, a list with integers is posted. This isbecause the options in the select element look like this:

```html```
Ford

Mercedes

Fiat

```

So how can the hydrator populate the bound object with a list of cars again? It's not possible unless one writes a custom hydrator that does that for you. An example of that is currently present in DoctrineModule.
The problem with this approach is that one needs a custom hydrator for each combination of object types that is returned.

This PR provides a solution for this problem. Instead of creating custom hydrators you can now create hydration strategies. These are reusable throughout the application. A hydration strategy basically acts as a filter before extracting and hydrating takes place.

In the garage example all one has to do is register a strategy to extract and return cars:

```php```
$hydrator->addStrategy('cars', new CarsHydrationStrategy());
```

This CarsHydrationStrategy class can look like this for example:

```php```
class CarsHydrationStrategy extends DefaultStrategy
{
private $simulatedStorageDevice;

public function __construct()
{
$this->simulatedStorageDevice = array();
$this->simulatedStorageDevice[1] = new Car(1, 'Ford');
$this->simulatedStorageDevice[2] = new Car(2, 'Mercedes');
$this->simulatedStorageDevice[3] = new Car(3, 'Fiat');
}

public function extract($value)
{
$result = array();
foreach ($value as $instance) {
$result[] = $instance->getId();
}
return $result;
}

public function hydrate($value)
{
$result = $value;
if (is_array($value)) {
$result = array();
foreach ($value as $id) {
$result[] = $this->findEntity($id);
}
}
return $result;
}

private function findEntity($id)
{
return $this->simulatedStorageDevice[$id];
}
}
```