Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2/Doctrine2 : Having generic links between objects

I have a modeling issue with Symfony2/Doctrine2. I am currently trying to pass a whole web site from a former PHP framework to Symfony2, and there's a conception in the former framework which I like but which I can't manage to modelize with Symfony and Doctrine.

Here is my issue : with the former framework, it's possible to link an object of a class A to any other object of any other class (B,C,D...). To do this, the class A has an attribute model_id to know which class the object is linked to (it corresponds to a unique id defined in a configuration file for each class), and an attribute record_id which is the external id of the linked object. This way, for example, it's possible to have a class Comment and have a comment about any object (a blog post, a user, etc.).

As these generic links seem impossible to modelize with Doctrine relationships (ManyToOne etc.), I thought about having - like in the former framework - a sort of global method, or a method for each class, called for example getItem, which looks at the attributes model_id and record_id and then return the right object.

But again I had problems :

  • I can't define this method in the Entity directly because I shouldn't have access to the database in the Entity class.

  • If I define it once in a global service, or n times for each class in a repository - which is possible because this time I have access to the database - I will be able to call the method everywhere but in the Entity code. And it makes the implementation pretty ugly because it means that in my previous example all the methods of the Entity which need to have access to the Comments must be moved from the Entity to the Repository. And finally I will have pretty much all my object methods in the Repository rather than in the Entity directly.

Do you have any idea about how I could have a system like this which allows to link generically an object to any other object and then recover easily the linked object just like it was a "usual" Doctrine relationship ?

Thank you very much in advance for your help.

like image 825
Ayom Avatar asked Jan 24 '26 20:01

Ayom


1 Answers

The thing is your solution means we know in advance that the object A is going to be linked to an object B, C, etc. However, what I wanted to implement is a solution where we don't know in advance what are going to be the links and we have the possibility to create a new link between the object A and an object of a newly created class Z without changing anything in the classes A and Z. This way, if I take my previous example, you can properly have a Comment on any Object, without making straight relationships between the class Comment and the other classes.

And I think I found the solution to this problem:

What I've done is implementing a Listener, with the event postLoad which triggers each time an entity is loaded from Doctrine. On the other hand, my entities have for example an attribute $item which is the linked item for which we don't know the class yet. In the postLoad event, we look in the database thanks to model_id and record_id what is the class of the linked item and return the object itself, and then we fill the $item attribute before the entity is returned by Doctrine. This way, each time we get an entity from Doctrine, the "fake" link between the entity and the item is built by the automatic event, and this works for every entity. With the same principle, we can update the link with a postUpdate event which triggers each time we update the entity. It will update manually the "fake" link in the database.

For more information, I recommend to read these pages :

  • http://symfony.com/doc/master/cookbook/doctrine/event_listeners_subscribers.html

  • http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#postload

like image 161
Ayom Avatar answered Jan 27 '26 11:01

Ayom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!