[DDC-2302] entity not updating with existing \Datetime object Created: 17/Feb/13  Updated: 08/Sep/13  Resolved: 08/Sep/13

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.1.7
Fix Version/s: None
Security Level: All

Type: Bug Priority: Minor
Reporter: Stephan Tijink Assignee: Benjamin Eberlei
Resolution: Invalid Votes: 0
Labels: None
Environment:

ubuntu 12.04
PHP 5.3.10
PostgreSQL 8.4
Symfony 2.0.15



 Description   

Within an entity i have an method to add days to a subscription. For that an datetime object is modified.

But the database is not going to be updated if an already existing datetime-object is modified an set. It's only working when an freshly created datetime object is used.

NOT WORKING EXAMPLE:

    public function addDaysToSubscription($days) {

        if ($this->hasValidSubscription()) {

            $startFromDate = $this->getSubscriptionValidUntil();
        }
        else {

            $startFromDate = new \DateTime('now');
        }

        $this->setSubscriptionValidUntil($startFromDate->modify('+' . $days .' days'));
    }

WORKAROUND:

    public function addDaysToSubscription($days) {

        if ($this->hasValidSubscription()) {

            $validDate = $this->getSubscriptionValidUntil()->format('Y-m-d H:i:s');
            $startFromDate = new \DateTime($validDate);
        }
        else {

            $startFromDate = new \DateTime('now');
        }

        $this->setSubscriptionValidUntil($startFromDate->modify('+' . $days .' days'));
    }


 Comments   
Comment by Benjamin Eberlei [ 17/Feb/13 ]

From the documentation (Mapping Objects):

DateTime and Object types are compared by reference, not by value. Doctrine updates this values if the reference changes and therefore behaves as if these objects are immutable value objects.

You have to replace them with a new instance.

Comment by Stephan Tijink [ 17/Feb/13 ]

Whats the reason for this behaviour ? For me it seem not very intuitive and cost me a couple of hours of project time

Comment by Marco Pivetta [ 17/Feb/13 ]

Stephan Tijink there is no real "global" way of comparing objects in PHP. The only way would be to use a non-strict comparison (aka `==` vs `===`), and that leads to many unexpected problems.

Since `DateTime` instances are objects like any other, the comparison is applied with `===`.

This the safest way to handle this is to work with it as if it was an immutable:

public function setCreationTime(\DateTime $dateTime)
{
    $this->creationTime = clone $dateTime;
}

public function getCreationTime(\DateTime $dateTime)
{
    return clone $this->creationTime;
}

This basically disallows a lot of unexpected behaviors, even when not working with the ORM.

Comment by Benjamin Eberlei [ 17/Feb/13 ]

Also DateTime objects being mutable was a mistake in PHP, this is why 5.5 will have DateTimeImmutable, which we will switch to if possible in the future

Comment by Benjamin Eberlei [ 08/Sep/13 ]

Change to 'Invalid'

Generated at Fri Sep 19 09:48:59 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.