Filter in doctrine

Познакомимся на примере с фильтрами в доктрине.

Цель: сделать так, чтобы неавторизованный пользователь видел только публичные статьи ( Article ).

Вариант 1

Создаем наш фильтр:

<?php

declare(strict_types=1);

namespace App\EntityFilter;

use App\Entity\Article;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;

/**
 * https://symfonycasts.com/screencast/doctrine-queries/filters
 * https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/filters.html
 */
class ArticleFilter extends SQLFilter
{
    /**
     * По мотивам https://symfonycasts.com/screencast/doctrine-queries/filters
     *
     * @inheritDoc
     */
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        if ($targetEntity->getName() === Article::class) {
            return $targetTableAlias.'.isShow = 1';
        }
        return '';
    }
}

Расскажем доктрине про наш фильтр:

doctrine:
    orm:
        auto_generate_proxy_classes: true
        default_entity_manager: entity_manager_oltp
        entity_managers:
            entity_manager_oltp:
                filters:
                    article_filter:
                        class: App\EntityFilter\ArticleFilter
                        # enabled: true - закммментировали, по умолчанию: false

Включаем фильтр, только если пользователь не авторизован:

<?php

declare(strict_types=1);

namespace App\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;

class DataAccessListener
{
	private ?UserInterface $user;
	private EntityManagerInterface $entityManager;

	public function __construct(Security $security, EntityManagerInterface $entityManager)
    {
        $this->user = $security->getUser();
        $this->entityManager = $entityManager;
    }

    public function onKernelController(ControllerEvent $event): void
    {
        if ($this->user === null) {
            $this->entityManager
                ->getFilters()
                ->enable('article_filter');
        }
    }
}

Подпишем нашего слушателя на событие:

services:
    App\EventListener\DataAccessListener:
        tags:
            - { name: kernel.event_listener, event: kernel.controller }

Готово.

Вариант 2 - попроще

Создаем наш фильтр сразу вместе с Security :

<?php

declare(strict_types=1);

namespace App\EntityFilter;

use App\Entity\Article;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
use Symfony\Component\Security\Core\Security;

/**
 * https://symfonycasts.com/screencast/doctrine-queries/filters
 * https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/filters.html
 */
class ArticleFilter extends SQLFilter
{
    private ?Security $security = null;

    public function setSecurity(Security $security)
    {
        $this->security = $security;
    }

    /**
     * По мотивам https://symfonycasts.com/screencast/doctrine-queries/filters
     *
     * @inheritDoc
     */
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        if ($this->security && $this->security->getUser() !== null) {
            return '';
        }
        if ($targetEntity->getName() === Article::class) {
            return $targetTableAlias.'.isShow = 1';
        }
        return '';
    }
}

Инъектим Security :

    App\EntityFilter\ArticleFilter:
        calls:
            - setSecurity: [ '@security.helper' ]

Расскажем доктрине про наш фильтр:

doctrine:
    orm:
        auto_generate_proxy_classes: true
        default_entity_manager: entity_manager_oltp
        entity_managers:
            entity_manager_oltp:
                filters:
                    article_filter:
                        class: App\EntityFilter\ArticleFilter
                        enabled: true

Готово.


11.09.2021 07:08