Multilingual entities with inheritance? - symfony

I need some multilingual entities in our application and I want to know what are the best practice for that.
Currently it solved with an 1:n relation, because there general information and language specific fields.
Is it possible and a good idea to use entity inheritance for that? So I can change always the general part on an object?
Example (pseudo code)
class Product {
public $id;
public $status;
}
class ProductDetails extends Product {
public $language;
public $name;
public $description;
}
I hope my explanation helps a bit to make clear what I need.

I think it's not a good idae, because inheritance is meant to be static. As soon as you want a new locale, you will have to add a new inheritance element in your map. As a contrary, a 1:n relation is good, as it grows without any modification. Moreover, adding a field with a single table inheritance means ading a field for every entity in this table.
Better to use oneToMany :)

Related

Doctrine: Allow extending STI entities from within 3rd party code

Background
I've got an entity A with single table inheritance set up and class Foo extending it like so:
/**
* #ORM\Entity()
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap(
* "foo" = Foo
* )
*/
abstract class A
{
// ...
}
/**
* #ORM\Entity()
*/
class Foo extends A
{
// ...
}
This works with no problems. However, I need to be able to let 3rd party code extend A as well. Problem: I don't know the discriminator mappings that would be needed to wire this up beforehand as this is a property of the base class.
My current solution
I'm in Symfony land, so I can make use of the dependency injection container and decorate the annotation_reader* (that processes the discriminator map class annotations) with my own one.
This reader delegates most of the calls to the original one but can extend found discriminator map annotations. It does so based on an 'extension registry' which itself is filled by a compiler pass looking for a special service tag. Anyone wanting to extend the core entity A with Bar can now tag Bar with this service tag (that also includes the identifier for the mapping; the column type in this example).
*) this will probably also work within the loadClassMetadata event - which would be preferable instead of decorating the reader
/**
* #ORM\Entity()
* #DiscriminatorMapExtension("bar")
*/
class Bar extends A
{
// ...
}
(I'm using service annotations in the above example to be able to write the tags directly beneath the entity annotation. But how exactly the classes will be registered in the end doesn't matter right now. I'm more interested in the general concept.)
So if it's working, what's the problem?
I'd really love to hear some feedback from experienced Doctrine devs on this approach, especially:
Is there a better way to achieve a 'shared entity' across bundles?
Why could this pattern be a problem?
Thanks a lot in advance!

Polymorphic attachments using a subset of the polymorphic relationship in doctrine 2

I need some help with doctrine 2 that uses "polymorphic associations". Let me clarify myself. Entitys can support file attachments using a subset of the polymorphic relationship. the File entity is used to safekeep this relationship where reference to the files are stored as records in the files table and have a polymorphic relation to the parent model. I want to create the same functionality as https://octobercms.com/docs/database/attachments
But do not know how to make the relationship, and how, for example, put the attachment_type dynamic like attachment_id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToOne(targetEntity="App\Domain\FileAttachment\Entity\FileAttachment", attachment_type="news_thumbnail")
*/
private $thumbnail;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToOne(targetEntity="App\Domain\FileAttachment\Entity\FileAttachment", attachment_type="news_image")
*/
private $image;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="App\Domain\FileAttachment\Entity\FileAttachment", attachment_type="news_files")
*/
private $files;
An example of the files table.
I have some experience in trying to make polymorphism work (including polymorphic files) in symfony and by this time I think I can share a few of my insights with you in hopes that they would provide you with some useful information about this subject.
Firstly, I would suggest reading up on inheritance mapping in doctrine link. With doctrine inheritance mapping you would simply create one main File class and then make every other attachment extend it. Then, say you want to add a picture attachment to the user. You would simply create a oneToOne relationship between the user and the main File class. If the attachment you persist would be an instance of one of the attachment classes, Doctrine is smart enough to return you an object of that class, not the main File class.
So to answer you question, I will give you a specific example. Case:
ImageAttachment extends FileAttachment
User has a property called photo
Property photo is a OneToOne relationship to the FileAttachment entity
Code:
$image = new ImageAttachment();
$user->setPhoto($image);
$em->persist($user);
$em->flush();
Result:
Now in the database in the User table, in a column called something like photo_id the referenced ID would be the one in the FileAttachment table. When you would do $user->getPhoto(); it would return an object of class ImageAttachment since doctrine knows that you have persisted an ImageAttachment, not just a FileAttachment.
When it comes to collections, things would also be pretty simple. In this case, you would probably need to create an ManyToMany relationship between the file and the entity that you want to relate to the file. Say that a user can have many different types of attachments saved in the database. If you want to use this filesystem application wide it would probably make no sense for a file to know about the user it belongs to, because soon file would have to hold information on all different types of the relationships and that is just not a smart architecture choice if you want to have any type of modular system in place. Thats why my suggestion is to use ManyToMany relationships between some entity and the attachments. This way only user would know about the files in the database and filesystem would be agnostic and decoupled.
A third important point to be made when talking about polymorphism in doctrine is symfony support for this feature. Generally polymorphism is considered to be somewhat of a bad practice in certain cases, and especially in data persistence does not have much support in the community. So an important thing to consider is that symfony CollectionType HAS NO SUPPORT FOR POLYMORPHISM what so ever. Basically you will have to write your own Type if you were planning on using polymorphic form collections. But if you don't mind using a bit of ajax, this is not really a problem, you can simply avoid using SF forms for this purpose alone.

How to map entity associations with doctrine 2 to retrieve specific data?

Introduction:
The title of the question is a bit generic because I was not able to make a more specific one, but now I will try to give a better description of my problem.
It's my first big project with Symfony (>=3.*) and Doctrine ORM (>=2.5) and I hope to get some tips about what to keep in mind to improve my understanding about modelling entity associations.
Minimized Use Case (ps: CodeStyled words are Doctrine Entities):
I have the AccountType entity where are defined 4 account types.
A User can register his credentials and must choose one AccountType.
I have 5 profile types in the relative entities ProfileOne, ProfileTwo, ProfileThree, ProfileFour, ProfileFive.
The User with AccountType:A can create only 1 ProfileOne and only 1 ProfileTwo.
The User with AccountType:B can create unlimited ProfileOne and ProfileTwo.
The User with AccountType:C can create unlimited ProfileFour.
The User with AccountType:D can create only 1 ProfileFive.
Actual Entity Associations:
User have a unidirectional OneToOne with AccountType.
The Question (UPDATED):
I'm forced to manage the logic outside (es: in a repository) or exist a way to map entities to retrieve the right data based on the AccountType (as showed in the use-case)?
Maybe I've to create a ProfileAccountA, ProfileAccountB, ProfileAccountC and a ProfileAccountD, where to store the relative associations based on the AccountType to then be able to have something like $profile = $user->getProfile() where inside the function getProfile() I manage the logic to returns the right data (like in a Factory class)? If Yes, is this a common and valid approach or there are better alternatives for this use-case?
Create a class for each account type (eg.: AccountTypeA, AccountTypeB, etc.). The properties, associations, and rules that tell which and how many profiles a User can have should be encapsulated in those classes.
Your associations will look like this: User has an (oneToOne) Account that has one or more (oneToMany) Profile
You will probably want an AccountInterface:
interface AccountInterface
{
public function getProfiles(): Collection;
}
An example of an Account class. It's better naming them accordingly to their nature (FreeAccount, MasterAccount...):
class MasterAccount implements AccountInterface
{
private $masterProfile;
private $expirationDate;
private $anotherAccountRelatedProperty;
public function getProfiles(): Collection
{
return new ArrayCollection([$this->masterProfile]);
}
}
Any property, association, or behavior related to the account should live in these classes.
In order to get the User profiles it should delegate to the account:
//User class
private $account;
public function getProfiles(): Collection
{
return $this->account->getProfiles();
}
This is a decent OOP approach to be used as guideline in your situation.

Symfony2 which doctrine relationship for blog between posts and comments

I am building a blog with symfony2 and I am wondering which doctrine relation mapping should be used for the comments. The thing is that I would like to use the comments in different parts, like commenting on pictures (which are not posts) or commenting on comments. So I need my comment entity to be independent of the post.
I wanted to try the OneToMany unidirectionnal but it forces a unique key on the post which is not great.
Thanks for your help
Simple way
The simplest way would be to create a OneToMany relationship for each linked entity. It's quite ugly and maybe is not effective when searching entities, but it works.
The mapping would be similar to this:
class Comment
{
/**
* #ORM\ManyToOne(targetEntity="Post")
* #ORM\JoinColumn(nullable=true)
**/
protected $post;
/**
* #ORM\ManyToOne(targetEntity="Picture")
* #ORM\JoinColumn(nullable=true)
**/
protected $picture;
/**
* #ORM\ManyToOne(targetEntity="Comment")
* #ORM\JoinColumn(nullable=true)
**/
protected $comment;
}
You'll have to handle security by yourself to make sure the comment has at least ONE linked element, and searching might be harder, but it's a basic way to do it.
Complex way
The most effective way to do it (but maybe the most complex) would be to create a "discriminant" property and a "element-to-be-commented" property, coupled with a Custom Doctrine hydrator to retrieve all objects at once, but each one being the correct entity.
The "element-to-be-commented" property would then be either a Comment, Picture or Post, and the discriminant would be here to tell which class is linked.
In SQL terms, it means no foreign key between tables, and that the element_id is dependent of the discriminant.
You may want to take a look at Single Table Inheritance. Disclaimer: I don't have direct experience with it, but it's been suggested often as an answer to similar questions.

Use of abstract class in shopping portal

I know that my this question may sound pathetic to you but as a beginner in .NET, it means a lot to me.
I just want to know that how can I utilize the concept of Abstract class, virtual class etc. in my shopping cart website. I have read the tutorial out there on internet and I saw some examples too, but those examples are so general that they dosen't fit into real world scenerio like I am searching for a shopping website. Same questions again and again comes to my mind that why to made a class only to give the declaration of methods and property.
I understand that most of you are Gurus of .NET and have ample knowlesge in it but if you could just help me out in thinking the logic behind this i'll be very greatfull.
If possible, please recommend me nice books for asp.net design patterns, from which I can learn design patterns.
Thanks in advance
Your one stop resource and guide is Head First - OOAD.
alt text http://i36.tinypic.com/8y6luo.jpg
If you can't see why to use them then don't for now. Never use a design pattern just for the sake of it.
As for their purpose however, imagine that you want to allow different types of products, but you never have something that is just a "Product" - it's always something specific like a "Book" or "Car". In that case you can put the common properties in an abstract Product class like this:
public abstract class Product
{
/* Abstract Price allows Car/Book to apply their own category discounts */
public abstract decimal Price { get; }
public string Title { get; }
public void AddReview(int userId, string reviewText)
{
/* Add review */
}
public abstract List<Product> Recommendations(int userId);
}
which your Book and Car classes can then extend.
Here is a good design patterns book with examples in C#.
C# 3.0 Design Patterns
Its not ture that for every desing you have to use Abstarct class or define virtual methods.
Basically virtual keyword is used to modify a method, property, indexer or event declaration, and allow it to be overridden in a derived class, and Abstarct keyword enables you to create classes and class members solely for the purpose of inheritance—to define features of derived, non-abstract classes
In your case you can have an abstract class called CartItem which works as a base class for all the types of items you are supposed to support in you cart. All types of items will inherit the CartItem class. You can’t directely create the instance of CartItem class but you can use this as a reference to achieve the Polymorphism.
You can define some concrete methods/properties like ItemId, ItemName, Price etc in the CartItem class which are common to all the types of items and you can also define some of the methods a virtual for which you have a default implementation but the child classes can override the implementation.

Resources