@Qixing

Как очистить переменную в репозитарии?

Добрый день. Отследил такой момент. При выполнении определенной страницы, у меня два запроса из двух разных контроллеров к одному репозитарию, но к разным методам. Обнаружилось то, что идет продолжение накладываний условий. Подробнее:
Мой репозитарий:
class ItemRepository extends EntityRepository
{
    public $exist = null;

    public function __construct($em, ClassMetadata $class)
    {
        parent::__construct($em, $class);
        $this->exist = $this->createQueryBuilder('i')
            ->where('i.isActive = true');
    }

    public function findOneByUrl($url)
    {
        return $this->exist
            ->andWhere('i.url = :url')
            ->setParameter('url', $url)
            ->getQuery()->getSingleResult();

    }

    public function findTop()
    {
        return $this->exist
            ->getQuery()->getResult();

    }

    public function findAll()
    {
        return $this->exist
            ->getQuery()->getResult();

    }


    public function findByCategory($category)
    {
        return $this->exist
            ->andWhere('i.category = :category')
            ->setParameter('category', $category)
            ->getQuery()->getResult();
    }


}


Так вот первый запрос идет
к findOneByUrl($url)

А потом, когда независимый контроллер обращается к
findByCategory($category),
то ко всем SQL условиям еще и наследуется ->andWhere('i.url = :url') из к findOneByUrl.

Почему при создании класса переменная не обнуляется?
Стоит кеширование php-fpm
  • Вопрос задан
  • 206 просмотров
Решения вопроса 1
lexxpavlov
@lexxpavlov
Программист, преподаватель
Это в рамках обработки одного запроса? тогда всё понятно, никакое кэширование здесь ни при чём.
Вы в конструкторе создаёте билдер запросов:
$this->exist = $this->createQueryBuilder('i')
То есть, в памяти хранится объект билдера, и в дальнейшем вы обращаетесь несколько раз к этому объекту, который уже имеет своё состояние.
У вас два подхода:
1) в каждом методе создавать новый билдер и указывать им нужные общие параметры. Чтобы не дублировать код, можно сделать приватный метод getBuilderExist(), который будет создавать объект билдера и задавать базовые настройки запроса.
2) либо в методах, использующих уже существующий билдер, клонировать его и использовать копию:
public function findByCategory($category)
    {
        $qb = clone($this->exist);
        return $qb
            ->andWhere('i.category = :category')
            ->setParameter('category', $category)
            ->getQuery()->getResult();
    }


Я бы выбрал первый подход, чтобы не добавлять классу лишнее состояние.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
Почему при создании класса переменная не обнуляется?

А кто вам сказал что класс создается каждый раз?

Вообще возьмите себе в привычку, что менять конструктор репозитория это не ок. И делать любые сервисы statefull тоже не ок, но иногда нужно.

Если вам нужно какое-то базовое условие запихнуть - можно вынести это в свой метод-фабрику, которая будет создавать вам QB.

class ItemRepository extends EntityRepository
{

    public function findOneByUrl($url)
    {
        return $this->filterIsActive()
            ->andWhere('i.url = :url')
            ->setParameter('url', $url)
            ->getQuery()->getSingleResult();

    }

    public function findTop()
    {
        return $this->filterIsActive()
            ->getQuery()->getResult();

    }

    public function findAll()
    {
        return $this->filterIsActive()
            ->getQuery()->getResult();

    }


    public function findByCategory($category)
    {
        return $this->filterIsActive()
            ->andWhere('i.category = :category')
            ->setParameter('category', $category)
            ->getQuery()->getResult();
    }

    private function filterIsActive() 
    {
           return $this->createQueryBuilder('i')
                ->where('i.isActive = true');
    }


}
Ответ написан
Комментировать
virtuozzz
@virtuozzz
Web Developer
Если вам для всех запросов нужно использовать 'i.isActive = true, лучше использовать Doctrine Filters

Как уже писали выше - никакой новый объект у вас не создается и используется во всех запросах один и тот же QueryBuilder.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы