Yesterday I was refactoring some mistakes that my 20 years old me did. As u know in that time I developed tiltbook.com which is basically poker social network very similar to facebook.
What was the problem?
- it was ugly
- it was about to get slow
- it was hard to maintain on php side when adding new features
As on facebook, the website is about posting statuses. On tiltbook you can also have groups, challenges and possibility to write blogs which is basically a status with some additional fields like title, slug, preview etc. Additional fields and more.
What my 20 years old me did?
I had one big Status entity.
As you can notice in case the status was posted inside of a group or challenge etc I marked it with a groupId, challengeId etc. (Holy shit there is no single naming convention :’()
The query was basically selecting statuses for newsfeed based on userId, groupId as u can see:
(reading this code makes me kind of angry but that’s not the point right now)
So… I was thinking how could I make this better and was testing few different approaches according to my needs. I asked for an opinion of my friend Moein. He suggested to treat a group as an user and that I google about Class Table Inheritance… so I studied the topic.
Class Table Inheritance
Doctrine2 offers a really interesting concept. Be sure to checkout documentation first, in case u have any questions, is not so bad actually.
Keep in mind, every project is different and requires a different design. In my situation I need to have a way to select last xy status ids in the most efficient way as possible and afterwards just join the splitted additional informations together based on the status type.
Instead of having one huge entity I went for abstract UserStatus.php entity that will serve as a source table to query.
As documentation explains:
@DiscriminatorColumn value determines what additional table needs to be joined in order to obtain the right informations.
@DiscriminatorMap specifies this relation. In this case 1 represents Status entity and 2 Article entity.
The class is abstract as it’s suppose to just link informations together and to avoid Doctrine requirement of writing down all hierarchy classes in DiscriminatorMap.
Base entity. Will hold all common fields. Extends UserStatus.
The “blog” version of status. As it’s basically a status with some additional fields on PHP side is represented literally in the exact same way.
Any other type of status will be a separate entity extending it in the same way.
Doctrine migrations generates following DB schema:
The simple beauty of creating a new status
Stored in database as:
And if you think it can’t get even better have a look at this:
Doctrine automatically recognises the status type and converts it into specific entity:
Doctrine is definitely powerful and should be used wisely. As you can see sometimes even a very specific DB schemas can be precisely sketched using doctrine and doctrine migrations. Obviously this was a very simple example and my design will get much much much more complicated but hopefully for illustration purposes it’s sufficient.