В моем приложении symfony2 / doctrine2 у меня есть странный случай, когда при сохранении измененного объекта изменение не сбрасывается в базу данных, и я не могу понять, почему.
Ниже мой код:
$date = $subscription->getPaymentValidUntil()->format('d/m/Y');
$period = $payment->getDetail('period');
$validDate = $subscription->getPaymentValidUntil()
->add(new\DateInterval($period == Subscription::MONTH ? 'P1M' : 'P1Y'))
;
$subscription->setPaymentValidUntil($validDate);
$this->em->persist($subscription);
exit(var_dump(array(
$date,
$this->em->getUnitOfWork()->getScheduledEntityUpdates(),
$subscription->getPaymentValidUntil(),
)));
$this->em->flush();
Вывод vardump следующий:
array (size=3)
0 => string '12/05/2015' (length=10)
1 =>
array (size=0)
empty
2 =>
object(DateTime)[2295]
public 'date' => string '2015-06-12 18:52:37' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Paris' (length=12)
Если я сбрасываю данные перед vardump или удаляю vardump, действительно, значение даты не изменяется в моей базе данных. Зачем?
Как видите, я добавляю один месяц к этому значению даты, это отражается на объекте, но не запланировано для обновления. Как я могу решить это?
РЕДАКТИРОВАТЬ: Я копался в функции персистента диспетчера сущностей, и я понял, что при выгрузке сущности в Doctrine \ ORM \ EntityManager :: persist дата была хорошей, но при выгрузке ее в Doctrine \ ORM \ UnitOfWork :: persist, дата был каким-то образом сброшен к первоначальному:
Doctrine\ORM\EntityManager::persist
: выдает обновленную сущность
public function persist($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()' , $entity);
}
$this->errorIfClosed();
if ($entity instanceof Subscription) exit(var_dump($entity));
$this->unitOfWork->persist($entity);
}
Doctrine \ ORM \ UnitOfWork :: persist: выводит неизмененную сущность: ПОЧЕМУ?
private function doPersist($entity, array &$visited)
{
if ($entity instanceof Subscription) exit(var_dump($entity));
$oid = spl_object_hash($entity);
if (isset($visited[$oid])) {
return; // Prevent infinite recursion
}
}
DateTime
являются объектом в конце концов, и всегда передаются по ссылке. Итак, я настоятельно рекомендую вам отредактировать ваш код следующим образом:
$period = $payment->getDetail('period');
$validDate = clone $subscription->getPaymentValidUntil();
$validDate->add(new \DateInterval($period == Subscription::MONTH ? 'P1M' : 'P1Y'));
$subscription->setPaymentValidUntil($validDate);
$this->em->persist($subscription);
$this->em->flush();
Таким образом, вы гарантируете, что вы передаете объект другому объекту, и избегаете каких-либо незначительных ошибок в EntityManager.
Других решений пока нет …