6   About the hydrators

6.1   About hydrators

The hydrator handles the sql query transformation into the objects that were configured in the metadata through the Repository

6.2   Default hydrator

The default hydrator will use the metadata to create the right object and will fill an associative array with, as a key, the table name (or alias used) and the object for as a value

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getCommentForSylvain()
    {
        $query = $this->getQuery('SELECT id, name, c.text FROM user LEFT JOIN comment c ON (c.user_id = user.id) WHERE name = :name');
        $query->setParams(['name' => 'Sylvain']);

        return $query->query();
    }

    // ...

The returned collection is composed of rows:

$row =
  [
    'user' => User(
      [id] => 3,
      [name] => "Sylvain"
    ),
    'c' => Comment(
      [text] => "Bonjour tout le monde"
    )
  ]

6.3   The hydrator for a single object

The default hydrator is optimized to return multiple objects when we do a query that is intended to return only one item, it is not the best choice.

You can inject CCMBenchmark\Ting\Repository\HydratorSingleObject that suit better your needs

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;
use CCMBenchmark\Ting\Repository\CollectionInterface;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getUserSylvain()
    {
        $query = $this->getQuery('SELECT id, name, c.text FROM user WHERE name = :name');
        $query->setParams(['name' => 'Sylvain']);

        return $query->query($this->getCollection(new CCMBenchmark\Ting\Repository\HydratorSingleObject()));
    }

    // ...

The returned collection is a collection of object User.

6.3.1   SQL join with no data

When the join returns no data, the key ‘c’ will be null

6.4   Data without metadata

If you perform a query that returns data that do not match any metadata, whether an aggregation column as SUM(price) or a column that has not been mapped as my_extra_column the hydrator will create a stdClass object with properties corresponding to those columns.

This stdClass object is accessible in the key 0 of the returned array.

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;
use CCMBenchmark\Ting\Repository\CollectionInterface;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getArticles()
    {
        $query = $this->getQuery('SELECT name, my_extra_column, SUM(price) as total FROM article');

        return $query->query();
    }

The returned collection is composed of rows:

$row =
  [
    0 => stdClass(
      [total] => 43,
      [my_extra_column] => 'Bic'
    ),
    'article' => Article(
      [name] => "Stylo"
    )
  ]

6.5   Mapping data without metadata

When you have an aggregate column you might want to mapped it to an object. To map the column nb_books into my model User througt the method setNbBooks you can do that:

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;
use CCMBenchmark\Ting\Repository\CollectionInterface;
use CCMBenchmark\Ting\Repository\Hydrator;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getUsersWithNbBooks()
    {
        $query = $this->getQuery('SELECT name, SUM(has_book.id) as nb_books FROM user INNER JOIN has_book ON (user.id = has_book.user_id)');
        $hydrator = new Hydrator();
        $hydrator->mapAliasTo('nb_books', 'user', 'setNbBooks')

        return $query->query($this->getCollection($hydrator));
    }

    // ...

The returned collection is composed of rows:

$row =
  [
    'user' => User(
      [name] => "name",
      [nbBooks] => 3
    )
  ]

6.6   Deserialize data without metadata

As a reminder, transform a database type into a PHP type is to deserializing. For example when you retrieve a date which is not in metadata, we may want to transform it to object Datetime.

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;
use CCMBenchmark\Ting\Repository\CollectionInterface;
use CCMBenchmark\Ting\Repository\Hydrator;
use CCMBenchmark\Ting\Serializer;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getArticlesWithFetchedDate()
    {
        $query = $this->getQuery('SELECT title, NOW() as fetchedDate FROM article');
        $hydrator = new Hydrator();
        $hydrator->unserializeAliasWith('fetchedDate', $services->get('SerializerFactory')->get(Serializer\Datetime::class))

        return $query->query($this->getCollection($hydrator));
    }

    // ...

The returned collection is composed of rows:

$row =
  [
    0 => stdClass(
      [fetchedDate] => Datetime("2016-01-13 10:41:36")
    ),
    'article' => Article(
      [name] => "My Awesome Book",
    )
  ]

6.7   Object composition

We may want to do object compositions, injecting one object into one other on many deep levels. To map object Country (which has alias co) into my model City (which has alias cit) through the method setCountry you can do that:

use CCMBenchmark\Ting\Repository\Repository;
use CCMBenchmark\Ting\Repository\MetadataInitializer;
use CCMBenchmark\Ting\Repository\CollectionInterface;
use CCMBenchmark\Ting\Repository\Hydrator;

class SampleRepository extends Repository implements MetadataInitializer
{
    /**
     * @return CollectionInterface
     */
    public function getCityWithCountry()
    {
        $query = $this->getQuery('SELECT cit.name, co.cou_name FROM city cit INNER JOIN t_country_cou co ON (c.cou_code = co.cou_code)');
        $hydrator = new Hydrator();
        $hydrator->mapObjectTo('co', 'cit', 'setCountry')

        return $query->query($this->getCollection($hydrator));
    }

    // ...

The returned collection is composed of rows:

$row =
  [
    'cit' => City(
      [name] => "Palaiseau",
      [country] => Country(
        [name] = "France"
      )
    )
  ]