Home » Php » php – How to update doctrine object type field

php – How to update doctrine object type field

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a doctrine Entity User, that implements AdvancedUserInterface. The entity has a field properties of class UserProperties, that is mapped as an object type.

My Entity:

class User implements AdvancedUserInterface, \Serializable {
<....>
    /**
     * @var UserProperties
     *
     * @ORM\Column(name="properties", type="object", nullable=true, options={"default":null})
     */
    private $properties;
<....>
}

Properties class:

class UserProperties {
    public $isEmailVisible = false;
    public $isNameVisible = false;
}

If the properties value in the database is null and I do some changes to the entity object setting the properties – it’s working fine. But if I commit some changes to the database and the properties field is NOT null (there is already a serialized UserProperties object) – the changes are not saved (but all other changes on the User entity are).

What do I do wrong?

How to&Answers:

Tracking policy of Doctrine checks whether or not an object has changed, in your case – User class. However, when checking if $this->properties has changed all Doctrine does is check if it still points to the same object in memory (!).

If you want to force it to update stored object, you can either copy all it’s properties to a new object instance (new UserProperties and then reassign it to $this->properties), clone it, or change Doctrine tracking policy to NOTIFY (see Doctrine docs).

Last one however, will require you to change all setters of the object and actually implement notification mechanism (as shown in Doctrine docs) so when this issue popped up in my code, I just recreated the object stored (which is my first suggestion, as it’s simple).

I do think however, that this is kind of unexpected behaviour, so I’d open a ticket/issue in Doctrine issue tracker, so that at least a documentation warns about this.

Answer:

Problem here is that Doctrine does not check if the values of the serialised object has changed, it only checks if the object is the same one (same memory pointer).

If you are working with object serialiser in Doctrine you need to always create a new instance of the object to save it.

I.e.

$user = $form->getData();

$properties = new UserProperties();
$properties->setProperty1($oldValue1);
$properties->setProperty2($newValue2);
...
$user->setProperties($properties);

$em->persist($properties);
$em->flush();

Of course you should be able to create a copy of the object and assign only the changed values.

$properties = clone $user->getProperties();
$properties->setProperty1($newValue);

$em->persist($properties);
$em->flush();