About this book

Doctrine 2 has become the most popular modern persistence system for PHP. It can either be used as a standalone system or can be distributed with Symfony 2, and it also integrates very well with popular frameworks. It allows you to easily retrieve PHP object graphs, provides a powerful object-oriented query language called DQL, a database schema generator tool, and supports database migration. It is efficient, abstracts popular DBMS, and supports PHP 5.3 features.

Doctrine is a must-have for modern PHP applications.

Persistence in PHP with Doctrine ORM is a practical, hands-on guide that describes the full creation process of a web application powered by Doctrine. Core features of the ORM are explained in depth and illustrated by useful, explicit, and reusable code samples.

Persistence in PHP with Doctrine ORM explains everything you need to know to get started with Doctrine in a clear and detailed manner.

From installing the ORM through Composer to mastering advanced features such as native queries, this book is a full overview of the power of Doctrine. You will also learn a bunch of mapping annotations, create associations, and generate database schemas from PHP classes. You will also see how to write data fixtures, create custom entity repositories, and issue advanced DQL queries. Finally it will teach you to play with inheritance, write native queries, and use built-in lifecycle events. If you want to use a powerful persistence system for your PHP application, Persistence in PHP with Doctrine ORM is the book you.

Publication date:
December 2013
Publisher
Packt
Pages
114
ISBN
9781782164104

 

Chapter 1. Getting Started with Doctrine 2

The Doctrine project is a collection of libraries providing utilities to ease data persistence in PHP applications. It makes it possible to create complex model layers in no time that will be compatible with popular DBMS, including SQLite, MySQL, and PostgreSQL. To discover and understand Doctrine, we will create a small blog from scratch throughout this book that will mainly use the following Doctrine components:

  • Common provides utilities that are not in the PHP standard library including a class autoloader, an annotations parser, collections structures, and a cache system.

  • Database Abstraction Layer (DBAL) exposes a unique interface to access popular DBMS. Its API is similar to PDO (and PDO is used when possible). The DBAL component is also able to execute the same SQL query on different DBMS by internally rewriting the query to use specific constructs and emulate missing features.

  • Object Relational Mapper (ORM) allows accessing and managing relational database tables and rows through an object-oriented API. Thanks to it, we will directly manipulate PHP objects, and it will transparently generate SQL queries to populate, persist, update, and delete them. It is built on top of DBAL and will be the main topic of this book.

Note

For more information on PHP Data Objects and the data-access abstraction layer provided by PHP, refer to the following link: http://php.net/manual/en/book.pdo.php

To learn Doctrine, we will build together a tiny blog engine with advanced features such as the following:

  • Posts list, creation, editing, and deletion

  • Comments

  • Tag filtering

  • Profiles for author of posts and comments

  • Statistics

  • Data fixtures

The following is a screenshot of the blog:

In this chapter, we will learn about the following topics:

  • Understanding concepts behind Doctrine

  • Creating the project's structure

  • Installing Composer

  • Installing Doctrine ORM, DBAL, and Common through Compose

  • Bootstrapping the app

  • Using Doctrine's Entity Manager

  • Configuring Doctrine command-line tools

 

Prerequisites


To follow this tutorial, we need a proper CLI installation of PHP 5.4 or superior. We will also use the curl command to download the Composer archive and the SQLite 3 client.

Note

For further information about PHP CLI, curl, and SQLite, refer to the following links: http://www.php.net/manual/en/features.commandline.php, http://curl.haxx.se, and http://www.sqlite.org

In the examples, we will use the PHP built-in web server and SQLite as DBMS. Doctrine is a pure PHP library. It is compatible with any web server supporting PHP, but is not limited to Apache and Nginx. Of course, it can also be used in applications that are not intended to run on web servers, such as command-line tools. On the database side, SQLite, MySQL, PostgreSQL, Oracle, and Microsoft SQL Server are officially supported.

Thanks to the DBAL component, our blog should work fine with all these DBMS. It has been tested with SQLite and MySQL.

The Doctrine project also provides Object Document Mappers (ODM) for NoSQL databases including MongoDB, CouchDB, PHPCR, and OrientDB. These topics are not covered in this book.

Note

Do not hesitate to consult the Doctrine documentation specified in the following link while reading this book: http://www.doctrine-project.org

 

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 a SELECT query. The state of this returned entity is managed. It means that when the flush() method is called, changes made to it will be synced to the database. The find() 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 the detach() method. Modifications made to the detached entity will not be synced to the database (even when the flush() method is called) until its state is set back to managed with a call to the merge() 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 a DELETE SQL query the next time the flush() method is called.

  • The flush() method syncs data of entities with managed and removed states to the database. Doctrine will issue INSERT, UPDATE, and DELETE 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.

 

Creating a project structure


The following is the folder structure of our app:

  • blog/: App root created earlier

  • bin/: Specific command line tools of our blog app

  • config/: Configuration files of our app

  • data/: The SQLite database will be stored here

  • src/: All PHP classes we write will be here

  • vendor/: This is where Composer (see the following section) stores all downloaded dependencies including the source code of Doctrine

  • bin/: This is a command-line tool provided by dependencies installed with Composer

  • web/: This is the public directory that contains PHP pages and assets such as images, CSS, and JavaScript files

We must create all these directories except the vendor/ one that will be automatically generated later.

 

Installing Composer


As with most modern PHP libraries, Doctrine is available through Composer, a powerful dependency manager. A PEAR channel is also available.

Note

For more information on Composer and Pear packages, please refer to the respective links as follows: http://getcomposer.org and http://pear.doctrine-project.org

The following steps should be performed to install Composer:

  1. The first step to install Doctrine ORM is to grab a copy of the latest Composer version.

  2. Open your preferred terminal, go to the blog/ directory (the root of our project), and type the following command to install Composer:

      curl -sS https://getcomposer.org/installer | php
    

    A new file called composer.phar has been downloaded in the directory. This is a self-contained archive of Composer.

  3. Now type the following command:

      php composer.phar
    

    If everything is OK, all available commands are listed. Your Composer installation is up and running!

 

Installing Doctrine


The following steps should be performed to install Doctrine:

  1. To install Doctrine, we need to create a file called composer.json in our new blog directory. It lists dependencies of our project as shown in the following code:

    {
        "name": "myname/blog",
        "type": "project",
        "description": "My small blog to play with Doctrine",
    
        "require": {
            "doctrine/orm": "2.4.*"
        },
    
        "autoload": {
            "psr-0": { "": "src/" }
        }
    } 

    This standard JSON file will be parsed by Composer to download and install all dependencies specified. Once installed, Composer will load all classes of these libraries automatically.

    The name, type, and description attributes are optional but it's a good practice to always fill them. They provide general information about the project we are working on.

    The more interesting part of this composer.json file is the require field. In order to get it installed by Composer, all libraries used by our app must be listed here. A lot of PHP libraries are available on Packagist, the default Composer package repository. Of course, it's the case of Doctrine projects.

    Note

    For more information on Packagist, go through the following link: https://packagist.org/

    We indicate that we need the latest minor release of the 2.4 branch of Doctrine ORM. You can set a major or minor version here, and even more complicated things.

    Note

    For more information on a package version, you can refer to the following link: http://getcomposer.org/doc/01-basic-usage.md#package-versions

    The autoload field is here to tell Composer to automatically load classes of our app. We will put our specific code in a directory called src/. Our files and classes will follow the PSR-0 namespacing and file-naming standard.

    Note

    PHP Specification Requests are attempts to improve interoperability of PHP applications and libraries. They are available at http://www.php-fig.org/.

  2. It's time to use Composer to install the ORM. Run the following command:

        php composer.phar install
    

    New files appear in the vendor/ directory. Doctrine ORM has been installed, and Composer was smart enough to get all its dependencies, including Doctrine DBAL and Doctrine Common.

    A composer.lock file has also been created. It contains exact versions of installed libraries. This is useful for deploying applications. Thanks to this file, when running the install command, Composer will be able to retrieve the same versions that have been used in the development.

    Doctrine is now properly installed. Easy, isn't it?

  3. To update libraries when there are new releases in the 2.4 branch, we just need to type the following command:

        php composer.phar update
    
 

Bootstrapping the app


The following steps need to be performed for bootstrapping the app:

  1. Create a new file called config/config.php that will contain configuration parameters of our app as shown in the following code:

      <?php
    
      // App configuration
      $dbParams = [
        'driver' => 'pdo_sqlite',
        'path' => __DIR__.'/../data/blog.db'
      ];
    
      // Dev mode?
      $dev = true;

    The Doctrine configuration parameters are stored in the $dbParams array. We will use a SQLite Database called blog.db stored in the data/ directory. If you want to use MySQL or any other DBMS, it's here that you will configure the driver to use, the database name, and the access credentials.

    Note

    The following is a sample configuration to use MySQL instead of SQLite:

    $dbParams = [
        'driver' => 'pdo_mysql',
        'host' => '127.0.0.1',
        'dbname' => 'blog',
        'user' => 'root',
        'password' => ''
    ];

    Config keys are self-explanatory.

    If the $dev variable is true, some optimizations will be disabled to ease debugging. Disabling the dev mode allows Doctrine to put a lot of data such as metadata in powerful caches to increase overall performances of the app.

    Note

    It requires cache driver installation and extra configuration, which is available at http://docs.doctrine-project.org/en/latest/reference/caching.html.

  2. Next, we need a way to bootstrap our app. Create a file called bootstrap.php in the src/ directory. This file will load everything we need as given in the following code:

      <?php
    
      require_once __DIR__.'/../vendor/autoload.php';
      require_once __DIR__.'/../config/config.php';

    The first line requires the Composer autoloader. It allows you to automatically load the Doctrine's classes, the project's classes (that will be in the src/ directory), and any class of a library installed with Composer.

    The second line imports the configuration file of the app. The project structure is created and the initialization process of the app is done. We are ready to start using Doctrine.

 

Using Doctrine's Entity Manager


The principle of an ORM is to manage data stored in a relational database through an object-oriented API. We learned about its underlying concepts earlier in this chapter.

Each entity class is mapped to the related database table. Properties of the entity class are mapped to the table's columns.

So, the rows of a database table are represented in the PHP app by a collection of entities.

Doctrine ORM is able to retrieve data from the database and to populate entities with them. This process is called hydration.

Note

Instead of entities, Doctrine can populate PHP arrays in different manners (with the object graph, with a rectangular result set, and so on). It is also possible to create custom hydrators by referring to the following link: http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html#hydration-modes

As we have learned with the Data Mapper design pattern, it also does the inverse job: it persists data held by entities to database.

We will play a lot with entities later.

Doctrine comes with the following files to map entities to tables:

  • Annotations in comment blocks that embed directly in the entities

  • XML configuration files

  • YAML configuration files

  • Plain PHP files

Annotations are fairly recent in the PHP world (they are popular in Java) but they are already widely used by Doctrine and Symfony communities. The advantages of this method are great readability and maintenance facility because mapping information is next to the PHP code. Putting mapping information directly in the code can also be a drawback in some contexts, especially for big projects that use several persistence systems.

We will use the annotation method in this book, but other methods are described in the Doctrine documentation. We will return to them in Chapter 2, Entities and Mapping Information.

In the next chapter, Chapter 2, Entities and Mapping Information, we will discover that Doctrine is smart enough to use mapping information to automatically create the related database schema.

For now, we will focus on retrieving an Entity Manager. As entities are retrieved, persisted, updated, and removed through it, this is the entry point of Doctrine ORM.

Edit the src/bootstrap.php file to retrieve a Doctrine's Entity Manager. Add the following code at the end of this file:

  $entitiesPath = array(__DIR__.'/Blog/Entity');
  $config = Setup::createAnnotationMetadataConfiguration    ($entitiesPath, $dev);
  $entityManager = EntityManager::create($dbParams, $config);

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

The $entitiesPath property contains the list of paths to directories storing entity classes. We already mentioned that our app will follow the PSR-0 namespacing convention. The \Blog folder will be the root namespace and entity classes will be in the \Blog\Entity folder.

A Doctrine configuration is created to use annotations for mapping information and to be able to locate the blog's entities that we'll create.

A new EntityManager is created and configured to use our database and Doctrine settings.

For simplicity, we create a unique Entity Manager that will be used across the application. For real-world apps, you should take a look at the Dependency Injection design pattern.

Note

Find more on Dependency Injection pattern at the following link: http://en.wikipedia.org/wiki/Dependency_injection

 

Configuring Doctrine command-line tools


The Doctrine library is bundled with some useful command line tools. They provide many helpful features, including, but not limited to the ability to create database schema from entity mappings.

Composer has installed Doctrine's command line tools in the vendor/bin/ directory. But before being able to use them, a bit of configuration must be done. Command line tools internally use an Entity Manager. We need to tell them how to retrieve it.

Here, we just need to create one more file called cli-config.php in the config/ directory as follows:

  <?php

// Doctrine CLI configuration file

use Doctrine\ORM\Tools\Console\ConsoleRunner;

require_once __DIR__.'/../src/bootstrap.php';

return ConsoleRunner::createHelperSet($entityManager);

Thanks to the Doctrine's conventions, the file will be automatically detected and used by the Doctrine CLI.

Note

Command line tools will look for a file called cli-config.php in the current directory and in the config/ directory.

This file just gets a new Entity Manager using the utility class we've created earlier and configures the Doctrine CLI to use it.

Type the following command to get a list of available Doctrine commands:

  php vendor/bin/doctrine.php
 

Summary


In this chapter, we discovered the fundamentals of Doctrine. We now know what entities and Entity Managers are, we have installed Doctrine with the Composer dependency manager, we created the skeleton of our blog app, and we managed to get the command line tools up and running.

In the next chapter, we will create our first entity class, discover a lot of annotations to map it to the database, generate the database schema, and start dealing with entities. By the end of the next chapter, the post system of our blog will be working!

About the Author

  • Kévin Dunglas

    Kévin Dunglas is the co-founder and CEO of La Coopérative des Tilleuls, a French IT company specializing in e-commerce, owned and managed by its workers themselves. He is also a software architect who works for a lot of companies, including Ubisoft and SensioLabs (creator of Symfony), as an external contractor. He contributes to open source software (especially Symfony, JavaScript, and Ubuntu ecosystems) and has been writing a technical blog for more than 10 years.

    Browse publications by this author

Latest Reviews

(3 reviews total)
Good starting point and tips regarding the API, but I think that it could had its content improved if more time were spent explaining more complex mappings (i.e. associative arrays), hydrators and possible "real life tough scenarios".
Sehr praxisnah. Man kommt schnell ins Thema rein. Für Praktiker und Entwickler geeignet!
Persistence in PHP with Doctrine ORM
Unlock this book and the full library FREE for 7 days
Start now