Я настраиваю класс слушателя, где я установлю столбец ownerid в любой доктрине prePersist. Мой файл services.yml выглядит так …
services: my.listener: class: App\SharedBundle\Listener\EntityListener arguments: ["@security.context"] tags: - { name: doctrine.event_listener, event: prePersist }
и мой класс выглядит так …
use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\SecurityContextInterface; class EntityListener { protected $securityContext; public function __construct(SecurityContextInterface $securityContext) { $this->securityContext = $securityContext; } /** * * @param LifecycleEventArgs $args */ public function prePersist(LifecycleEventArgs $args) { $entity = $args->getEntity(); $entityManager = $args->getEntityManager(); $entity->setCreatedby(); } }
Результатом этого является следующая ошибка.
ServiceCircularReferenceException: Обнаружена циклическая ссылка для службы «doctrine.orm.default_entity_manager», путь: «doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> my.listener -> security.context -> security.authentication.manager -> fos_user .user_manager».
Мое предположение состоит в том, что контекст безопасности уже был внедрен где-то в цепочке, но я не знаю, как получить к нему доступ. Есть идеи?
У меня были подобные проблемы, и единственным обходным решением было передать весь контейнер в конструкторе ( arguments: ['@service_container']
).
use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\DependencyInjection\ContainerInterface; class MyListener { protected $container; public function __construct(ContainerInterface $container) { $this->container = $container; } // ... public function prePersist(LifeCycleEventArgs $args) { $securityContext = $this->container->get('security.context'); // ... } }
Начиная с Symfony 2.6 эта проблема должна быть исправлена. Запрос на растяжение только что был принят в мастер. Ваша проблема описана здесь. https://github.com/symfony/symfony/pull/11690
Начиная с Symfony 2.6, вы можете ввести security.token_storage
в свой прослушиватель. Эта служба будет содержать токен, используемый в SecurityContext
в <= 2.5. В 3.0 эта служба полностью заменит SecurityContext::getToken()
. Вы можете увидеть основной список изменений здесь: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service
Пример использования в версии 2.6:
Ваша конфигурация:
services: my.listener: class: App\SharedBundle\Listener\EntityListener arguments: - "@security.token_storage" tags: - { name: doctrine.event_listener, event: prePersist }
Ваш слушатель
namespace App\SharedBundle\Listener; use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class EntityListener { private $token_storage; public function __construct(TokenStorageInterface $token_storage) { $this->token_storage = $token_storage; } public function prePersist(LifeCycleEventArgs $args) { $entity = $args->getEntity(); $entity->setCreatedBy($this->token_storage->getToken()->getUsername()); } }
Для хорошего примера created_by вы можете использовать https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php для вдохновения. Он использует компонент hostnet / entity-tracker, который предоставляет специальное событие, которое запускается, когда объект изменяется во время вашего запроса. Также есть комплект для настройки в Symfony2
Я использую файлы конфигурации доктрины для установки preUpdate
или prePersist
:
Project\MainBundle\Entity\YourEntity: type: entity table: yourentities repositoryClass: Project\MainBundle\Repository\YourEntitytRepository fields: id: type: integer id: true generator: strategy: AUTO lifecycleCallbacks: prePersist: [methodNameHere] preUpdate: [anotherMethodHere]
И методы объявляются в сущности, так что вам не нужен прослушиватель, и если вам нужен более общий метод, вы можете сделать BaseEntity, чтобы сохранить этот метод и расширить другие возможности от этого. Надеюсь, поможет!
В этом потоке есть большой ответ, но все меняется. Теперь в Doctrine есть классы слушателей сущностей: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners-class
Таким образом, вы можете добавить аннотацию к своей сущности, например:
/** * @ORM\EntityListeners({"App\Entity\Listener\PhotoListener"}) * @ORM\Entity(repositoryClass="App\Repository\PhotoRepository") */ class Photo { // Entity code here... }
И создайте класс следующим образом:
class PhotoListener { private $container; function __construct(ContainerInterface $container) { $this->container = $container; } /** @ORM\PreRemove() */ public function preRemoveHandler(Photo $photo, LifecycleEventArgs $event): void { // Some code here... } }
Также вы должны определить этого слушателя в services.yml
следующим образом:
photo_listener: class: App\Entity\Listener\PhotoListener public: false autowire: true tags: - {name: doctrine.orm.entity_listener}