Dima Dz
Dima Dz

Reputation: 538

ZF2 hydrating multiple rows into class's property that should be array

In ZF2, suppose I have a query result from the database like this:

Name | Value 
-----+-------
a    | 1
a    | 2
a    | 3
b    | 6
b    | 1
b    | 5
...

There is a class:

class SomeClass 
{
    protected $values;
    // + getter and setter for $values
}

I want to hydrate SomeClass so that I have the values property as an array, like [1, 2, 3].

How to do this?

PS: I know the hydration is done with the HydratingResultSet(), but AFAIK, HydratingResultSet() hydrates one object per table row, whereas here I need to hydrate 1 object for several rows.

EDIT: after remarks from @newage, understood that the question wasn't well described.

I need to have the objects, instantiated from SomeClass, like a = new SomeClass() and b = new SomeClass() that will have the values variables filled with [1, 2, 3] for a, and [6, 1, 5] for b -- exactly what corresponds to a and b from the database query result.

Upvotes: 0

Views: 388

Answers (2)

Dima Dz
Dima Dz

Reputation: 538

@newage, posted a great solution, but I found out there's another possibility to do what I wanted, maybe a bit simpler. There's a php function parse_str() that can parse a string from Mysql field and create an array for the values variable if you properly format the content of the mysql field. An example of a mysql join with the ZF2 that creates the needed string for parsing is like this

->join(
    ['t' => 'Table', 
    't.Id = t1.Id',
    [
        'Values' =>
            new Expression("GROUP_CONCAT(
                 DISTINCT CONCAT_WS('=', t1.Id, t1.Name) SEPARATOR '&')"
            ),
    ]
)

Upvotes: 0

newage
newage

Reputation: 909

HydratingResultSet will return a ResultSet. ResultSet implements Iterator interface. It return array of results.

If you need other collection class, you can write it. For example:

$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter'); // Get an adapter
$hydrator = new ClassMethods; // Create a hydrator.
$entity = Entity\User::class; // Entity class name
$prototype = new EntityCollection($hydrator, $entity);
$table = new TableGateway('table_name', $dbAdapter, null, $prototype);

If your entity with methods set... and get..., you need use ClassMethods hydrator. If entity with properties, need use ObjectProperty hydrator.

For creating a collection of entities. Need create a collection class, it need implement Iterator and ResultSetInterface

class EntityCollection implements Iterator, ResultSetInterface
{
    protected $entities = [];

    protected $hydrator;

    protected $entityName;

    public function __construct($hydrator, $entityName)
    {
        $this->hydrator = $hydrator;
        $this->entityName = $entityName;
    }

    public function initialize($dataSource)
    {
        foreach ($dataSource as $dataRow) {
            $this->append($this->hydrator->hydrate((array)$dataRow, new $this->entityName()));
        }
    }

    public function append($entity)
    {
        array_push($this->entities, $entity);
        return $this;
    }

    /* Need create all methods from Iterator */
    ...
}

UPDATE: after remark from @dima-dz. You can read all data from DB and use foreach.

Like this. Example

$someObjectA = new SomeClass();
$someObjectB = new SomeClass();
$result = $table->select([]);
foreach ($result as $row) {
    switch ($row->Name) {
        case 'a':
            $someObjectA->add($row->Value);
            break;
        case 'b':
            $someObjectB->add($row->Value);
            break;
    }
}

Upvotes: 1

Related Questions