Как получить исходные данные перед изменением?

У меня есть простое действие editAction для Product Entity. Он отлично работает стандартным способом, но мне нужна специальная проверка, прежде чем я сохраню Product после редактирования. Товар имеет несколько цен в отдельных полях. У меня в проекте есть общая установка «минимальной цены» на товары. Прежде чем сохранить Товар после редактирования, я хочу сравнить цены с «минимальной ценой». Я так делаю:

public function editAction(Request $request, Product $pr1, UserInterface $op)
{
    // 1
    $pr_original = $this->getDoctrine()->getRepository(Product::class)->getProductById($pr1->getId());

    $form = $this->createForm('AppBundle\Form\ProductType', $product);
    $form->handleRequest($request); 

    if ($form->isSubmitted() && $form->isValid())
    {
        // 2
        $em = $this->getDoctrine()->getManager();
        $em->persist($product);
        $em->flush();
    }

    return $this->redirect(path('product_list'));
}

Во 2 есть место, где я сравниваю значения. Но проблема в том ... Я не могу сравнить исходные значения. В 1 я хочу получить оригинальный Продукт, но он будет $pr_original с уже измененными значениями! Это странно, потому что я вижу прямо в базе данных, что объект все еще имеет исходные значения. Поэтому я думаю, что Symfony не делает новый запрос к базе данных. Так что же теперь делать? Как заставить Symfony получить оригинальный объект?

Doctrine имеет так называемый кэш единиц работы. Каждый раз, когда вы запрашиваете один и тот же идентификатор, вы всегда получаете один и тот же объект. Рассмотрите возможность клонирования вашей сущности: $ prOriginal = clone $ pr1;

Cerad 17.05.2018 17:18

Хочу добавить, что событие Doctrine preUpdate позволяет получить ревизию doctrine-project.org/projects/doctrine-orm/en/2.6/reference/‌…

Francesco Abeni 19.05.2018 16:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
2
746
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Спасибо за @Cerad - ваш комментарий - это решение:

Doctrine имеет так называемый кэш единиц работы. Каждый раз, когда вы запрашиваете один и тот же идентификатор, вы всегда получаете один и тот же объект. Рассмотрите возможность клонирования своей сущности:

$prOriginal = clone $pr1;

У меня это хорошо работает.

Ответ принят как подходящий

Вам нужно понять, что Doctrine делает для вас. ORM - это не простые создатели запросов. Они сопоставляют состояние вашей базы данных с объектами в памяти, которые ваш код понимает и с которыми может работать.

Итак, когда вы передаете форму, как и вы, доктрина запрашивает объект и обновляет значения в состоянии объектов. Таким образом, после обработки формы ваш объект уже имеет состояние, отличное от того, которое находится в базе данных. Единственное, что осталось сделать доктрине, - это сохранить и очистить, или, другими словами, зарегистрировать, что изменение состояния будет отражено в базе данных (сохраниться) и фактически изменит значения db (очистить).

Если вы запрашиваете объект, который является «управляемым» (то есть, который уже был запрошен и находится в памяти доктрины), тогда доктрина предоставит вам объект в памяти для повышения эффективности. Он не будет снова запрашивать БД для этого. Вы можете вызвать метод обновления в диспетчере для обновления состояния объекта из базы данных, но это будет означать потерю состояния, которое еще не было сохранено, например данных, поступающих из вашей формы.

В этом случае я бы порекомендовал либо создать событие формы, которое будет сравнивать значение, написанное пользователем, с вашим системным значением. Событие формы должно быть preSetData, поскольку вы хотите провести сравнение до того, как ваша сущность будет обновлена ​​новыми данными. Вы можете узнать больше об этом здесь здесь

Другой альтернативой является создание настраиваемого ограничения проверки. Если ваше системное значение фиксировано, вы можете проверить это с помощью специального валидатора. Или даже с обычным Ограничения сравнения.

Надеюсь, эта информация поможет!

Очень сомнительно, что событие preSetData действительно дает вам набор объектов до / после для сравнения. Может быть, немного кода упростит задачу? И да, вопрос сбивает с толку, так как желаемый код не соответствует описанию проблемы.

Cerad 17.05.2018 17:42

Другие вопросы по теме