How to create custom update operation that can be rejected depending on the entity current status?

你离开我真会死。 提交于 2021-01-29 10:57:18

问题


I'm creating a custom PUT operation.

Not using the built-in operations because the affected property is not included in the default normalization for this entity, and also because this operation has a few side-effects that go beyond this entity/model.

Additionally, the update operation should only succeed if the current state of the entity on the DB matches certain expectations.

E.g. for the entity

class Lead {
    /**
    * @ORM\Column(type="integer", nullable=true)
    * @Groups({"lead", "leadReject" })
    **/
    private $rejectionReason

    public function isRejected() {
       return $this->rejectionReason !== null;

}

I'm creating the custom operation PUT /lead/{id}/reject.


class LeadReject {
     public function __invoke( Lead $data ): Lead {

           // if lead is rejected, we need not only to update its status
           // but create an entry in a LeadLog table, and update the state
           // for the Lead owner
     }
}

Problem is, by the time we get to __invoke() the $data I get has already merged the input from the user with the values from the database. Thus, any call to $data->isRejected() returns true, even if it's still null on the database.

And before I persist the object and I perform all the other operations, I need to check that Lead has not been rejected previously.

How can I do this? Can it be done at the operation controller level? I guess I could inject the EntityManager and retrieve the object again, but seems wasteful considering at this point the object has already been retrieved.


回答1:


You can add a Doctrine Listener:

<?php

namespace App\Listener;

use App\Entity\MyEntity;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;

class EntityPreUpdateListener
{
    /**
     * @param MyEntity $entity
     * @param LifecycleEventArgs $args
     */
    public function preUpdate($entity, LifecycleEventArgs $args)
    {
        $entityManager = $args->getObjectManager();
        // do whatever you need

        // you can persist your entity to the database if you need
        $entityManager->flush();

        // detach your entity, so it won't be updated
        $entityManager->detach($entity);
    }
}

And just add this line in your entity Doc Block

@ORM\EntityListeners({"App\Listener\EntityPreUpdateListener"})

You can see more information about the doctrine events here:

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/events.html




回答2:


Switch off automatic loading of the object so that retrieving the object from the Controller is not using any extra resources:

/*
 * @ApiResource(
 *     itemOperations={
 *         "put"={
 *             "read"=false
 *         }
 * )
 */
class Lead {



回答3:


Let the Entitiy remember the change transiently:

class Lead {
    /**
    * @ORM\Column(type="integer", nullable=true)
    * @Groups({"lead", "leadReject" })
    **/
    private $rejectionReason

    /** @var int|null Not mapped to the db */
    private $previousRejectionReason; 

    public function setRejectionReason($value)
    {
         $this->previousRejectionReason = $this->rejectionReason;
         $this->rejectionReason = $value;
    }

    public function isRejected() {
       return $this->rejectionReason !== null;
    }

    public function wasAlreadyRejected() {
        return $this->previousRejectionReason !== null;
    }
}

(Similar result may be obtainted by checking if the property has changed in Doctrines $entityManager::getUnitOfWork->getEntityChangeSet($lead), but i guess that's not what you're looking for...)



来源:https://stackoverflow.com/questions/56733961/how-to-create-custom-update-operation-that-can-be-rejected-depending-on-the-enti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!