Я создаю приложение Saas / Multitenant с помощью Symfony 2. Я создал подписчика событий Doctrine, чтобы добавить и обновить владельца строки, пользователя, который ее создал, пользователя, который его модифицировал, временных меток и так далее.
И теперь мне нужно реализовать какой-то фильтр, поэтому, когда пользователь вошел в систему, он может видеть только данные из своей компании. Мой первый, хотя и использовал событие Doctrine preLoad, но этого события не существует … Насколько я знаю, я должен использовать фильтры Doctrine, не так ли? Если да, как этот фильтр может получить доступ к данным пользователя, чтобы прочитать идентификатор компании? Должен ли я вводить его с помощью инъекции зависимостей? Есть ли стандартный способ достижения моей цели?
UPDATE. Я ищу, чтобы создать какой-то плагин Doctrine / hook, поэтому каждый раз, когда я вызываю любую функцию, которая извлекает данные из базы данных (find, findOneBy и т. Д.), И объект, который я получаю, реализует определенный интерфейс, extra 'AND company_id =: id' В сгенерированный запрос добавляется SQL-последовательность, поэтому ни контроллер, ни модель не получают данные от других компаний.
Для этого вы можете использовать ссылку DoctrineFilter от официальных doc Doctrine2 SQL Filters
namespace Rwmt\Bundle\RwmtBundle\DoctrineFilters; use Doctrine\ORM\Mapping\ClassMetaData, Doctrine\ORM\Query\Filter\SQLFilter; class MultiTenantFilter extends SQLFilter { public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) { // Check if the entity implements the MultiTenant interface if (!$targetEntity->reflClass->implementsInterface('Rwmt\Bundle\RwmtBundle\Entity\MultiTenant')) { return ""; } return $targetTableAlias.'.tenant_id = ' . $this->getParameter('tenantId'); } }
И для установки параметра tenantId, используемого в фильтре, вы должны включить фильтр и установить параметр
$filter = $em->getFilters()->enable('multi_tenant'); $filter->setParameter('tenantId', $tenant->getId(), 'integer');
Что касается интерфейса MultiTenant, это просто что-то для сущностей для реализации
namespace Rwmt\Bundle\RwmtBundle\Entity; use Rwmt\Bundle\RwmtBundle\Entity\Tenant; interface MultiTenant { public function setTenant(Tenant $tenant); public function getTenant(); }
Фильтрация в Doctrine2 проста. Просто назначьте функцию фильтра переменной, затем отправьте эту переменную в качестве параметра через метод filter (), включенный в класс ArrayCollection.
$closure = function($list_item) use($user) { return $list_item->belongsToSameCompanyThatEmploys($user) === true; }; $filtered_array_collection = $arrayYouWantToFilter->filter($closure);
В этом примере вам нужно было бы ранее определить метод, belongsToSameCompanyThatEmploys($user)
в классе list_item, который возвращает true
если он принадлежит той же компании, для которой работает пользователь.
UPDATE
Необходимо также указать, что функция фильтра должна использовать пользователя локальной переменной, так как иначе он не будет иметь свою собственную область.