Understanding the concepts behind Doctrine
Doctrine ORM implements Data Mapper and Unit of Work design patterns.
The Data Mapper is a layer designed to synchronize data stored in database with their related objects of the domain layer. In other words, it does the following:
Inserts and updates rows in the database from data held by object properties
Deletes rows in the database when related entities are marked for deletion
Hydrates in-memory objects with data retrieved from the database
Note
For more information about the Data Mapper and Unit of Work design patterns, you can refer to the following links: http://martinfowler.com/eaaCatalog/dataMapper.html and http://martinfowler.com/eaaCatalog/unitOfWork.html
In the Doctrine terminology, a Data Mapper is called an Entity Manager. Entities are plain old PHP objects of the domain layer.
Thanks to the Entity Manager, they don't have to be aware that they will be stored in a database. In fact, they don't need to be aware of the existence of the Entity Manager itself. This design pattern allows reusing entity classes regardless of the persistence system.
For performance and data consistency, the Entity Manager does not sync entities with the database each time they are modified. The Unit of Work design pattern is used to keep the states of objects managed by the Data Mapper. Database synchronization happens only when requested by a call to the flush()
method of the Entity Manager and is done in a transaction (if something goes wrong while synchronizing entities to the database, the database will be rolled back to its state prior to the synchronization attempt).
Imagine an entity with a public $name
property. Imagine the following code being executed:
$myEntity->name = 'My name'; $myEntity->name = 'Kévin'; $entityManager->flush($myEntity);
Thanks to the implementation of the Unit of Work design pattern, only one SQL query similar to the following will be issued by Doctrine:
UPDATE MyEntity SET name='Kévin' WHERE id=1312;
Note
The query is similar because, for performance reasons, Doctrine uses prepared statements.
We will finish the theory part with a short overview of the Entity Manager methods and their related entity states.
The following is an extract of a class diagram representing an entity and its Entity Manager:
The
find()
method hydrates and returns an entity of the type passed in the first parameter having the second parameter as an identifier. Data is retrieved from the database through aSELECT
query. The state of this returned entity is managed. It means that when theflush()
method is called, changes made to it will be synced to the database. Thefind()
method is a convenience method that internally uses an entity repository to retrieve data from the database and hydrate the entity. The state of the managed entities can be changed to detached by calling thedetach()
method. Modifications made to the detached entity will not be synced to the database (even when theflush()
method is called) until its state is set back to managed with a call to themerge()
method.Note
The start of Chapter 3, Associations, will be dedicated to entity repositories.
The
persist()
method tells Doctrine to set the state of the entity passed in parameter as managed. This is only useful for entities that have not been synced at least one time to the database (the default state of a newly created object is new) because entities hydrated from existing data automatically have the managed state.The
remove()
method sets the state of the passed in entity to removed. Data related to this entity will be effectively removed from the database with aDELETE
SQL query the next time theflush()
method is called.The
flush()
method syncs data of entities with managed and removed states to the database. Doctrine will issueINSERT
,UPDATE
, andDELETE
SQL queries for the sync. Before that call, all changes are only in-memory and are never synchronized to the database.
Note
Doctrine's Entity Manager has a lot of other useful methods documented on the Doctrine website, http://www.doctrine-project.org/api/orm/2.4/class-Doctrine.ORM.EntityManager.html.
This is abstract for now, but we will understand better how the Entity Manager works with numerous examples throughout the book.