экземпляры DateTime
, возвращенные ExampleBundle\Entity\User#getServiceExpiresAt()
, - это те же объекты, которые хранятся в самой сущности, которая прерывает инкапсуляцию .
Применяется UnitOfWork в ORM доктрины строгое сравнение для наборов изменений , что в основном означает, что в случае свойств объектов, содержащих объекты, если экземпляр объекта не изменился, ORM не обнаруживает изменения.
При строгом сравнении , верно следующее:
$dateTime1 = new \DateTime('@0');
$dateTime2 = new \DateTime('@0');
$dateTime3 = $dateTime1;
var_dump($dateTime1 !== $dateTime2); // true
var_dump($dateTime1 === $dateTime3); // true
$dateTime1->modify('+1 day');
var_dump($dateTime1 === $dateTime3); // true
Это очень распространенная ошибка среди новичков в программировании ООП, и ее можно быстро решить, установив ваши геттеры и сеттеры, чтобы исходный экземпляр никогда не делился вне вашего объект, как в следующем примере:
public function getServiceExpiresAt()
{
return clone $this->service_expires_at;
}
public function setServiceExpiresAt(\DateTime $service_expires_at)
{
$this->service_expires_at = clone $service_expires_at;
}
Это также устранит вашу проблему с помощью Doctrine ORM.
Также обратите внимание, что это устраняет возможные утечки в вашей логике. Например, следующий код ошибочен и трудно отлаживается (при применении ваших сломанных геттеров / сеттеров):
$bankTransaction1 = $someService->getTransaction(1);
$bankTransaction2 = $someService->getTransaction(2);
// leak! Now both objects reference the same DateTime instance!
$bankTransaction2->setDateTime($bankTransaction1->getDateTime());
// bug! now both your objects were modified!
$bankTransaction1->getDateTime()->modify('+1 day');
Итак, независимо от части ORM в вопросе, пожалуйста, не прерывайте инкапсуляцию.