This is an effort to make Symfony2 workflow (bit more) DRY where Entities are mapped with Doctrine ORM.
Such mapped entities sometimes share same attributes between them i.e. id, timestamps etc. In order to use DRY concept here we can create a base entity and then every new entity can extend it to share those attributes. Let’s start by creating two entities with repeated attributes.
An Entity is simply a PHP class.
Here are two Entities User and Address, and they are structured as following:
Here is the Address entity class.
As you can see that we have id, createdAt and updatedAt attributes that are being repeated in both entities. To implement a DRY concept here we are going to create a new entity class that will have the shared/repeated attributes and then can be extended by other entities.
Let’s create a BaseEntity class and move the repeated values to it.
Note a new annotation @ORM\MappedSuperclass at top of the BaseEntity that makes sure that attributes in this entity are properly extended into sub-entities. Now we can remove these attributes from User and Address entities and extend our BaseEntity class into these.
Our entities are already started to look cleaner.
Now since we have some shared attributes in one entity, this gives us flexibility to add further enhancements to it as required.
Let’s add some automation to make sure that both timestamps createdAt and updatedAt are properly set before we persist or update the records to our database. For that we will use @ORM\PrePersist and @ORM\PreUpdate annotations in custom methods. We also need an additional annotation @ORM\HasLifecycleCallbacks at class root level.
Now we have two additional custom methods, setTimestamps and setUpdatedTimestamp. The names for these methods do not really matter so we can name those as we want. First method sets the values for createdAt and updatedAt attributes just before we persist a new record to database. We set the values as DateTime object and Symfony2/Doctrine will automatically convert those to required format for database entry. Second method only updates the updatedAt value when a database record is updated.
We can simply extend the BaseEntity to any entity and need not worry about generating a primary key attribute (id) and timestamps now on.
We can have as many as enhancement we like to the BaseEntity and those will be automatically extended to sub-entities. For example we can have a save method to persist the record by keeping all logic in BaseEntity instead of a controller. In current situation if we are creating a user we will use following steps inside a controller:
By adding following helper method into our BaseEntity we can shorten it from 3 lines to 1:
Now we can simply use the save method inside our controller:
I hope that this was useful for anyone refactoring their Symfony2 project. Here is the complete BaseEntity class as a Gist. Feel free to suggest any enhancements.