Ошибка: 'c' используется вне области его объявления - PullRequest
0 голосов
/ 29 мая 2018

Приложение имеет страницу статистики, представляющую десятки расчетов.Чтобы избежать дублирования кода в репозитории, ошибка

Ошибка: 'c' используется вне области его объявления

возникает при попытке вставить DQL с условиями вQueryBuilder.

Основными объектами являются Домохозяйство и Контакт.Расчеты основаны на диапазоне дат контакта, месте (место контакта) и типе (тип контакта).Существует служба, которая создает массив операторов where и параметров запроса, как будет видно из приведенного ниже кода.

Я знаю, что расчет работает, если весь код выполняется в одной функции.Кажется, проблема возникает из-за объединения с объектом Contact и его необходимыми ограничениями.Можно ли выполнить DRY в этом сценарии?

В хранилище сущности домохозяйства появляется все следующее:

DQL:

private function reportHousehold($criteria)
{
    return $this->createQueryBuilder('i')
        ->select('i.id')
            ->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH',
                'c.household = i')
            ->where($criteria['betweenWhereClause'])
            ->andWhere($criteria['siteWhereClause'])
            ->andWhere($criteria['contactWhereClause'])
            ->getDQL()
    ;
}

Пример $ критерия: $criteria['betweenWhereClause'] = 'c.contactDate BETWEEN :startDate AND :endDate'

Один из расчетов по домашнему хозяйству:

public function res($criteria)
{
    $parameters = array_merge(
        $criteria['betweenParameters'], $criteria['siteParameters'],
        $criteria['startParameters'], $criteria['startParameters'],
        $criteria['contactParameters']);
    $qb = $this->getEntityManager()->createQueryBuilder();

    return $this->getEntityManager()->createQueryBuilder()
            ->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
            ->from('TruckeeProjectmanaBundle:Household', 'h')
            ->distinct()
//DQL inserted here:
            ->where($qb->expr()->in('h.id', $this->reportHousehold($criteria)))
            ->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
            ->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
            ->andWhere($criteria['startWhereClause'])
            ->setParameters($parameters)
            ->getQuery()->getResult()
    ;
}

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

В некотором смысле Preciel верен: решение требует использования $this->getEntityManager()->createQueryBuilder().Вместо внедрения DQL в качестве подзапроса, хитрость заключается в том, чтобы вернуть массив идентификаторов и использовать этот массив в предложении IN.Эффект заключается в том, чтобы исключить из расчета любые соображения о субъектах, отличных от субъекта домохозяйства.Вот результат:

public function res($criteria)
{
    $parameters = array_merge($criteria['startParameters'], $criteria['startParameters'], ['hArray' => $this->reportHousehold($criteria)]);
    $qb = $this->getEntityManager()->createQueryBuilder();

    return $this->getEntityManager()->createQueryBuilder()
            ->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
            ->from('TruckeeProjectmanaBundle:Household', 'h')
            ->distinct()
            ->where('h.id IN (:hArray)')
            ->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
            ->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
            ->setParameters($parameters)
            ->getQuery()->getResult()
    ;
}

private function reportHousehold($criteria)
{
    $parameters = array_merge($criteria['betweenParameters'], $criteria['siteParameters'], $criteria['contactParameters']);
    return $this->createQueryBuilder('i')
            ->select('i.id')
            ->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH', 'c.household = i')
            ->where($criteria['betweenWhereClause'])
            ->andWhere($criteria['siteWhereClause'])
            ->andWhere($criteria['contactWhereClause'])
            ->setParameters($parameters)
            ->getQuery()->getResult()
    ;
}
0 голосов
/ 29 мая 2018

Вам не хватает getRepository() или from()

Попробуйте это (мой предпочтительный выбор):

private function reportHousehold($criteria) {
    return $this->getEntityManager
                ->createQueryBuilder()
                ->select("i.id")
                ->from(YourEntity::class, "i")
                ->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
                ->where($criteria['betweenWhereClause'])
                ->andWhere($criteria['siteWhereClause'])
                ->andWhere($criteria['contactWhereClause'])
                ->getQuery()
                ->execute();
}

Или это

private function reportHousehold($criteria) {
    return $this->getEntityManager
                ->getRepository(YourEntity::class)
                ->createQueryBuilder("i")
                ->select("i.id")
                ->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
                ->where($criteria['betweenWhereClause'])
                ->andWhere($criteria['siteWhereClause'])
                ->andWhere($criteria['contactWhereClause'])
                ->getQuery()
                ->execute();
}

ОсторожноЯ предполагаю, что вы используете Symfony 3 или выше.
Если нет, замените YourEntity::class синтаксисом Symfony 2, который равен "YourBundle:YourEntity"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...