programming, if persistence and entities are kept perfectly seperated.
## What are Entities?
Entities are leightweight PHP Objects that don't need to extend any abstract base class or interface.
An entity class must not be final or contain final methods. Additionally it must not implement __clone
nor __wakeup or [do so safely](http://www.doctrine-project.org/documentation/cookbook/2_0/en/implementing-wakeup-or-clone).
An entity contains persistable properties. A persistable property is an instance variable of the entity
that contains the data which is persisted and retrieved by Doctrine's data mapping capabilities.
## An Example Model: Bug Tracker
For this Getting Started Guide for Doctrine we will implement the Bug Tracker domain model from the [Zend_Db_Table](http://framework.zend.com/manual/en/zend.db.table.html)
* A Bugs has a description, creation date, status, reporter and engineer
* A bug can occour on different products (platforms)
* Products have a name.
* Bug Reporter and Engineers are both Users of the System.
* A user can create new bugs.
* The assigned engineer can close a bug.
* A user can see all his reported or assigned bugs.
* Bugs can be paginated through a list-view.
> **WARNING**
>
> This tutorial is incrementally building up your Doctrine 2 knowledge and even lets you make some mistakes, to
> show some common pitfalls in mapping Entities to a database. Don't blindly copy-paste the examples here, it
> is not production ready without the additional comments and knowledge this tutorial teaches.
## A first prototype
A first simplified design for this domain model might look like the following set of classes:
[php]
class Bug
{
public $id;
public $description;
public $created;
public $status;
public $products = array();
public $reporter;
public $engineer;
}
class Product
{
public $id;
public $name;
}
class User
{
public $id;
public $name;
public $reportedBugs = array();
public $assignedBugs = array();
}
> **WARNING**
>
> This is only a prototype, please don't use public properties with Doctrine 2 at all,
> the "Queries for Application Use-Cases" section shows you why. In combination with proxies
> public properties can make up for pretty nasty bugs.
Because we will focus on the mapping aspect, no effort is being made to encapsulate the business logic in this example.
All peristable properties are public in visibility. We will soon see that this is not the best solution in combination
with Doctrine 2, one restriction that actually forces you to encapsulate your properties. For persistence Doctrine 2
actually uses Reflection to access the values in all your entities properties.
Many of the fields are single scalar values, for example the 3 ID fields of the entities, their names, description,
status and change dates. Doctrine 2 can easily handle these single values as can any other ORM. From a point of our
domain model they are ready to be used right now and we will see at a later stage how they are mapped to the database.
There are also several references between objects in this domain model, whose semantics are discussed case by case at this point
to explain how Doctrine handles them. In general each OneToOne or ManyToOne Relation in the Database is replaced by an
instance of the related object in the domain model. Each OneToMany or ManyToMany Relation is replaced by a collection
of instances in the domain model.
If you think this through carefully you realize Doctrine 2 will load up the complete database in memory if you access
one object. However by default Doctrine generates Lazy Load proxies of entities or collections of all the relations
that haven't been explicitly retrieved from the database yet.
To be able to use lazyload with collections, simple PHP arrays have to be replaced by a generic collection
interface Doctrine\Common\Collections\Collection which tries to act as array as much as possible using ArrayAccess,
IteratorAggregate and Countable interfaces. The class \Doctrine\Common\Collections\ArrayCollection is the most simple
implementation of this interface.
Now that we know this, we have to clear up our domain model to cope with the assumptions about related collections:
[php]
use Doctrine\Common\Collections\ArrayCollection;
class Bug
{
public $products = null;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
class User
{
public $reportedBugs = null;
public $assignedBugs = null;
public function __construct()
{
$this->reportedBugs = new ArrayCollection();
$this->assignedBugs = new ArrayCollection();
}
}
Whenever an entity is recreated from the database, an Collection implementation of the type
Doctrine\ORM\PersistantCollection is injected into your entity instead of an array. Compared
to the ArrayCollection this implementation helps the Doctrine ORM understand the changes that
have happend to the collection which are noteworthy for persistence.
> **Warning**
> Lazy load proxies always contain an instance of Doctrine's EntityManager and all its dependencies. Therefore a var_dump()
> will possibly dump a very large recursive structure which is impossible to render and read. You have to use
> `Doctrine\Common\Util\Debug::dump()` to restrict the dumping to a human readable level. Additionally you should be aware
> that dumping the EntityManager to a Browser may take several minutes, and the Debug::dump() method just ignores any
> occurences of it in Proxy instances.
Because we only work with collections for the references we must be careful to implement a bidirectional reference in
the domain model. The concept of owning or inverse side of a relation is central to this notion and should always
be kept in mind. The following assumptions are made about relations and have to be followed to be able to work with Doctrine 2.
These assumptions are not unique to Doctrine 2 but are best practices in handling database relations and Object-Relational Mapping.
* Changes to Collections are saved or updated, when the entity on the *ownin*g side of the collection is saved or updated.
* Saving an Entity at the inverse side of a relation never triggers a persist operation to changes to the collection.
* In a one-to-one relation the entity holding the foreign key of the related entity on its own database table is *always* the owning side of the relation.
* In a many-to-many relation, both sides can be the owning side of the relation. However in a bi-directional many-tomany relation only one is allowed to be.
* In a many-to-one relation the Many-side is the owning side by default, because it holds the foreign key.
* The OneToMany side of a relation is inverse by default, since the foreign key is saved on the Many side. A OneToMany relation can only be the owning side, if its implemented using a ManyToMany relation with join table and restricting the one side to allow only UNIQUE values per database constraint.
> **Important**
>
> Consistency of bi-directional references on the inverse side of a relation have to be managed in userland application code.
> Doctrine cannot magically update your collections to be consistent.
In the case of Users and Bugs we have references back and forth to the assigned and reported bugs from a user,
making this relation bi-directional. We have to change the code to ensure consistency of the bi-directional reference:
[php]
class Bug
{
protected $engineer;
protected $reporter;
public function setEngineer($engineer)
{
$engineer->assignedToBug($this);
$this->engineer = $engineer;
}
public function setReporter($reporter)
{
$reporter->addReportedBug($this);
$this->reporter = $reporter;
}
public function getEngineer()
{
return $this->engineer;
}
public function getReporter()
{
return $this->reporter;
}
}
class User
{
public function addReportedBug($bug)
{
$this->reportedBugs[] = $bug;
}
public function assignedToBug($bug)
{
$this->assignedBugs[] = $bug;
}
}
I chose to name the inverse methods in past-tense, which should indicate that the actual assigning has already taken
place and the methods are only used for ensuring consistency of the references. You can see from `User::addReportedBug()`
and `User::assignedToBug()` that using this method in userland alone would not add the Bug to the collection of the owning
side in Bug::$reporter or Bug::$engineer. Using these methods and calling Doctrine for persistence would not update
the collections representation in the database.
Only using `Bug::setEngineer()` or `Bug::setReporter()` correctly saves the relation information. We also set both collection
instance variables to protected, however with PHP 5.3's new features Doctrine is still able to use Reflection to set and get values
from protected and private properties.
The `Bug::$reporter` and `Bug::$engineer` properties are Many-To-One relations, which point to a User. In a normalized
relational model the foreign key is saved on the Bug's table, hence in our object-relation model the Bug is at the owning
side of the relation. You should always make sure that the use-cases of your domain model should drive which side
is an inverse or owning one in your Doctrine mapping. In our example, whenever a new bug is saved or an engineer is assigned
to the bug, we don't want to update the User to persist the reference, but the Bug.
This is the case with the Bug being at the owning side of the relation.
Bugs reference Products by a uni-directional ManyToMany relation in the database that points from from Bugs to Products.
[php]
class Bug
{
protected $products = null; // Set protected for encapsulation
public function assignToProduct($product)
{
$this->products[] = $product;
}
public function getProducts()
{
return $this->products;
}
}
We are now finished with the domain model given the requirements. From the simple model with public properties only
we had to do quite some work to get to a model where we encapsulated the references between the objects to make sure
we don't break its consistent state when using Doctrine.
However up to now the assumptions Doctrine imposed on our business objects have not restricting us much in our domain
modelling capabilities. Actually we would have encapsulated access to all the properties anyways by using
object-oriented best-practices.
## Metadata Mappings for our Entities
Up to now we have only implemented our Entites as Data-Structures without actually telling Doctrine how to persist
them in the database. If perfect in-memory databases would exist, we could now finish the application using these entities
by implementing code to fullfil all the requirements. However the world isn't perfect and we have to persist our
entities in some storage to make sure we don't loose their state. Doctrine currently serves Relational Database Management Systems.
In the future we are thinking to support NoSQL vendors like CouchDb or MongoDb, however this is still far in the future.
The next step for persistance with Doctrine is to describe the structure of our domain model entities to Doctrine
using a metadata language. The metadata language describes how entities, their properties and references should be
persisted and what constraints should be applied to them.
Metadata for entities are loaded using a `Doctrine\ORM\Mapping\Driver\Driver` implementation and Doctrine 2 already comes
with XML, YAML and Annotations Drivers. In this Getting Started Guide I will use the XML Mapping Driver. I think XML
beats YAML because of schema validation, and my favorite IDE netbeans offers me auto-completion for the XML mapping files
which is awesome to work with and you don't have to look up all the different metadata mapping commands all the time.
Since we haven't namespaced our three entities, we have to implement three mapping files called Bug.dcm.xml,
Product.dcm.xml and User.dcm.xml and put them into a distinct folder for mapping configurations.
The first discussed definition will be for the Product, since it is the most simple one: