Laravel & Doctrine Tutorial

Doctrine is a widely used independent(not affiliated with a framework) ORM that uses the entity manager pattern.

Why does it exist?

Doctrine uses the entity manager pattern, this makes it a bit odd in the PHP community, most of the framework ORM tools use the active record pattern. The entity manager pattern splits the database communication layer from the domain layer. Objects are fetched and stored through an entity manager. The entity manager controls their access and storage rather than the models themselves. The entity manager is usually given a description(ex. yaml) of the database and a model that represents the data in the application. In this way the model becomes an abstraction of the database in the application, with the entity manager controlling how and when the data in the model is fetched or persisted.

What is an ORM?

An ORM is a database(or generically a data) abstraction in a application that exposes the storage and management of the data in developer friendly way. Database tables map to classes and columns to variable declerations. In some programming language updating a variable automatically updates the matching database record in other a method to save the data must be called.

Active Record vs Entity Manager

The entity manager pattern is the dominant strategy for accessing data in Java. This quickly makes any talk of doctrine into an argument over Java vs PHP rather than Active Record vs Entity Manager. Trying to pick a fight over Java vs PHP is kinda against the point of what we do and most of the community heads of PHP agree. Both languages offer advantages and both languages can learn something from each other and in most cases do. Anyway back to the database thing. Active Record combines the data representation and the database access. Database operations are done via the models rather than a separate system like an entity manager. Creating or updating a model invokes some database code.

Separate Database from Domain Code

Separating the database access from the domain logic makes the domain logic much faster and lighter. In larger system that deal with a variety of use cases the domain logic will not always be driven by an underlying database. Ex. serialising data to be sent via a socket. Tying the database to the domain logic in that context does make sense and makes create, destroying and administrating objects much more expensive. In the entity manager pattern is very cheap to create 10000 models and persist or manipulate them later.

Laravel and Doctrine

There are a few solutions out there for tying in Doctrine to Laravel. We are going to look at “atrauzzi/laravel-doctrine”.

Add the following the require section in composer.json:

    “atrauzzi/laravel-doctrine”: “dev-master”,
    “doctrine/migrations”: “dev-master”,

Run this command:

php artisan vendor:publish —provider=“Atrauzzi\LaravelDoctrine\ServiceProvider” —tag=“config”

In the config folder there should be a new doctrine config file called doctrine.php. Uncomment the database connections mysql section. Doctrine does not support the mysql driver and Laravel does not support the mysqli driver so we need to separate these for Laravel and Doctrine. Doctrine provides a few ways to add the mapping information for models. For now we are picking the simplest one and adding a static loadMetaData function to the model.

namespace App\Models;

//use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ClassMetadata;

/**
 * @Entity
 * @Table(name=“users”)
 */
class Users
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(type=“integer”)
     */
    protected $id;

    /**
     * @Column(type=“string”, unique=true)
     */
    protected $email;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param mixed $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    public static function loadMetadata(ClassMetadata $metadata)
    {
        $metadata->setPrimaryTable(array(
            ‘name’ => ‘users’
        ));

        $metadata->mapField(array(
            ‘id’ => true,
            ‘fieldName’ => ‘id’,
            ‘type’ => ‘integer’
        ));

        $metadata->mapField(array(
            ‘fieldName’ => ‘email’,
            ‘type’ => ‘string’
        ));
    }
}

In routes add the following in the default Laravel welcome screen.

Route::get(‘/‘, function (\Illuminate\Contracts\Foundation\Application $app) {

    $em = $app->make(‘Doctrine\ORM\EntityManager’);
    $user = $em->find(‘App\Models\Users’, 1);
    print_r($user);

    return view(‘welcome’);
});

Why I likely won’t use Doctrine

I don’t really see myself using doctrine. Most frameworks chose the active record pattern for a reason. The entity manager pattern does not make that much sense in PHP. PHP usually deals with much less data at a time than something like Java and is not constrained by the same memory environment. In the case of PHP the ease of use of the active record pattern for me wins over the system benefits of an entity manager. As for the serialisation benefits mentioned above: because PHP is a dynamically typed language serialising models on the fly is very simple compared to statically typed languages. I feel that the PSR standards will likely go the way of the active record pattern when they get to ratifying database access.

Leave a Reply

Your email address will not be published. Required fields are marked *