问题描述
您好,感谢您的关心。
我是学生,这是我第一次创建 eventSubriber。
当我尝试更新实体“Menu”之一时,我想更改实体“Menu”中的所有属性“display”(布尔值)在我的所有实体中,属性“显示”为真。
如果您需要了解,我会在我的项目 Symfony 中使用 EasyAdmin 3。
我的问题开始于 $this->entityManager->flush();我认为在 UniqueBoolTureEvent.PHP 中。
先谢谢你。
Service.yaml
App\EventListener\UniqueBoolTrueEvent:
tags:
- { name: doctrine.event_listener,event: preUpdate,Lazy: true }
UniqueBoolTrueEvent.PHP
<?PHP
namespace App\EventListener;
use App\Entity\Menu;
use Doctrine\Common\EventSubscriber;
// Entity to listen
use Doctrine\Persistence\ObjectManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
class UniqueBoolTrueEvent implements EventSubscriber {
private $entityManager;
/**
* @param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function getSubscribedEvents() {
return array('preUpdate');//Event to listen
}
public function preUpdate( PreUpdateEventArgs $eventArgs ) {
if ($eventArgs->getEntity() instanceof Menu) {
if ($eventArgs->hasChangedField('display') && $eventArgs->getNewValue('display') == 'true') {
//get the id of entity change for true
$entityId = $eventArgs->getEntity()->getId();
// search the entity already on true exept entity change Now
$displayTrue = $this->entityManager->getRepository(Menu::class)->findBydisplay($entityId);
//Change the value for entity already on true exept entity change Now
foreach ($displayTrue as $display) {
$display->setdisplay(false);
$this->entityManager->persist($display);
}
$this->entityManager->flush();
}
}
}
}
MenuRepository.PHP
<?PHP
namespace App\Repository;
use App\Entity\Menu;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Menu|null find($id,$lockMode = null,$lockVersion = null)
* @method Menu|null findOneBy(array $criteria,array $orderBy = null)
* @method Menu[] findAll()
* @method Menu[] findBy(array $criteria,array $orderBy = null,$limit = null,$offset = null)
*/
class MenuRepository extends ServiceEntityRepository
{
/**
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry,Menu::class);
}
/**
* @return Menu[] Returns an array of Menu objects
*/
public function findBydisplay($entityId)
{
return $this->createqueryBuilder('m')
->andWhere('m.display = true')
->andWhere('m.id != :entityId')
->setParameter('entityId',$entityId)
->orderBy('m.id','ASC')
->getQuery()
->getResult()
;
}
}
之后,我的 ajax 请求中只有一个错误,看不到问题出在哪里。 提前致谢。
解决方法
My Solution No 2 Solutions lol
第一个使用 EventSubscriberInterface 和 BeforeEntityUpdatedEvent 的解决方案。使用此解决方案,您无需在 service.yaml 中添加配置
class UniqueBoolTrueEvent implements EventSubscriberInterface
{
private $entityManager;
/**
* @param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public static function getSubscribedEvents()
{
return [
BeforeEntityUpdatedEvent::class => ['setDisplayTrue'],];
}
public function setDisplayTrue(BeforeEntityUpdatedEvent $event)
{
$entity = $event->getEntityInstance();
$entityId = $entity->getId();
if ($entity instanceof Menu) {
$displayTrue = $this->entityManager->getRepository(Menu::class)->findByDisplay($entityId);
foreach ($displayTrue as $display) {
$display->setDisplay(false);
$this->entityManager->persist($display);
}
$this->entityManager->flush();
}
}
}
我的第二个解决方案 onFlush()
service.yaml
App\EventListener\UniqueBoolTrueEvent:
tags:
- { name: doctrine.event_listener,event: onFlush}
UniqueBoolTrueEvent.php
类 UniqueBoolTrueEvent {
private $entityManager;
/**
* @param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function onFlush(OnFlushEventArgs $eventArgs)
{
$em = $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();
$entities = $uow->getScheduledEntityUpdates();
foreach ($entities as $entity) {
//continue only if the object to be updated is a Ticket
if ($entity instanceof Menu) {
$entityId = $entity->getId();
$entityDisplay = $entity->getDisplay();
// //get all the changed properties of the Menu object
// $changes_set = $uow->getEntityChangeSet($entity);
//Check if the changed value of "display" is True
if ($entityDisplay == true) {
//find the entity with "display" value true exept the entity update
$displayTrue = $this->entityManager->getRepository(Menu::class)->findByDisplay($entityId);
// Change the value of "display" to false for each entity on true exept the entity update
foreach ($displayTrue as $display) {
$display->setDisplay(false);
$em->persist($display);
// for flush
$classMetadata = $em->getClassMetadata(get_class($entity));
// dd($classMetadata);
$uow->computeChangeSet($classMetadata,$display);
}
}
}
}
}
}