Хобрук: Ваш путь к мастерству в программировании

Как создать настраиваемую операцию обновления, которая может быть отклонена в зависимости от текущего статуса сущности?

Я создаю специальную PUT операцию.

Не использовать встроенные операции, потому что затронутое свойство не включено в нормализацию по умолчанию для этой сущности, а также потому, что эта операция имеет несколько побочных эффектов, выходящих за рамки этой сущности / модели.

Кроме того, операция обновления должна быть успешной только в том случае, если текущее состояние объекта в БД соответствует определенным ожиданиям.

Например. для юридического лица

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

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

}

Я создаю специальную операцию 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
     }
}

Проблема в том, что к тому времени, когда мы дойдем до __invoke(), $data, который я получаю, уже объединил введенные пользователем данные со значениями из базы данных. Таким образом, любой вызов $data->isRejected() возвращает истину, даже если он все еще null в базе данных.

И прежде чем я сохраню объект и выполню все остальные операции, мне нужно убедиться, что Lead не был отклонен ранее.

Как я могу это сделать? Можно ли это сделать на уровне операционного контроллера? Думаю, я мог бы ввести EntityManager и снова получить объект, но это кажется расточительным, учитывая, что на данный момент объект уже был получен.


Ответы:


1

Вы можете добавить слушателя доктрины:

<?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);
    }
}

И просто добавьте эту строку в свой блок документа объекта

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

Вы можете увидеть больше информации о событиях доктрины здесь:

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

03.07.2019
  • Я знаю о слушателях доктрины, но это совсем не то, что я ищу по многим причинам. Спасибо хоть. 19.07.2019

  • 2

    Отключите автоматическую загрузку объекта, чтобы при извлечении объекта из Контроллера не использовались дополнительные ресурсы:

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

    3

    Пусть Entitiy временно запомнит изменение:

    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;
        }
    }
    

    (Аналогичный результат можно получить, проверив, изменилось ли свойство в Doctrines $ entityManager :: getUnitOfWork- ›getEntityChangeSet ($ lead), но я думаю, это не то, что вы ищете ...)

    09.12.2020
    Новые материалы

    (Почти) полнофункциональная реализация Gumbel MuZero в Джулии.
    TLDR; Gumbel Muzero — это современный алгоритм обучения с подкреплением. Он достиг сверхчеловеческой производительности во многих настольных играх и даже, что более впечатляюще, в Atari..

    Передача нейронного стиля в браузерах с использованием Angular и WebDNN
    В последние годы глубокое обучение привлекло большое внимание из-за его безупречной производительности при обучении на обширных данных и высокой точности при выводе. Развертывание этих алгоритмов..

    Шифр Цезаря в C
    Шифр Цезаря  — один из самых простых и широко известных методов шифрования. Он включает в себя сдвиг каждой буквы в сообщении на определенное количество позиций в алфавите. В этой статье мы..

    Исследовательский анализ данных (EDA)
    Что такое ЭДА? Анализ данных, который ищет закономерности в данных, известен как исследовательский анализ данных. Это похоже на беглый просмотр данных, чтобы найти наиболее важные..

    1x1 Convolution: демистификация
    Чтобы пролить свет на концепцию операции свертки 1x1, которая представлена ​​в статье «Сеть в сети» Лин и др. и Google Inception Некоторое время назад я прочитал статью «Сеть в сети» (NiN),..

    Лучшие расширения VS Code в 2022 году
    Код ВС Лучшие расширения VS Code в 2022 году Список самых полезных расширений VS Code, которые вы можете использовать как разработчик в 2022 году Расширения находятся на рынке VS Code,..

    Новый подход к изучению Python и ИИ: мой путь как CodeApprenticeAI
    Будучи начинающим программистом на Python, я столкнулся со своей долей проблем при изучении языка. Кривая обучения была крутой: от борьбы со сложными объяснениями до отсутствия руководства...