Symfony 5 PreUpdate 更改值只有一个 true

问题描述

您好,感谢您的关心。
我是学生,这是我第一次创建 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);
                }
            }

            
        }
    }
}

}