У меня есть простое действие 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 preUpdate позволяет получить ревизию doctrine-project.org/projects/doctrine-orm/en/2.6/reference/…




Спасибо за @Cerad - ваш комментарий - это решение:
Doctrine имеет так называемый кэш единиц работы. Каждый раз, когда вы запрашиваете один и тот же идентификатор, вы всегда получаете один и тот же объект. Рассмотрите возможность клонирования своей сущности:
$prOriginal = clone $pr1;
У меня это хорошо работает.
Вам нужно понять, что Doctrine делает для вас. ORM - это не простые создатели запросов. Они сопоставляют состояние вашей базы данных с объектами в памяти, которые ваш код понимает и с которыми может работать.
Итак, когда вы передаете форму, как и вы, доктрина запрашивает объект и обновляет значения в состоянии объектов. Таким образом, после обработки формы ваш объект уже имеет состояние, отличное от того, которое находится в базе данных. Единственное, что осталось сделать доктрине, - это сохранить и очистить, или, другими словами, зарегистрировать, что изменение состояния будет отражено в базе данных (сохраниться) и фактически изменит значения db (очистить).
Если вы запрашиваете объект, который является «управляемым» (то есть, который уже был запрошен и находится в памяти доктрины), тогда доктрина предоставит вам объект в памяти для повышения эффективности. Он не будет снова запрашивать БД для этого. Вы можете вызвать метод обновления в диспетчере для обновления состояния объекта из базы данных, но это будет означать потерю состояния, которое еще не было сохранено, например данных, поступающих из вашей формы.
В этом случае я бы порекомендовал либо создать событие формы, которое будет сравнивать значение, написанное пользователем, с вашим системным значением. Событие формы должно быть preSetData, поскольку вы хотите провести сравнение до того, как ваша сущность будет обновлена новыми данными. Вы можете узнать больше об этом здесь здесь
Другой альтернативой является создание настраиваемого ограничения проверки. Если ваше системное значение фиксировано, вы можете проверить это с помощью специального валидатора. Или даже с обычным Ограничения сравнения.
Надеюсь, эта информация поможет!
Очень сомнительно, что событие preSetData действительно дает вам набор объектов до / после для сравнения. Может быть, немного кода упростит задачу? И да, вопрос сбивает с толку, так как желаемый код не соответствует описанию проблемы.
Doctrine имеет так называемый кэш единиц работы. Каждый раз, когда вы запрашиваете один и тот же идентификатор, вы всегда получаете один и тот же объект. Рассмотрите возможность клонирования вашей сущности: $ prOriginal = clone $ pr1;