symfony2 - doctrine relationship between entitiy and entities implementing the same interface - php

I cant find any satisfactory solution for the problems which I sometimes meet. For example we have Article, Photo and Comment entities, I want to make Article and Photo commentable. So, there are same approaches:
1. For all entities like Article, Photo make specific enitity like CommentPhoto, CommentArticle. But it makes me crazy when I duplicate the same code...
2. Use mappedSuperClass. But it forces me to extends class like Article - the problem occurs, when i want make Articles for example 'likeable' and I cant do that because i can extend only one class. There are traits which would be helpful but they are available since php5.4.0.
3. So i want to use interface "Commentable" and implement it entities. Then i want to Create entity with relation to this interface. I know there is something like "resolve target entities" (http://symfony.com/doc/master/cookbook/doctrine/resolve_target_entity.html) it allows to configure relationship with interface but this configuration is static (Correct me if I am wrong -> maybe I could configure in config.yml more than one entity for the same interface ?? )
So my question is: Is there any other approach? Or how to use "resolve target entities" to achieve this?
Edit: 4. fourth approach is to add fields 'entity_type', 'entity_id' to Comment, but it is still not clear as I dreamt...

Related

Reusing of entites in symfony or Dynamic mapping of entities

While Working on my project in Symfony, I realized that there is one entity(Assign Item to category) in my project which is being used in all other entities like products,categories,upsells etc as all of them need to be assigned to a category.
Is there a way that this entity can be reused?
I know a way where it can be defined in all ORM's (copy pasted in all entities), but want a more optimal solution to this.
Any help would be appreciated.
After doing a research, here is what I found.
There is a term called dynamic binding in Symphony where one entity can be used into another there by saving us from writing the same code again and again.
Here is the link that helped me:
https://www.theodo.fr/blog/2013/11/dynamic-mapping-in-doctrine-and-symfony-how-to-extend-entities/
Hope that helps someone.
Create a bundle with abstract classes that defines your entities. Don't forget to put there the annotations. Then load that bundle in your projects and extend your entities from these abstract classes. You can override methods or atributtes to customize to the certain usage. FosUserBundle works in that way
FOSUserBundle usage

Doctrine ORM and factories with abstract classes strategy

So I've stumbled upon this hurdle where I have to create an abstract class and a factory to create objects of more specific classes that extend the abstract class and implement more specific object methods.
Simply said, I got a SocialMediaAbstract class. Extending classes are Facebook, Instagram, and they implement a SocialMediaInterface. Facebook, Instagram etc are all saved in the db, with an id, a name and several more properties that are all used among the extending classes, hence an abstract class.
Because I want to be able to query several things from the SocialMedia Objects, and every social media platform have their own APIs for it, I made the interface and created the different classes so they can all have their own implementations of those methods.
Now, the problem is of course with my abstract class and Doctrine. Doctrine says this on their website regarding inheritance:
A mapped superclass cannot be an entity, it is not query-able [...]
Now if I had a SocialMediaFactory and threw in an ID, I would like to get the respective Object of, for example, class Facebook or Instagram back. I don't want to know exactly which SocialMedia it is when I collect them. Now that is a problem with doctrine, at least that's what I think it is.
Am I overlooking something, is the factory pattern still possible? Or should I really just remove the abstract class, and create a factory that searches in every table of a SocialMediaInterface implementing class, which seems highly inefficient and unmaintable when an application gets bigger.
Any insight or pointers would be appreciated, since I'm sure this problem must've come up more often. I tried googling and searching on Stackoverflow itself, but I couldn't get any relevant questions or answers.
Thank you very much in advance.
EDIT:
I came across this interesting possibility: Class Table Inheritance. This would mean adding:
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"facebook" = "Facebook", "instagram" = "Instagram"})
to my code. I had high hopes, but sadly enough the validator gave me this error:
[Doctrine\ORM\Mapping\MappingException]
It is not supported to define inheritance information on a mapped superclas
s 'Portal\SocialMedia\Entity\SocialMediaAbstract'.
A shame mapper superclasses are not supported.
EDIT 2/CONCLUSION:
I've decided to go with Class Table Inheritance (just like the answer below suggested). Removing the abstract from the class made it possible to still use my factory.
I am using a concrete class as an abstract class now however, which feels wrong. I've documented in docblock that no objects should be instantiated from this class.
One little sidenote: Doctrine's Entity Manager more or less already provides the Factory:
$socialMedia = $entityManager->find('Portal\SocialMedia\Entity\SocialMedia', 2);
This returns an Instagram object. I still suggest you build your own factory above it for maintainability later as the SocialMedia entity might change later on.
Some time has passed now since I worked with doctrine, but if I remember correctly, doctrine's mapped super classes are an implementation of the concrete table inheritance pattern by Martin Fowler.
In the example mentioned there, the Player is the mapped super class, whose attributes are distributed to all inheriting entities / models. The point here is that a player can't be instantiated and thus has no own id. Instead, every inheriting model got it's own id, which are all independent of each other.
I think the pattern you are looking for is either single table inheritance or class table inheritance (have a look at doctrine's inheritance types).
Single table inheritance is implemented in doctrine's inheritance type "SINGLE_TABLE", where you have one table for all entities. They are sharing the exact same attributes and same id pool, meaning you can "throw in" an id, get the object and check the type (Facebook, Instagram etc..).
The downside is that if you got in any of the entites an attribute that may be NULL, you could run into problems if the other entites don't have this attribute or don't need it. This would mean you have to set the given attribute to a dummy value in the other entities to save them into the database table.
Class table inheritance overcomes this issue by saving every entity in its own table, while still being able to share the id pool, because doctrine takes care that the common attributes are saved in the base class table, while all the attributes specific to an entity are saved in the entity's table. The tables are then joined by the id, hence the inheritance type "JOINED" in doctrine.
Conclusion:
Use single table inheritance if the classes are very similar and only differ in function definition or implementation, but have the same attributes.
Use class table inheritance if the classes have distinct attributes that would be problematic to store in a single table.
Use concrete table inheritance if the classes are not really related to each other, but only share a small amount of common attributes. But this could also be implemented through PHP's traits, which in my opinion is easier and more flexibly to use than doctrine's mapped super class. In a PHP trait you can also use doctrine's annotations, because the PHP interpreter will properly assign the annotations to the classes you use the traits in.
You should still be able to use your SocialMediaFactory with either single table or class table inheritance pattern.

Laravel project UML Class diagram

I have been googling around for UML examples for MVC PHP Framework as well as a project UML Diagram to do with a PHP project but unfortunately java and c# examples always come up.
I have a small understanding of UML diagrams but not real example to see hwo it is used. I have a laravel project which I am working on and I want to create a UML class diagram to show the class i am using.
In java and PHP i know one of the ways to know if a class is associate with another is when it is getting instantiated in another class with the key word new
what I want to know is in laravel hwo do you know when a model or controller is associate with each other or another. I have asked in one of the community channels and someone told me "it is not really linked" which doesn't answer my question. What I want to know is if i do something like User::where('username', '=', $username)->where('active', '=', 0)->get(); in a controller does this mean that the controller is now associated with the User model or the controller is a dependency of the User model?
e.g.
What I am confusing about is another a UML class diagram will look like for any laravel or PHP MVC application.
Thanks
You can show the relation between both by using a role name at each side of the association. The role name is placed "on the other side" of the association. So if AccountController uses User as currentUser then place the role name currentUser near the User attached association.
An example for the role use is this:
The class diagram will not tell you anything about instantiation itself. Rather you use a sequence diagram to show that. E.g. (without knowing anything about your domain) if AccountController creates a User object it will send a new message which tells that a :User instance has to be created. Termination can be shown by a X at the end of the life line of an object.
And the instances of these classes are used in a SD as follows:
The first message is the new message. The messages below use some of the operations you stated in your classes (no idea if that makes sense). The final X indicates the termination of :User

How to fill a custom object via the repository pattern and Laravel's Eloquent

Okay, so here's the deal. I'm working with a custom CMS, and I'd like for the code to be as optimized as possible. I've been reading/watching tuts/etc. like crazy about the repository pattern in general as well as specifically using it with Laravel's Eloquent. There are probably some really dumb questions/thoughts in here, but bear with me. :-) Sometimes there's no easy way to ask about terminology/best practices without looking silly.
As with many things, there are million ways I could "make it work"; my dilemma is essentially a matter of "best practice."
General Scenario/Question
Let's assume I am trying to get a Page for my CMS from the database. From what I can understand the typical way to set up the repository pattern with Eloquent is to have the following files:
Page.php -- the Eloquent Model
PageRepositoryInterface.php -- the "contract" for what should be in Page repo's
EloquentPageRepository.php -- the Page repository that can grab data via Eloquent
Easy enough. So I might use it this way. Assuming I have a getPageById method in EloquentPageRepository.php, I could just do something like this from my controller:
$page = $this->repo->getPageById();
Now my question arises: what type of data should getPageById() return? Some people recommend setting it up to return an Eloquent collection. Others say just a plain array or generic object.
Ideally I feel like my scenario would best lend itself to having EloquentPageRepository grab the data from Eloquent and actually return an instance of a custom Page class that I have. For example, something along the lines of this:
<?php namespace Acme\Repositories\EloquentPageRepository;
use Acme\...\PageObject as PageObject; // Better name than PageObject?
//...
class EloquentPageRepository implements PageRepositoryInterface {
// Omitting constructor, etc.
public function getPageById($id)
{
// Grab the row via Eloquent (obviously not stored in Page:: at
// this point. I'm just using it here for clarity and time's sake.
$page = Page::find($id);
// Now we have an Eloquent collection stored in $page, but I'd
// like to return the data inside an instance of my custom class.
$pageObj = new PageObject($page->title, $page->body);
return $pageObj;
}
}
To me, this seems good because it gives a consistent delivery format from repo to repo. It also allows me to perform some constructor logic on my pageObject. Finally, it allows me to have some custom methods on the PageObject (that are repository-agnostic).
It's similar to a collection, but I don't think it's exactly that. It's basically just an instance of a class that I'm immediately populating with my database info.
My questions, listed:
Is it considered bad practice to use a repo to stuff eloquent data into a specific object and return it?
I don't want to call my class "PageObject," because that's just lame. I'd way rather call it something like "PageCollection," except for the fact that it's not actually a collection. Is there actually a name for the way that I'm using this class? It's not a collection, it's a ...? I have no idea about this, I'm just searching for any input you have.
It whole depends on what you expect from the repository pattern. Are you using the repository pattern because in the future you're going to swith of data layer and needs a new repository. If you're using Eloquent as long as your cms live then you can return an eloquent object. If you want it very flexible then make a new page object(PageComposer as mentioned in the comments). This is one of the strengts of the repository pattern so I suggest you make a PageComposer class which you instantiate and return by the repository.
Normally you can call it Page because its a page and it ships some information of a page. But that name you've already give to the Eloquent model. You can consider changing the eloquent models name and call your return object Page.

Doctrine2 - relation depending on parameter

I would like to know what is the best way to have an entity with 1:N relation to another entity but additionally depending on a parameter.
For example I have productentity and product_description entity, which depends on product_id and also on language (2 char code). Another examples would be manufacturer and manufacturer_description, category and category_description. There is a lot of it - you got the idea.
I though about extending EntityRepository class and adding automatic join based for example on an annotation. I'm just not sure if this is the "correct way" to do what I want. Can you suggest better solution? Another though was just to have method getDescription($language) in product entity but to me it just doesn't look as best solution, especially because I want to load the language-dependent content in 90% cases with all other information. Getting that content in separate query would just create unnecessary load.
Thank you for your suggestions.
There is a translatable extensions for doctrine. I've never used it but it looks like it might address your use case:
http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html
See also
https://github.com/l3pp4rd/DoctrineExtensions

Categories