Skip to content

Conversation

cuca24
Copy link
Contributor

@cuca24 cuca24 commented Jul 25, 2024

Changes in this pull request

Resolves #
Duplicate relations on event listeners save

Additional info

Prerequisite

  1. Object with at least one data type relation
  2. Event Listener that listens to event pimcore.dataobject.postAdd
  3. Inside event listener additional save call on target element in event

What happens is that if we have event listener pimcore.dataobject.postAdd or pimcore.dataobject.postUpdate and inside that function we have to call additional save in that case all relations inside of that object would get duplicate.

This happens because of the calculation of the delta determines that there is no records for relation id db, introduced here: 5a91072

Although there is noting wrong with the delta calculation itself, the problem is that state of relations has been temporary cached inside __rawRelationData. Now Concrete class itself has $this->__rawRelationData = null but it happens too late, as event for post add/post update is dispatched earlier and therefore any additional calls to save inside listeners will duplicate relations.

To correct this late call i moved $this->__rawRelationData = null into parent class AbstractObject as well as full variable there. With this change there is no duplication of relations data.

Copy link

Review Checklist

  • Target branch (11.3 for bug fixes, others 11.x)
  • Tests (if it's testable code, there should be a test for it - get help)
  • Docs (every functionality needs to be documented, see here)
  • Migration incl. install.sql (e.g. if the database schema changes, ...)
  • Upgrade notes (deprecations, important information, migration hints, ...)
  • Label
  • Milestone

Copy link

@ghost ghost added the Pimcore:ToDo label Jul 26, 2024
@fashxp
Copy link
Member

fashxp commented Jul 26, 2024

@dpfaffenbauer any thoughts on this?

@kingjia90
Copy link
Contributor

kingjia90 commented Aug 27, 2024

looks like a follow up of #16596 , just linking it for code documentation purposes

@mcop1 mcop1 self-assigned this Aug 28, 2024
@mcop1
Copy link
Contributor

mcop1 commented Aug 29, 2024

Hello @cuca24 , there is also a getter for the property you moved. What do you think about moving it to the abstract class too?

@cuca24
Copy link
Contributor Author

cuca24 commented Sep 2, 2024

Agree, I moved it to abstract class.

@mcop1
Copy link
Contributor

mcop1 commented Sep 13, 2024

@cuca24 Thank you! One last thing, could you please take a look at the merge conflict and tag me after it was resolved? Will merge it then.

@cuca24 cuca24 force-pushed the fix-duplicate-relations-on-event-liseners-save branch from 211ded6 to ebf162b Compare September 13, 2024 22:04
cuca24 and others added 2 commits September 13, 2024 22:05
@cuca24
Copy link
Contributor Author

cuca24 commented Sep 13, 2024

Thanks @mcop1 done.

@mattamon
Copy link
Contributor

Thanks @mcop1 done.

Hey @cuca24 can you recheck again for the failing tests? Seems like the getClassId is not available everywhere.

@cuca24
Copy link
Contributor Author

cuca24 commented Sep 24, 2024

Hey @mattamon Thanks

So yes $this->getClassId() doesn't exist in AbstractObject it will be populated later in child Concrete class.

@mattamon or anybody else i need your advice how to pull out classId. I could just make a protected variable classId in AbstractObject and use it, other methods as i can see is to store variable in Dao object and read it from there. What would be preferred pimcore's way of doing it.

@oriiyx
Copy link

oriiyx commented Sep 25, 2024

Is there any known workaround for now? 🤔

@kingjia90 kingjia90 changed the base branch from 11.3 to 11.4 October 1, 2024 08:54
@mattamon
Copy link
Contributor

mattamon commented Oct 2, 2024

Hey @mattamon Thanks

So yes $this->getClassId() doesn't exist in AbstractObject it will be populated later in child Concrete class.

@mattamon or anybody else i need your advice how to pull out classId. I could just make a protected variable classId in AbstractObject and use it, other methods as i can see is to store variable in Dao object and read it from there. What would be preferred pimcore's way of doing it.

Hey @cuca24 sorry I was on vacation.

For the static error to go away, we need to define the class in the abstract.
The preferred way would be to define the classId method as an abstract method. Guess there is no need to define a property classid.

WDYT?

@cuca24
Copy link
Contributor Author

cuca24 commented Oct 6, 2024

Hey @mattamon

For the static error to go away, we need to define the class in the abstract.
The preferred way would be to define the classId method as an abstract method. Guess there is no need to define a property classid.

You mean to add abstract function getClassId(): ?string; into AbstractObject?
If so than DataObject class must also be declared as abstract, but this cannot happen as DataObject is instantiated
For example in Pimcore\Model\Element\Service DataObject::getByPath($path) and in other occasions too.

@mattamon
Copy link
Contributor

mattamon commented Oct 7, 2024

Hey @mattamon

For the static error to go away, we need to define the class in the abstract.
The preferred way would be to define the classId method as an abstract method. Guess there is no need to define a property classid.

You mean to add abstract function getClassId(): ?string; into AbstractObject? If so than DataObject class must also be declared as abstract, but this cannot happen as DataObject is instantiated For example in Pimcore\Model\Element\Service DataObject::getByPath($path) and in other occasions too.

I just checked and yes you are right sorry. This is a conundrum that the DataObject is another layer inbetween the concret and the abstract.

Either we would need to make it abstract or implement the getClassId in the DataObject. The first option is not possible and the second is not ideal.

Let's go for the protected variable then and implement the function in the abstract please.

@dpfaffenbauer
Copy link
Contributor

@fashxp sorry, I did not see that you pinged me here. What confuses me, that the issue itself also happens on Pimcore 10, so pre delta calculations for relations.


public function getClassId(): ?string
{
if (isset($this->classId)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cuca24 thank you for moving the method and the property. I am thinking about also improving the method itself.
Since the setClassId has now a string parameter, we could remove the string cast from the getter. Also we do not need the isset anymore right? Since classId always exists and it returns null anyways if the setter is not called.
WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattamon You are totally right. PR updated :)

Copy link
Contributor

@mattamon mattamon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me now!
Thanks for your effort!

Copy link

@mcop1 mcop1 merged commit d8da787 into pimcore:11.4 Oct 18, 2024
19 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Oct 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: DataObjects onPostAdd Event Listener makes duplicate Object Relation
8 participants