0

I have the following class diagram:

enter image description here

When I try to persist the $blockImage collection on a new ImageContentBlock the first ImageContentBlockImage object (always the one with $order = 1) is dropped from the collection and not persisted. I can trace its existing back until the point I'm actually persisting (and flushing) the object.

The ImageContentBlock => ImageContentBlockImage relation is defined as OneToMany, where the ImageContentBlockImage object as a ManyToOne relation with a JoinColumn. The ImageContentBlockImage => Image relation is a ManyToOne relation. All of these relations use the following cascade options: cascade={"merge", "persist", "detach"}

The objects are temporarily added, managed and edited in serialised string through Redis before they are persisted. The objects are retrieved from Redis correctly and stored back into it again.

I have the following code when I get the objects out of Redis and intent to persist them in the entity manager. The objects need to be merged (attached) after detaching them.

if ($block instanceof ImageContentBlock) {
    /**
     * @var ImageContentBlock $block
     * @var ImageContentBlockImage $blockImage
     * @var Image $mergedImage
     * @var ArrayCollection $images ;
     */
    $blockImages = $block->getBlockImages();
    $block->setBlockImages(new ArrayCollection());

    foreach ($blockImages as $blockImageUuid => $blockImage) {
        // merge the image?
        $image = $blockImage->getImage();
        $blockImage->setImage(new Image());

        $image = $entityManager->merge($image);
        $blockImage->setImage($image);

        // set the image block
        $blockImage->setBlock($block);

        if (!is_null($blockImage->id)) {
            $blockImage = $entityManager->merge($blockImage);
        }

        if (is_null($blockImage->id)) {
            $entityManager->persist($blockImage);
        }

        // put it back!
        $block->putImageContentBlockImage($blockImage, $blockImageUuid);
    }
}

I have read about the limitations of Doctrine and its bad practices. I guess this is one of them? But I do need this setup to work. How can I achieve this?

Edit 1: I've been digging into this bug even further. I found this issue here on StackOverflow. This dude did debug the EntityManager and the UnitOfWork. When I add 3 ImageContentBlockImage objects to the ImageContentBlock object they are added to the UnitOfWork and marked for persistence. But one, the first one, is never written to the db. Their solution is to persist the temporary data to the database and not to keep in session (Redis in my case). I use a lot of requests that manage these objects, it would slow down the user experience. So how can I enforce this to work?

Edit 2: When trying to create a new ImageContentBlock object with 3 ImageContentBlockImage objects. The output of the UnitOfWork is;

array (size=3)
  '0000000001fdf8f000000000117b20f8' => 
    object(stdClass)[1214]
      public '__CLASS__' => string 'Pagewize\Domain\Block\ContentBlock\Image\ImageContentBlockImage' (length=63)
      public 'block' => string 'Pagewize\Domain\Block\ContentBlock\Image\ImageContentBlock' (length=58)
      public 'image' => string 'PagewizeProxy\__CG__\Pagewize\Domain\File\Image' (length=47)
[..]
  '0000000001fdf8f200000000117b20f8' => 
     object(stdClass)[1255]
       public '__CLASS__' => string 'Pagewize\Domain\Block\ContentBlock\Image\ImageContentBlockImage' (length=63)
       public 'block' => string 'Pagewize\Domain\Block\ContentBlock\Image\ImageContentBlock' (length=58)
       public 'image' => string 'PagewizeProxy\__CG__\Pagewize\Domain\File\Image' (length=47)
[..]
  '0000000001fdf8fb00000000117b20f8' => 
     object(stdClass)[1257]
        public '__CLASS__' => string 'Pagewize\Domain\Block\ContentBlock\Image\ImageContentBlock' (length=58)
        public 'blockImages' => string 'Array(3)' (length=8)

I can see there is one ImageContentBlockImage object missing from the UnitOfWork. This is before i call the flush operation, after doing some merge operations and such. I guess i'll have to look into the flow.

Still if someone can point me into the right direction..

Edit 3: Alright, I have been testing with the JMS Serializer to rule out the php-serialiser problem that Doctrine has. When I debug the application I can see the new ImageContentBlockImage is added with its (unique) Image object. All the ImageContentBlockImage objects have their own Image. After submitting the page that holds the Block objects, and the array is deserialised from Redis I can see that 2 ImageContentBlockImage objects have a reference to the same the Image object. This reference is unique while I'm on the page and I add an image.

Community
  • 1
  • 1
  • Did you [initialize your collections](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/best-practices.html#initialize-collections-in-the-constructor) correctly? – Wilt Sep 14 '16 at 14:32
  • @Wilt yep, collections are initialised in the constructors. – Hugo Zonderland Sep 14 '16 at 14:35
  • Research is continuing. I'm guessing I have to switch serialisers. – Hugo Zonderland Sep 15 '16 at 13:53
  • Switched to JMS Serializer, but this doesn't solve the problem. When I submit the page and request the array (serialised) from Redis and deserialise the content I can see that 2 of the `ImageContentBlockImage` objects hold a reference to the same `Image` object. – Hugo Zonderland Sep 20 '16 at 10:37

0 Answers0