# doctrine-laminas-hydrator
[![Build Status](https://travis-ci.org/doctrine/doctrine-laminas-hydrator.svg?branch=master)](https://travis-ci.org/doctrine/doctrine-laminas-hydrator)
[![Coverage Status](https://coveralls.io/repos/github/doctrine/doctrine-laminas-hydrator/badge.svg?branch=master)](https://coveralls.io/github/doctrine/doctrine-laminas-hydrator?branch=master)
This library provides Doctrine Hydrators for Laminas.
## Installation
Run the following to install this library:
```bash
$ composer require doctrine/doctrine-laminas-hydrator
```
## Usage
Hydrators convert an array of data to an object (this is called "hydrating") and
convert an object back to an array (this is called "extracting"). Hydrators are mainly used in the context of Forms,
with the binding functionality of Laminas, but can also be used in any hydrating/extracting context (for
instance, it can be used in RESTful context). If you are not really comfortable with hydrators, please first
read [Laminas hydrator's documentation](https://docs.laminas.dev/laminas-hydrator/).
### Basic usage
The library ships with a very powerful hydrator that allow almost any use-case.
#### Create a hydrator
To create a Doctrine Hydrator, you just need one thing: an object manager (also called Entity Manager in Doctrine ORM
or Document Manager in Doctrine ODM):
```php
use Doctrine\Laminas\Hydrator\DoctrineObject as DoctrineHydrator;
$hydrator = new DoctrineHydrator($objectManager);
```
The hydrator constructor also allows a second parameter, `byValue`, which is true by default. We will come back later
about this distinction, but to be short, it allows the hydrator the change the way it gets/sets data by either
accessing the public API of your entity (getters/setters) or directly get/set data through reflection, hence bypassing
any of your custom logic.
#### Example 1 : simple entity with no associations
Let's begin by a simple example:
```php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class City
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=48)
*/
protected $name;
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
```
Now, let's use the Doctrine hydrator:
```php
use Doctrine\Laminas\Hydrator\DoctrineObject as DoctrineHydrator;
$hydrator = new DoctrineHydrator($entityManager);
$city = new City();
$data = [
'name' => 'Paris',
];
$city = $hydrator->hydrate($data, $city);
echo $city->getName(); // prints "Paris"
$dataArray = $hydrator->extract($city);
echo $dataArray['name']; // prints "Paris"
```
As you can see from this example, in simple cases, the Doctrine Hydrator provides nearly no benefits over a
simpler hydrator like "ClassMethods". However, even in those cases, I suggest you to use it, as it performs automatic
conversions between types. For instance, it can convert timestamp to DateTime (which is the type used by Doctrine to
represent dates):
```php
namespace Application\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Appointment
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="datetime")
*/
protected $time;
public function getId()
{
return $this->id;
}
public function setTime(DateTime $time)
{
$this->time = $time;
}
public function getTime()
{
return $this->time;
}
}
```
Let's use the hydrator:
```php
use Doctrine\Laminas\Hydrator\DoctrineObject as DoctrineHydrator;
$hydrator = new DoctrineHydrator($entityManager);
$appointment = new Appointment();
$data = [
'time' => '1357057334',
];
$appointment = $hydrator->hydrate($data, $appointment);
echo get_class($appointment->getTime()); // prints "DateTime"
```
As you can see, the hydrator automatically converted the timestamp to a DateTime object during the hydration, hence
allowing us to have a nice API in our entity with correct typehint.
#### Example 2 : OneToOne/ManyToOne associations
Doctrine Hydrator is especially useful when dealing with associations (OneToOne, OneToMany, ManyToOne) and
integrates nicely with the Form/Fieldset logic ([learn more about this here](https://docs.laminas.dev/laminas-form/collections/)).
Let's take a simple example with a BlogPost and a User entity to illustrate OneToOne association:
```php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=48)
*/
protected $username;
/**
* @ORM\Column(type="string")
*/
protected $password;
public function getId()
{
return $this->id;
}
public function setUsername($username)
{
$this->username = $username;
}
public function getUsername()
{
return $this->username;
}
public function setPassword($password)
{
$this->password = $password;
}
public function getPassword()
{
return $this->password;
}
}
```
And the BlogPost entity, with a ManyToOne association:
```php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class BlogPost
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Application\Entity\User")
*/
protected $user;
/**
* @ORM\Column(type="string")
*/
protected $title;
public function getId()
{
return $this->id;
}
public function setUser(User $user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
```
There are two use cases that can arise when using OneToOne association: the toOne entity (in this case, the User) may
already exist (which will often be the case with a User and BlogPost example), or it can be created. The
DoctrineHydrator natively supports both cases.
##### Existing entity in the association
When the association's entity already exists, all you need to do is simply give the identifier of the association:
```php
use Doctrine\Laminas\Hydrator\DoctrineObject as DoctrineHydrator;
$hydrator = new DoctrineHydrator($entityManager);
$blogPost = new BlogPost();
$data = [
'title' => 'The best blog post in the world!',
'user' => [
'id' => 2, // Written by user 2
],
];
$blogPost = $hydrator->hydrate($data, $blogPost);
echo $blogPost->getTitle(); // prints "The best blog post in the world!"
echo $blogPost->getUser()->getId(); // prints 2
```
**NOTE** : when using association whose primary key is not compound, you can rewrite the following more succinctly:
```php
$data = [
'title' => 'The best blog post in the world!',
'user' => [
'id' => 2, // Written by user 2
],
];
```
to:
```php
$data = [
'title' => 'The best blog post in the world!',
'user' => 2,
];
```
##### Non-existing entity in the association
If the association's entity does not exist, you just need to give the object:
```php
use Doctrine\Laminas\Hydrator\DoctrineObject as DoctrineHydrator;
$hydrator = new DoctrineHydrator($entityManager);
$blogPost = new BlogPost();
$user = new User();
$user->setUsername('bakura');
$user->setPassword('p@$$w0rd');
$data =