Laravel Doctrine is a drop-in implementation of the famous ORM for the Laravel 5.X Framework, and a really interesting alternative to the default choice, Eloquent. In this article, we will learn how to use it, and when.
Why Doctrine, and not Eloquent?
Those of us who have used Laravel at least once, have probably used Eloquent. We all love its fluent and easy syntax, and we all know snippets like the following:
$user = new App\User;
$user->name = 'Francesco';
$user->email = 'francesco@foo.bar';
$user->save();
What we're using here is the so called "Active Record" pattern. A frequently used architectural pattern, named by Martin Fowler in his ultra-famous book "Patterns of Enterprise Application Architecture". To simplify and explain things, this pattern assumes that a single row in the database is treated like an object in our software. However, with time, this pattern encountered many criticisms:
-
Active Record is about a strong coupling between database operations and the classes in our software. For many little projects this approach is more than fine, but what if our software grows in complexity? We could stumble upon the need for more classes, not always related to a specific table in our database. There, Active Record doesn't help us achieve a good level of abstraction from the data source.
-
the other main criticism is a direct consequence of the first: testability. If the model is tightly coupled to the database, building a test without it can be more difficult. It has to be said that a part of this problem can be reduced (not solved) with mocking and a good use of dependency injection.
Now, in the same book we mentioned before, Martin Fowler explained another architectural pattern: the Data Mapper. The Data Mapper consists of the presence of an intermediate layer which, working in both directions, provides access to the data source on one hand, and a good abstraction from it on the other. This means that objects in the software are not closely related to the data source, with great improvement in terms of responsibility isolation. The result? The developer can now focus on building an object that is nearer to the real world situation, and not to the database system chosen for the job.
Eloquent is an implementation of the Active Record pattern, and Doctrine is an implementation of Data Mapper. Let's see how we can install Doctrine for Laravel, and how to configure and use it.
Installing Doctrine for Laravel
As usual, we will use Homestead Improved as a standard development environment for our tests.
Let's create a new Laravel project.
composer create-project laravel/laravel Project
Then, we enter our project's folder and add Laravel Doctrine as a dependency with Composer.
composer require "laravel-doctrine/orm:1.1.*"
We also need to add the following class to our service providers list, in the config/app.php
file:
LaravelDoctrine\ORM\DoctrineServiceProvider::class,
Also, we can register the three facades for the EntityManager, Registry and Doctrine in the same file:
'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class,
'Registry' => LaravelDoctrine\ORM\Facades\Registry::class,
'Doctrine' => LaravelDoctrine\ORM\Facades\Doctrine::class,
Finally, we can publish the dedicated config file:
artisan vendor:publish --tag="config"
We are done! Laravel Doctrine is completely installed and configured.
The Example Application - ToDo List!
In order to learn something more about Doctrine for Laravel, we are going to replicate an existing application example that uses Eloquent. What about the Intermediate Task List on Laravel's official site?
We will create a very basic multi-user task list. In this application, our user will be able to:
- log into their own area.
- list existing tasks.
- add a new task to the list.
- mark a task as done / not done.
- update an existing task in the list.
- delete an existing task from the list.
Obviously, every user will be able to see only their own tasks.
Let's change the application's namespace to TodoList
first.
artisan app:name TodoList
Ok, now we can start from the very basics of Doctrine. In Eloquent, we used models. How do we start now?
Entities!
In Doctrine we use Entities to represent our application objects. Unlike with Eloquent where the model extends a base Model
class, a Doctrine entity is a plain PHP class that does not extend anything.
Here's a first stub of the Task
entity:
<?php
namespace TodoList\Entities;
class Task
{
private $id;
private $name;
private $description;
private $isDone = false;
public function __construct($name, $description)
{
$this->name = $name;
$this->description = $description;
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function getDescription()
{
return $this->description;
}
public function setName($name)
{
$this->name = $name;
}
public function setDescription($description)
{
$this->description = $description;
}
public function isDone()
{
return $this->isDone;
}
public function toggleStatus()
{
if(!$this->isDone) {
$this->isDone = true;
} else {
$this->isDone = false;
}
}
}
Not bad as a beginning. Yes, it's a little more "verbose" than an Eloquent model. However, there is a specific reason for that. First of all, if we think about it, this is a plain PHP class. It says nothing about its implementation, has no extra responsibilities. Everything it does is strictly related to the task itself. That's a good thing, because this approach is more "compatible" with the Single Responsibility Principle.
But...
Where is the Database?
In Eloquent, models are just an interface to the database. With some "magic", sometimes without even writing a single line of code in the model, we can just start working with them. The only thing we have to do is design our database accordingly. With Doctrine, the key concept is a little bit different.
Here, we start designing our application from our classes which represent the "real world" problem we want to solve. Then, we bind our classes to tables, and properties to columns.
Continue reading %Laravel Doctrine – Best of Both Worlds?%
by Francesco Malatesta via SitePoint
No comments:
Post a Comment