ZF2/ZF3 hydrate object and nested objects from single query

822 views Asked by At

Suppose I have a query that returns the following data:

RangeId | MinValue | MaxValue | Resolution | UnitId | UnitName

I want to hydrate the object MeasurementRange with the above data.

class MeasurementRange {
    public function getRangeId() {...};
    public function setRangeId($id) {...};
    public function getRange() {...};
    public function setRange(Range $range) {...};
    public function getUnit() {...};
    public function setUnit(Unit $unit) {...};
}

class Range {
    public function getMinValue() {...};
    public function setMinValue(float $minVal) {...};
    public function getMaxValue() {...};
    public function setMaxValue(float $maxVal) {...};
    public function getResolution {...};
    public function setResolution(float $resolution) {...};
}

class Unit {
    public function getUnitId() {...};
    public function setUnitId(int $id) {...};
    public function getUnitName() {...};
    public function setUnitName(string $name) {...};
}

As you can see the MeasurementRange object has set Range and Unit objects.

How can I hydrate MeasurementRange and the inner Range and Unit objects from the above query?

PS: I didn't specify protected properties of the objects. I guess they are self-evident.

1

There are 1 answers

1
Thomas Dutrion On BEST ANSWER

You need to create a mapper, that will use your dbAdapter to fetch the data as an array, and then use hydrators to hydrate all the objects, and finally add the Range and Unit to MeasurementRange. You could alternatively create a custom hydrator (that would be even better, in terms of single responsibility).

I haven't got time to clean the example below, but that's what it could look like :)

final class LanguageMapper
{
    /**
     * @param LanguageTable   $languageTable
     * @param PackageTable    $packageTable
     * @param Cache           $cache
     * @param LoggerInterface $logger
     */
    public function __construct(LanguageTable $languageTable, PackageTable $packageTable, Cache $cache, LoggerInterface $logger)
    {
        $this->languageTable = $languageTable;
        $this->packageTable = $packageTable;
        $this->cache = $cache;
        $this->logger = $logger;
    }

    /**
     * @param array $where
     *
     * @return array List of active languages
     */
    public function findActive(array $where = [])
    {
        try {
            if (empty($where) && $this->cache->hasItem('active_languages')) {
                return unserialize($this->cache->getItem('active_languages'));
            }
        } catch (RuntimeException $exception) {
             $this->logger->critical($exception->getMessage(), [
                'exception' => $exception,
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
             ]);
        }
        /* @var $adapter \Zend\Db\Adapter\Adapter  */
        $adapter = $this->languageTable->getGateway()->getAdapter();
        $sql = new Sql($adapter);
        $select = $sql->select()->columns([Select::SQL_STAR])
            ->from('language')
            ->join('package', 'package.id = language.package', Select::SQL_STAR, Select::JOIN_LEFT)
            ->where(array_merge($where, ['active' => true]))
            ->order(['position']);
        $selectString = $sql->buildSqlString($select);

        $resultSet = $adapter->query($selectString, Adapter::QUERY_MODE_EXECUTE);
        $languages = [];
        $hydrator = new ArraySerializable();
        foreach ($resultSet as $result) {
            $language = new Language();
            $package = new Package();
            $hydrator->hydrate((array) $result, $package);
            $hydrator->hydrate((array) $result, $language);
            $language->setPackage($package);
            $languages[] = $language;
        }
        if (empty($where)) {
            try {
                $this->cache->setItem('active_languages', serialize($languages));
            } catch (RuntimeException $exception) {
                $this->logger->warning($exception->getMessage(), [
                    'exception' => $exception,
                    'file' => $exception->getFile(),
                    'line' => $exception->getLine(),
                ]);
            }
        }

        return $languages;
    }
}