# How to prepare data from SQL for nested hydrator strategy

**URL:** <https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626>\
**Category:** Components & MVC\
**Tags:** laminas-db, laminas-hydrator\
**Created:** [March 12, 2024, 10:20pm UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626 "2024-03-12T22:20:17Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![stark](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stark/32/535_2.png) [@stark](https://discourse.laminas.dev/u/stark)\
**Post date:** [March 12, 2024, 10:20pm UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/1 "2024-03-12T22:20:17Z")

</div>

Hey guys,

let’s imagine we have a Mezzio based REST API app.  
The data are stored in MariaDB so when retrieving those from DB we get a flat array:

Data from DB:

```auto
[
   'name',
   'surname',
   'sample_1',
   'sample_2',
   'sample_3'
]

```

But the response is supposed to be a nested object (which later on gets serialized to a json).

Expected response:

```auto
class Samples
{
   private string $sample_1;
   private string $sample_2;
   private string $sample_3;
}

class Someone
{
  private string $name;
  private string $surname;  
  private Samples $samples;  
}

```

Using the hydrator strategy allows only binding on some key in the array. So to make that work the original flat array would need to be modified to:

Modified response from DB:

```auto
[
   'name',
   'surname',
   'samples' = 
   [
      'sample_1',
      'sample_2',
      'sample_3'
   ]
]

```

Am I missing something or am I am looking at the issue from a wrong perspective? And of course ideally the above should work nicely with `DbSelect` so it can be passed to a `Paginator`.

---

<div class="post-metadata">

**Author:** ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)\
**Post date:** [March 13, 2024, 7:51am UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/2 "2024-03-13T07:51:09Z")

</div>

> [@stark](#):
>
> So to make that work the original flat array would need to be modified to:

This can be done in a custom hydrator which uses one of the standard hydrators with added strategies. This custom hydrator modifies the array structure before it is passed to standard hydrator.  
Another option can be the [AggregateHydrator](https://docs.laminas.dev/laminas-hydrator/v4/aggregate/) which handles different parts of the array. But I suggest to try the custom hydrator first.

---

<div class="post-metadata">

**Author:** ![stark](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stark/32/535_2.png) [@stark](https://discourse.laminas.dev/u/stark)\
**Post date:** [March 13, 2024, 8:50am UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/3 "2024-03-13T08:50:25Z")

</div>

Thanks a lot @froschdesign - I give it a go and let you know.

---

<div class="post-metadata">

**Author:** ![stark](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stark/32/535_2.png) [@stark](https://discourse.laminas.dev/u/stark)\
**Post date:** [March 13, 2024, 7:36pm UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/4 "2024-03-13T19:36:43Z")

</div>

So I have created this one way Hydrator to convert the array to a nested array.

```auto
class NestedArrayHydrator extends AbstractHydrator
{
    private string $nestedKey;

    public function __construct(string $nestedKey)
    {
        $this->nestedKey = $nestedKey;
    }

    public function hydrate(array $data, object $object): array
    {
        $reflect = new ReflectionClass($object);
        $events = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);

        foreach($events as $event)
        {
            $eventName = $event->getName();
            if (!array_key_exists($eventName, $data))
            {
                throw new InvalidKeyProvided("Key '{$eventName}' not found in the array.");
            }

            $data[$this->nestedKey][$eventName] = $data[$eventName];
            unset($data[$eventName]);
        }

        return $data;
    }

    public function extract(object $object): array
    {
        throw new RuntimeException("Not implemented.");
    }
}

```

I hope I am not violating the design 🙂

The usage itself can look like this:

```auto
$customHydrator = new NestedArrayHydrator('samples');
$restructuredData = $customHydrator->hydrate($data, new Samples());

$hydrator = new ReflectionHydrator();
$hydrator->addStrategy(
    'samples',
    new HydratorStrategy(new ReflectionHydrator(), Samples::class)
);

$hydratedResult = $hydrator->hydrate($restructuredData, new Someone());

```

I would be more than happy to get your thoughts guys, thx.

---

<div class="post-metadata">

**Author:** ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)\
**Post date:** [March 13, 2024, 8:50pm UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/5 "2024-03-13T20:50:26Z")

</div>

> [@stark](#):
>
> I hope I am not violating the design 🙂

Your class `NestedArrayHydrator` is not a hydrator because nothing is “hydrated”. In this form this makes no sense.

Here an **untested** example:

```php
final class MyHydrator implements Laminas\Hydrator\HydratorInterface
{
    private Laminas\Hydrator\HydratorInterface $baseHydrator;

    public function __construct(Laminas\Hydrator\HydratorInterface $baseHydrator)
    {
        $this->baseHydrator = $baseHydrator;
    }

    public function extract(object $object): array
    {
        $data = $this->baseHydrator->extract($object);

        // Reformat data here…

        return $data;
    }

    public function hydrate(array $data, object $object)
    {
        // Reformat data here…

        return $this->baseHydrator->hydrate($data, $object);
    }
}

```

The reformatting can be:

```php
$data['samples'] = [];
if (array_key_exists('sample_1', $data)
    && array_key_exists('sample_2', $data)
    && array_key_exists('sample_3', $data)
) {
    $data['samples'] = [
        $data['sample_1'],
        $data['sample_2'],
        $data['sample_3'],
    ];
}

```

The usage of the hydrator:

```php
$baseHydrator = new Laminas\Hydrator\ReflectionHydrator();
$baseHydrator->addStrategy(
    'samples',
    new Laminas\Hydrator\Strategy\HydratorStrategy(
        new Laminas\Hydrator\ReflectionHydrator(),
        Samples::class
    )
);
// Add more strategies here if required

$myHydrator = new MyHydrator($baseHydrator);
$myHydrator->hydrate($flatDataArrayFromDatabase, new Someone());

```

---

<div class="post-metadata">

**Author:** ![stark](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stark/32/535_2.png) [@stark](https://discourse.laminas.dev/u/stark)\
**Post date:** [March 16, 2024, 9:59pm UTC](https://discourse.laminas.dev/t/how-to-prepare-data-from-sql-for-nested-hydrator-strategy/3626/6 "2024-03-16T21:59:47Z")

</div>

Thanks a lot. I have updated the design based on your example. Again, thanks a lot for great support!
