I have the following class diagram:
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.