PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, January 31, 2022

[FIXED] How to force Doctrine to update array type fields?

 January 31, 2022     arrays, doctrine, doctrine-orm, php, symfony     No comments   

Issue

I have a Doctrine entity with array type field:

/**
 * @ORM\Table()
 */
class MyEntity
{
    (...)

    /**
     * @var array $items
     * 
     * @ORM\Column( type="array" ) 
     */
    private $items;

    /**
     * @param SomeItem $item 
     */
    public function addItem(SomeItem $item)
    {
        $this->items[] = $item;
    }

    (...)
}

If I add element to the array, this code works properly:

$myEntityObject->addItems(new SomeItem()); 
$EntityManager->persist($myEntityObject);
$EntityManager->flush();

$myEntityObject is saved to the database with correct data (array is serialized, and deserialized when querying database).

Unfortunately, when I change one of the object inside array without changing size of that array, Doctrine does nothing if I'm trying to save changes to the database.

$items = $myEntityObject->getItems();
$items[0]->setSomething(123);
$myEntityObject->setItems($items);
$EntityManager->persist($myEntityObject);
$EntityManager->flush();
print_r($myEntityObject);

Although, print_r in the last line of that code displays changed object's data, Doctrine doesn't know that something was changed inside the array if array size didn't changed. Is there any way to force Doctrine to save changes made in that field (or gently inform it about changes in that field that needs to be saved) ?


Just found in documentation a way to solve my issue:

http://docs.doctrine-project.org/en/latest/reference/change-tracking-policies.html

It requires a lot of changes in the code, but it works. Does someone know how to preserve default tracking policy for other fields and use NotifyPropertyChanged just for the field that stores array?


Solution

Doctrine uses identical operator (===) to compare changes between old and new values. The operator used on the same object (or array of objects) with different data always return true. There is the other way to solve this issue, you can clone an object that needs to be changed.

$items = $myEntityObject->getItems();
$items[0] = clone $items[0];
$items[0]->setSomething(123);
$myEntityObject->setItems($items);

// ...

Or change the setItems() method (We need to clone only one object to persist the whole array)

public function setItems(array $items) 
{
    if (!empty($items) && $items === $this->items) {
        reset($items);
        $items[key($items)] = clone current($items);
    }
    $this->items = $items;
}

Regarding the second question:

Does someone know how to preserve default tracking policy for other fields and use NotifyPropertyChanged just for the field that stores array?

You cannot set tracking policy just for a one field.



Answered By - Vadim Ashikhman
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing