diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index 2bd9c70f8..fa58d3ff7 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -1,47 +1,48 @@ -Getting Started: Code First -=========================== +Getting Started with Doctrine +============================= -.. note:: *Development Workflows* +This guide covers getting started with the Doctrine ORM. After working +through the guide you should know: - When you :doc:`Code First `, you - start with developing Objects and then map them onto your database. When - you :doc:`Model First `, you are modelling your application using tools (for - example UML) and generate database schema and PHP code from this model. - When you have a :doc:`Database First `, then you already have a database schema - and generate the corresponding PHP code from it. +- How to install and configure Doctrine by connecting it to a database +- Mapping PHP objects to database tables +- Generating a database schema from PHP objects +- Using the ``EntityManager`` to insert, update, delete and find + objects in the database. -Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.0+ that provides -transparent persistence for PHP objects. It uses the Data Mapper pattern at -the heart of this project, aiming for a complete separation of the -domain/business logic from the persistence in a relational database management -system. The benefit of Doctrine for the programmer is the ability to focus -solely on the object-oriented business logic and worry about persistence only -as a secondary task. This doesn't mean persistence is not important to Doctrine -2, however it is our belief that there are considerable benefits for -object-oriented programming if persistence and entities are kept perfectly -separated. +Guide Assumptions +----------------- -Starting with the object-oriented model is called the *Code First* approach to -Doctrine. +This guide is designed for beginners that haven't worked with Doctrine ORM +before. There are some prerequesites for the tutorial that have to be +installed: + +- PHP 5.3.3 or above +- Composer Package Manager (`Install Composer + `_) + +The code of this tutorial is `available on Github `_. .. note:: - The code of this tutorial is `available on Github `_. + This tutorial assumes you work with Doctrine 2.3 and above. + Some of the code will not work with lower versions. -What are Entities? ------------------- +What is Doctrine? +----------------- -Entities are lightweight 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 :doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`. +Doctrine 2 is an `object-relational mapper (ORM) +`_ for PHP 5.3.3+ that +provides transparent persistence for PHP objects. It uses the Data Mapper +pattern at the heart, aiming for a complete separation of your domain/business +logic from the persistence in a relational database management system. -See the :doc:`architecture chapter <../reference/architecture>` for a full list of the restrictions -that your entities need to comply with. - -An entity contains persistable properties. A persistable property -is an instance variable of the entity that is saved into and retrieved from the database -by Doctrine's data mapping capabilities. +The benefit of Doctrine for the programmer is the ability to focus +on the object-oriented business logic and worry about persistence only +as a secondary problem. This doesn't mean persistence is downplayed by Doctrine +2, however it is our belief that there are considerable benefits for +object-oriented programming if persistence and entities are kept +separated. An Example Model: Bug Tracker ----------------------------- @@ -50,8 +51,7 @@ For this Getting Started Guide for Doctrine we will implement the Bug Tracker domain model from the `Zend\_Db\_Table `_ documentation. Reading their documentation we can extract the -requirements to be: - +requirements: - A Bugs has a description, creation date, status, reporter and engineer @@ -118,27 +118,47 @@ A first prototype We start with a simplified design for the bug tracker domain, by creating three classes ``Bug``, ``Product`` and ``User`` and putting them into `entities/Bug.php`, `entities/Product.php` and `entities/User.php` -respectively. +respectively. We want instances of this three classes to be saved +in the database. A class saved into a database with Doctrine is called +entity. Entity classes are part of the domain model of your application. .. code-block:: php `. -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. + An entity contains persistable properties. A persistable property + is an instance variable of the entity that is saved into and retrieved from the database + by Doctrine's data mapping capabilities. -We will soon add references between objects in this domain -model. The semantics are discussed case by case 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. You never have to work with the foreign keys, only -with objects that represent the foreign key through their own identity. +Note how all properties have getter and setter methods defined except +`$id`. To access data from entities Doctrine 2 uses the Reflection API, so it +is possible for Doctrine to access the value of `$id`. You don't have to +take Doctrine into account when designing access to the state of your objects. -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 +All of the properties so far are scalar values, for example the 3 ID +fields of the entities, their names, description, status and change dates. + +With just the scalar values this model is useless. We need to add references +between entities in this domain model. The semantics of each type of reference +are now introduced and discussed on a case by case basis +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. You never have to work with the foreign keys, only with objects that +represent the foreign key through their own identity. + +To prevent Doctrine 2 from loading up the complete database in memory if you +access one object, the Lazy Load pattern is implemented. Proxies of entities or +collections are created 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 for Doctrine which -tries to act as as much like an array as possible by using ArrayAccess, -IteratorAggregate and Countable interfaces. The class 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: +Now that you know the basics about references in Doctrine, we can extend the +domain model to match the requirements: .. code-block:: php @@ -234,7 +259,7 @@ with the assumptions about related collections: { // ... (previous code) - protected $products = null; + protected $products; public function __construct() { @@ -251,8 +276,8 @@ with the assumptions about related collections: { // ... (previous code) - protected $reportedBugs = null; - protected $assignedBugs = null; + protected $reportedBugs; + protected $assignedBugs; public function __construct() { @@ -1161,13 +1186,10 @@ Find by Primary Key The next Use-Case is displaying a Bug by primary key. This could be done using DQL as in the previous example with a where clause, -however there is a convenience method on the Entity Manager that +however there is a convenience method on the ``EntityManager`` that handles loading by primary key, which we have already seen in the write scenarios: -However we will soon see another problem with our entities using -this approach. Try displaying the engineer's name: - .. code-block:: php find("Bug", (int)$theBugId); echo "Bug: ".$bug->getDescription()."\n"; - // Accessing our special public $name property here on purpose: - echo "Engineer: ".$bug->getEngineer()->name."\n"; + echo "Engineer: ".$bug->getEngineer()->getName()."\n"; -The output of the engineers name is null! What is happening? -It worked in the previous example, so it can't be a problem with the persistence code of -Doctrine. What is it then? You walked in the public property trap. +The output of the engineers name is fetched from the database! What is happening? -Since we only retrieved the bug by primary key both the engineer -and reporter are not immediately loaded from the database but are -replaced by LazyLoading proxies. Sample code of this proxy -generated code can be found in the specified Proxy Directory, it -looks like: +Since we only retrieved the bug by primary key both the engineer and reporter +are not immediately loaded from the database but are replaced by LazyLoading +proxies. These proxies will load behind the scenes, when the first method +is called on them. + +Sample code of this proxy generated code can be found in the specified Proxy +Directory, it looks like: .. code-block:: php @@ -1218,26 +1239,9 @@ looks like: } See how upon each method call the proxy is lazily loaded from the -database? Using public properties however we never call a method -and Doctrine has no way to hook into the PHP Engine to detect a -direct access to a public property and trigger the lazy load. We -need to rewrite our entities, make all the properties private or -protected and add getters and setters to get a working example: +database? -.. code-block:: php - - find("Bug", (int)$theBugId); - - echo "Bug: ".$bug->getDescription()."\n"; - echo "Engineer: ".$bug->getEngineer()->getName()."\n"; - -Now prints: +The call prints: :: @@ -1245,10 +1249,6 @@ Now prints: Bug: Something does not work! Engineer: beberlei -Being required to use private or protected properties Doctrine 2 -actually enforces you to encapsulate your objects according to -object-oriented best-practices. - Dashboard of the User ---------------------