Symfony Doctrine Hydrator - с пользовательским гидратором я теряю отношения ManyToOne

Я хотел бы расширить ObjectHydrator, чтобы улучшить гидратацию моего отношения ManyToOne и добавить дополнительное поле к сущности.

Вот мой гидратор: StatisticsDataHydrator.php

namespace AppBundle\Hydrator\ProjectAssignment;

use AppBundle\Entity\ProjectAssignment;
use Doctrine\ORM\Internal\Hydration\ObjectHydrator;

    class StatisticsDataHydrator extends ObjectHydrator
    {
        /**
         * {@inheritdoc}
         */
        protected function hydrateRowData(array $data, array &$result)
        {
            $hydrated_result = array();
            parent::hydrateRowData($data, $hydrated_result);

            /** @var ProjectAssignment $project_assignment */
            $project_assignment = $hydrated_result[0][0];

            $result[] = $project_assignment;
        }
    }

Вот мой конфиг: config.yml

doctrine:
    orm:
        hydrators:
            project_assignment_statisticsdata_hydrator: AppBundle\Hydrator\ProjectAssignment\StatisticsDataHydrator

Где я не использую гидратор, у меня нет проблем:

/**
 * @param ProjectStage $stage
 * @return array
 */
public function findByStageWithStatisticsData(ProjectStage $stage){
    $qb = $this->createQueryBuilder('pa');

    $qb
        //->addSelect('44')
        ->where($qb->expr()->eq('pa.project_stage', ':stage'))
        ->setParameter('stage', $stage);

    return $qb->getQuery()->getResult();
}

Но когда я использую мой гидратор:

/**
 * @param ProjectStage $stage
 * @return array
 */
public function findByStageWithStatisticsData(ProjectStage $stage){
    $qb = $this->createQueryBuilder('pa');

    $qb
        ->addSelect('1234') // referencial value
        ->where($qb->expr()->eq('pa.project_stage', ':stage'))
        ->setParameter('stage', $stage);

    return $qb->getQuery()->getResult('project_assignment_statisticsdata_hydrator');
}

Самое странное поведение - то же самое происходит с этим config: config.yml

doctrine:
    orm:
        hydrators:
            project_assignment_statisticsdata_hydrator: Doctrine\ORM\Internal\Hydration\ObjectHydrator

Я перепробовал все виды отношений без успеха:

@ORM\ManyToOne(... , fetch="EAGER")
@ORM\ManyToOne(... , fetch="LAZY")
...

Может быть, я должен использовать прокси на моей сущности, я действительно не знаю:(

Спасибо за любую помощь!

1 ответ

Большой! Я нашел проблему, это было с моим конструктором запросов. Мне пришлось вручную добавлять объединения и выбирать связанные объекты.

/**
 * @param ProjectStage $stage
 * @return array
 */
public function findByStageWithStatisticsData(ProjectStage $stage){
    $qb = $this->createQueryBuilder('pa');

    $qb
        ->addSelect('e') // added
        ->addSelect('r') // added
        ->addSelect('1234')
        ->leftJoin('pa.employee', 'e')  // added
        ->leftJoin('pa.role', 'r')  // added
        ->where($qb->expr()->eq('pa.project_stage', ':stage'))
        ->setParameter('stage', $stage);

    return $qb->getQuery()->getResult('project_assignment_statisticsdata_hydrator');
}

Бонус, вот мой Гидратор (он может кому-то помочь):

namespace AppBundle\Hydrator\ProjectAssignment;

use AppBundle\Entity\Hydrator\ProjectAssignment\StatisticsData;
use AppBundle\Entity\ProjectAssignment;
use Doctrine\ORM\Internal\Hydration\ObjectHydrator;

class StatisticsDataHydrator extends ObjectHydrator
{
    /**
     * {@inheritdoc}
     */
    protected function hydrateRowData(array $data, array &$result)
    {
        $hydrated_result = array();
        parent::hydrateRowData($data, $hydrated_result);

        /** @var ProjectAssignment $project_assignment */
        $project_assignment = $hydrated_result[0][0];

        $keys = array_keys($hydrated_result); $key = end($keys);

        $statistics_data = new StatisticsData($project_assignment);
        $statistics_data->setTotalWorkedTime((int)$hydrated_result[$key][1]);

        $project_assignment->setStatisticsData($statistics_data);

        $result[] = $project_assignment;
    }
}

В моей сущности у меня есть следующий атрибут /getter/setter

/********** NON SYNCED FIELDS **********/

/** @var StatisticsData $statistics_data */
private $statistics_data;

/**
 * @return StatisticsData
 */
public function getStatisticsData()
{
    return $this->statistics_data;
}

/**
 * @param StatisticsData $statistics_data
 */
public function setStatisticsData($statistics_data)
{
    $this->statistics_data = $statistics_data;
}

/***************************************/

Проблема в том, что Doctrine SqlWalker не будет загружать мета-столбцы, которые включают подклассы и ассоциации, если запрос Hydration Mode не HYDRATE_OBJECT или если запрос подсказка HINT_INCLUDE_META_COLUMNS к истине:

$addMetaColumns = ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
    $this->query->getHydrationMode() == Query::HYDRATE_OBJECT
    ||
    $this->query->getHydrationMode() != Query::HYDRATE_OBJECT &&
    $this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS);

О проблеме уже сообщалось в этом выпуске.

Как уже упоминалось автором проблемы, вы можете либо внедрить предложенное исправление, либо установить подсказку к запросу. HINT_INCLUDE_META_COLUMNS к истине:

$query = $queryBuilder->getQuery();
$query->setHint(Query::HINT_INCLUDE_META_COLUMNS, true);
$result = $query->getResult('CustomHydrator');
Другие вопросы по тегам