Home » Code » Getting started with Doctrine 2 and Laravel

Getting started with Doctrine 2 and Laravel

Posted by on June 30th, 2014

Getting started with Doctrine 2 and Laravel
So far in this Building Cribbb series of tutorials I’ve used Laravel’s Eloquent ORM to handle dealing with the database. Eloquent makes querying, inserting, updating and deleting data from a database really easy, and it comes bundled with Laravel meaning everything is set up right out of the box for you.

However recently I’ve been thinking that it might be advantageous to use a different ORM other than Eloquent. Eloquent is a fine ORM and I’ve used it extensively in other projects, but I think it would be really interesting to use a different ORM in this project.

Instead of Eloquent, I’ve decided to use Doctrine 2. Doctrine 2 is an ORM, but it follows a different methodology to Eloquent that offers a number of benefits.

In this tutorial I’m going to talk about the benefits of using Doctrine 2 over Eloquent as well as how to set it up within your Laravel project.

What is Doctrine2 and how is it different to Eloquent?

Doctrine2 is an ORM is much the same way as Eloquent, but there are some very important differences.

An ORM (Object-relational mapping) is a way of moving data between a relational database (like MySQL) into PHP objects that are useful to work with in our applications. Because the database will store the data as relations, we need a way of converting back and forth whenever we save or retrieve data.

Both Doctrine 2 and Eloquent are ORMs that allow us to easily query and persist data with a database without ever having to worry about converting objects to relations or vice versa.

However, Doctrine2 and Eloquent differ in the way that they work.

Eloquent uses the Active Record pattern. Generally speaking, this is where each row in the database is tied to an object. When you retrieve a row from the database you can update, delete or save using the object itself.

For example using Eloquent you would do something like this:

$user = new User;
$user->name = 'Philip Brown';
$user->save();

Doctrine 2 uses the Data mapper pattern. This is where data is mapped to the database, but the ability to persist data is kept separate from the actually object itself. To persist the data we use something called an entity manager.

Using Doctrine 2 looks like this:

$user = new User('Philip Brown');
EntityManager::persist($user);
EntityManager::flush();

Why would you want to use Doctrine2 instead of Eloquent?

The benefit of using Doctrine2 over Eloquent is that the domain logic of the object is kept completely separate from the logic of persisting data to the database. This means that the things that make your application unique, don’t need to be concerned with how the data is actually persisted to storage.

When you use an Active Record implementation like Eloquent, each object has the ability to change the database. This makes for code that is leaky and can cause issues if the rules of dealing with those objects aren’t strictly followed.

Using a Data Mapper implementation like Doctrine 2 ensures that the “business logic” of the objects are encapsulated in plain PHP objects, and all logic about how those objects are stored is handled by a completely separate service.

For more on this topic, take a look at What’s the difference between Active Record and Data Mapper?.

An example of the benefits of Doctrine

So you are probably thinking, “the difference between using Eloquent or using Doctrine seems a bit hand wavy”. I would have to agree that without actual real world examples, the difference between using Active Record verses using The Data Mapper pattern does seem like a bit of a non-issue.

However with that being said, here is a real life example of why I’m choosing to use Doctrine over Eloquent for this project.

The big benefit of using the Data Mapper pattern over the Active Record pattern is the encapsulation of business rules. Business rules are simply the rules around how your application works.

Business rules

Each application will have rules around how things should work. Typically if you are building an application within an existing business, the business will already have rules and processes around how things work. But even for new applications or new businesses, the application will typically be required to work in a certain way.

For example in Cribbb, a User might only be able to write a new Post if she is a member of the Cribbb.

This is a business rule of our application. We need to be able to enforce this rule so users can’t make posts into cribbbs that they are not a member of.

But how and where do we enforce this rule in our application?

Where to enforce business rules

The business rules of our applications are extremely important as they enforce how the application should work and how users should be able to interact with the system.

Knowing when and where to place your business rules, however, can be a little bit tricky.

Typically you might see an application dealing with this kind of logic in the controller:

public function store()
{
  $user = User::find(Input::get('user_id');
  $cribbb = Cribbb::find(Input::get('cribbb_id');

  if($cribbb->users->contains($user)
  {
    $cribbb->posts()->save(Post::create(Input::all()));
  }

  return $cribbb;
}

This would work, but strictly speaking, this kind of logic should not be in the Controller. If you place this kind of logic in the Controller you will probably find that you end up repeating yourself in multiple places around your application. Your Controllers are only for web requests, and so if you need to provide an API or a command line interface to your application you will have to duplicate this code.

Alternatively you could place this logic in the Model itself. This means whenever a user tries to post to a Cribbb our business rule will be in place:

class Cribbb extends Eloquent {

  public function addPost(User $user, array Post)
  {
    if($this->users->contains($user)
    {
      $this->posts()->save($post);
    }
  }

}

This means whenever we use an instance of Cribbb in our controllers, API or command line the business rule will be enforced!

However…

The Cribbb model is still an instance of Eloquent and so we could quite easily bypass the business rule by simple doing:

$cribbb->posts()->save(new Post(Input::all()));

This means our all important business rules are easy to break if someone who isn’t aware of the business rules is working in the codebase.

Finally, we could place the business rules logic in a Service class or Repository. This means that the Service class or Repository would provide an interface that enforces the business rules. This means we couldn’t add posts to a cribbb we weren’t a member of.

However, once again because we are working with Active Record models, there would be nothing to stop us from bypassing the Service or Repository altogether and just doing what we want with the model object.

So hopefully you can see, having direct access to the persistence layer of the database means we can’t enforce the business rules of our application. We can define an API for our models, or put a layer of indirection in-between the model and the developer, but there is no way of totally enforcing the rules. Active Record will allow us direct access to the database to make whatever changes we want, no matter what business rules we have in place.

Using Doctrine to enforce business rules

This is not an issue with Doctrine because Doctrine entities are plain PHP objects that do not inherit any public methods and they have no knowledge of how the entities are persisted to the database.

When using Doctrine, we could define a method on our Cribbb entity like this:

public function addPost(Post $post)
{
  if($this->isMemberOf($post->user))
  {
    $this->posts[] = $post;
  }
}

This would enforce the rule that a post can only be added to cribbb by members of that cribbb.

So as you can see, the big benefit of using the Data Mapper pattern with Doctrine is the ability to define and encapsulate our business rules within our entities. This prevents leaky code, and allows us to enforce these rules at the heart of application’s domain.

For more on this problem, have a read of How We Code: ORMs and Anemic Domain Models.

Setting up Doctrine2 with Laravel

Doctrine2 is a stand alone package that can be basically dropped into any PHP project as the ORM layer.

However Doctrine 2 isn’t exactly a trivial package to set up as there is a lot going on under the hood.

What’s more, ideally we want Doctrine 2 to seamlessly fit with the structure of Laravel 4. It would be a bit awkward if the configuration of Doctrine looked totally out of place with how everything else is set up in our Laravel 4 project.

Fortunately we work within the beautiful world of Open Source software and so we don’t have to reinvent the wheel! Mitchell van Wijngaarden has already created a bridge to allow Doctrine 2 to melt seamlessly with Laravel 4’s existing configuration.

This will make our lives working with Doctrine 2 and Laravel 4 a whole lot easier!

To install Doctrine 2 within our Laravel 4 project we can simply add the following to the composer.json file:

"require": {
    "mitchellvanw/laravel-doctrine": "0.*"
}

And then update composer:

composer update

Next we need to add the Service Provider and Facade alias to the app.php configuration file under app/config.

Add the following to your providers array:

'Mitch\LaravelDoctrine\LaravelDoctrineServiceProvider'

And the following to your alias array:

'EntityManager' => 'Mitch\LaravelDoctrine\EntityManagerFacade'

Finally this package has a custom configuration file. To publish the configuration file, run the following command:

php artisan config:publish mitch/laravel-doctrine --path=vendor/mitch/laravel-doctrine/config

Conclusion

Using Doctrine2 is quite a bit of a shift from using Eloquent and so I’ll save getting into the code for next week. Whilst there are many of the same similarities, I think if you are approaching Doctrine 2 for the first time, some of the concepts do need a bit of explaining.

It’s important to say, there is absolutely nothing wrong with Eloquent or the Active Record pattern. I’ve personally used Eloquent in a number of projects. Eloquent (and the Active Record pattern) make working with data and persistence in your application a total breeze.

However I do like the Data Mapper pattern and what it can offer you as a developer. I think using Doctrine 2 in a Laravel application is a good opportunity to write some tutorials on using the ORM and making good use of the different methodology. I’ve been looking at using it for a while, but Mitchell’s bridge package sealed the deal for me.

If you are happy using Eloquent you shouldn’t switch just for the sake of it. Continue using Eloquent and use the next couple of tutorials as something to think about for one of your future projects.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

To view a full listing of the tutorials in this series, click here.

Philip Brown

Hey, I'm Philip Brown, a designer and developer from Durham, England. I create websites and web based applications from the ground up. In 2011 I founded a company called Yellow Flag. If you want to find out more about me, you can follow me on Twitter or Google Plus.

  • Voodoo

    Interesting article. I think using a Data Mapper is far better for large to Enterpripse projects. Advantages are quite evident. However, about Laravel, Eloquent will be always supported by Taylor Otwell and a lot of L4 packages use/integrate Eloquent. Furthermore, if mitch/laravel-doctrine development ended, it could be a problem for a project which implemented it.

    For my project I chose Eloquent, even if I fully recognize the disadvantages of the Active Record pattern. Having a strict control over other devs following the correct business logic won’t be easy. I hope to have done the right choice.

    Thanks Philip! :)

  • Chapi

    In your example of using Doctrine to enforce rules, what is preventing you to do the following?
    $post = new Application_Models_Post();
    //Asign “post” properties here
    EntityManager::persist($post);
    EntityManager::flush();

    Also, using eloquent couldn’t you overwrite the save method in the post model to enforce a rule?

    I am not critiquing, this are doubts that I have.
    Actually I am using doctrine 2 with zend framework at work and laravel with eloquent for personal projects.

    This is my first comment here but I am reading you since last year.
    I have enjoyed your articles and learned a lot.

    Thank you.

    P.S.: Sorry for my bad english

    • Voodoo

      I think the solution of overriding save()/update()/delete() methods in the model would only partially solve that. You could still perform queries for example, and you can’t override querying methods or you would break repositories too. However, I suppose there are elaborated solutions to avoid that as well (for example, overriding the querying methods with an if clause, if the model primary key is set than the method doesn’t work. Or disabling them in the view presenters).

      The point, I think, is that with a Data Mapper you have really a POPO (Plain Old Php Object) and you have out of the box no way to break these formal rules with a real separation between storage (db) and persistence. By using Eloquent you need lot of code/changes/hack to obtain the same result.

      Philip correct me if I’m wrong :)

      • That’s exactly right my friend :)

      • kinteba

        Eloquent or Doctrine is a matter of choice, I do not judge. by cons that we need more code (and time) to write rules with Eloquent I do not agree. It must also write the rules for Doctrine, with Eloquent I write the same logic without hack on methods : save, update, delete, …, I write the rules directly hooked on update a property (through ArrayAccess).

        as follows:

        // validation: ok
        $user->name = ‘foo’;

        // validation: fails because is not an email
        $user->email = ‘foobar’;

        This executes automatically my validation function using the laravel validator (before the persistance). I define my rules with only a few characters in the model like this:

        protected $rules = [
        ‘name’ => ‘between:3,16|unique:users’ ,
        ’email’ => ‘required|email|unique:users’
        ];

        Short and safe.

        Also, the rules are reusable in validations forms :)

        PS: sorry for my english

        • Yes I agree that you are able to define your validation in a simple way using Eloquent, but I think you are missing the big difference of the Active Record pattern verses the Data Mapper pattern.

          ORMs like Active Record and ORMs like Doctrine 2 are two very different tools for two very different types of applications. I don’t think you could say one is better than the other for all situations.

          • kinteba

            You say: “two very different tools for two very different types of applications”

            Call a spade a spade. Two patterns / two “organizations”.

            It only concerns the organization of the code, not the type of application whose the two ORMs are technically appropriate for all cases. Unless if Doctrine makes the coffee since the last time I used it? ;)

            The best is the one that satisfies us. In this case, the choice mostly depends on the favorite organization. Not technical limitations, for one or the other.

          • One could argue that although ActiveRecord does not necessarily impose technical limitations – it does open you up to code bleed and systems knowledge elsewhere in the application – something that Doctrine helps to avoid.

            In short, Doctrine ensures a better separation of concerns via the DataMapper pattern as opposed to Eloquent and the Active Record pattern.

          • Absolutely Kirk :) I do believe that you need to pick the right tool for the job. I love Active Record, but you have to work with the inherent positives and negatives of how the pattern works.

    • You definitely can use the Active Record pattern to enforce rules. This usually means adding methods rather than overwriting or blocking existing methods.

      However overwriting the save() method is just going to get you into a situation where your code diverges from the underlying Eloqouent#save method.

      You also have the problem of relating objects together. In my experience, the business rules around how objects are related are often most important. This means you would have to do something about every relation method too.

      At the end of the day, as I mentioned above, there are ways of using Active Record to enforce business rules. However, sometimes it’s better to just use a different tool.

  • Peter

    You fucking rule man! Great website, great tutorials! It’s my first time here and I’m very glad to learning everything for free!

    Maybe later you can add a paid section! I think everybody will be agree to pay you for this awesome working!

    Best Regards,

    Greetings from Brazil :D

    • Thanks Peter :D

      You’ve read my mind, I have big plans for Culttt :D

  • kinteba

    With Doctrine, the problem is that it reduces the productivity gain that can be done with Eloquent.

    If we want to enforce the rules with Eloquent, it must be put in place then is quiet, the usage is very fast and friendly.

    By against Doctrine, the establishment is long and utilisation is also lengthened.

    Matter of taste, I prefer the way simple and productive

    • Yeah I prefer simple and productive too. But I also prefer the right tool for the job and Eloquent isn’t for every type of application :)

      • kinteba

        I used Doctrine during 3 years, I do not see a single case where Doctrine provides a solution that is not feasible simply with Eloquent.

        See my reply to Voodoo :)

        • But that entirely depends on the types of applications you were building.

          I agree, Eloquent is perfect for CRUD applications, but not for all applications.

          • kinteba

            I do not mean better, at this level it’s 2 very good ORM.
            The best is the one that satisfies us.

            What kind of application Eloquent is not good?

          • Well it really depends on the specifics of the application. It’s hard to say a certain “type” of application. I like not having to think about the database or forcing certain conventions when writing really complex applications though.

          • kinteba

            Ok, so It’s only a choice of organization.

  • Pingback: Encapsulating your application's business rules | Culttt()

  • windmaomao

    So the Doctrine will let you deal with the database access in a later stage with a separate manager, whereas Eloquent requires you to deal with database and business logic at the same time. Even when you decide to code business logic first, with Eloquent you still end up with database code at the same place later. So Doctrine will always give us cleaner code.

    Thanks for the article, Philip.

    • Yeah that’s right. You can build a lot of your application without ever really thinking about the database if you don’t couple your business logic to the persistence layer :)

  • Nick Myer

    Great Article as always but I have one question that goes towards Laravel.

    Most of my jobs are CRUD applications and I just use Eloquent for it but the last week I built a CRUD application with Doctrine 2 instead and it feels like I have much more freedom to do certain things that sometimes can get quite annoying with Eloquent, at least for me, and I really like that Doctrine generates the database from my entities.

    Do you think it would be overkill to use Doctrine 2 for my future applications instead of Eloquent even though Eloquent is sufficient for CRUD applications?

    • Thanks Nick :)

      I think it really depends on the application. I think Eloquent is great for both CRUD and non-CRUD applications. Doctrine can also be used for CRUD or non-CRUD applications. I guess it really just depends.

      I find that I can usually get stuff done quicker with the Active Record pattern.

  • Eivar Montenegro

    I think there is a typo on your require example for laravel-doctrine package, according to https://github.com/mitchellvanw/laravel-doctrine/wiki/Installation it should be:

    “require”: {
    “mitchellvanw/laravel-doctrine”: “0.*”
    }

    • Ah yeah Mitchell changed his namespace.

      Thank you, I’ve updated the post :)

  • Mihai Georgescu

    Could you not enforce a rule in Eloquent by hooking into the model events ?http://laravel.com/docs/eloquent#model-events

    Post::saving(function($post){
    //stuff
    });

    • Yeah there are definitely ways to do to it. To be honest having code reviews would be even easier because you wouldn’t have to use anything to “enforce” rules.

  • Rafael C

    Hey Philip, when you say “To install Doctrine 2 within our Laravel 4 project” I think you forgot to mention that you need the Doctrine2 ORM itself on your required dependencies also. Besides this really good article, gratz !

  • Nice. I switched from Eloquent to Doctrine in Laravel. I have a question. How do you go about doing seeding/fixtures for testing with Doctrine in Laravel? Thanks, and keep up the good work.

  • is there a way of enforcing business rules in laravel without using doctrine. i understand that separation of business rules is important however..doctrine is not easy to use as it involves lots of coding and definings. there must be a way we can deal with laravel without involving doctrine..

    • Yes of course, you can just use methods on the Eloquent model for the actions you want the object to be capable of. The only issue is that the Eloquent model would still be able to bypass those rules, but as long as you do code reviews and everyone is aware of following the rules and not skipping them for simplicity, you will be fine.

  • matiux

    I tried to use Commandline Tools.
    According to official guide, I can use this command to generate getters and setters:

    php/vendor/doctrine orm:generate-entities

    but I get this error:
    —————————————————
    You are missing a “cli-config.php” or “config/cli-config.php” file in your
    project, which is required to get the Doctrine Console working. You can use the
    following sample as a template:

    <?php
    use DoctrineORMToolsConsoleConsoleRunner;

    // replace with file to your own project bootstrap
    require_once 'bootstrap.php';

    // replace with mechanism to retrieve EntityManager in your app
    $entityManager = GetEntityManager();

    return ConsoleRunner::createHelperSet($entityManager);
    ———————————————–
    So I have try to create the cli-config.php but where is the correct bootstrap.php file?

    if I understand correctly, the bootstrap.php file is need to load EntityManager in cli, it contain the user credential to database access:

    http://doctrine-orm.readthedocs.org/en/latest/reference/configuration.html

    Thanks

    • matiux

      < ? php
      use DoctrineORMToolsConsoleConsoleRunner;

      // replace with file to your own project bootstrap
      require_once 'bootstrap.php';

      // replace with mechanism to retrieve EntityManager in your app
      $entityManager = GetEntityManager();

      return ConsoleRunner::createHelperSet($entityManager);

      So I have try to create the cli-config.php but where is the correct bootstrap.php file?

      if I understand correctly, the bootstrap.php file is need to load EntityManager in cli, it contain the user credential to database access:

      http://doctrine-orm.readthedocs.org/en/latest/reference/configuration.html

      Thanks

      • Yes you have to create the bootstrap.php file like it says in the docs.

        • matiux

          Hi Philip, the file like that, doesnt work.
          Maybe I created in a wrong directory.
          The problem is that require_once ‘bootstrap.php’; don’t find the file and the GetEntityManager() function, obusly, doesn’t exists

        • matiux

          For now I have solved it

          https://github.com/mitchellvanw/laravel-doctrine/issues/43

          Some suggestion to improve the bootstrap-doctrine.php file?

          • Hmm, well you could resolve the Config from the IoC container to get your database details, or use resolve them from environment variables if you are using them.

          • matiux

            Yes, but what can I do to resolve the Config from the IoC container?

  • Tim Cox

    Hey Philip.
    Thanks for your article. Have you got Mitchells Doctrine bridge working with Laravel 5? I know Laravel 5 is due in November but I’m just starting a large project and wanted to use Laravel 5 bleeding edge along with Doctrine.
    Cheers!
    Tim

    • I haven’t tried it to be honest Tim, I’m sure Mitchell will ensure the package will be compatible with Laravel 5 though :)

  • Umanda Jayobandata

    What are the disadvantages and advantages of Sentry and Doctrine

    • Sentry and Doctrine are two very different things. Do you mean Eloquent and Doctrine?

  • George Felix

    Use
    php artisan config:publish mitchellvanw/laravel-doctrine –path=vendor/mitchellvanw/laravel-doctrine/config

    Instead:
    php artisan config:publish mitch/laravel-doctrine –path=vendor/mitch/laravel-doctrine/config

    Thanks for the article, is very helpful

  • Dave Jong A Lock

    cannot update the composer (using laravel 4.2). I get an error stating it’s not stable for use with my current settings

    • Yeah you need to have "minimum-stability": "dev" in your composer.json:

      https://github.com/cribbb/cribbb/blob/master/composer.json#L45

      • Dave Jong A Lock

        Hi Philip,

        Thanks for the reaction.

        I managed to install it.

        Do you have a guide or sample app so I can see how to create models and / or views?

        I tried to use your cribbb app, but I get errors, because of missing or wrong paths of files.

        Regards,

        Dave

  • Of course, nothing in Doctrine stops you from using an entity manager to access your database directly. On the other hand, my experience with both Doctrine and Eloquent indicates that Doctrine is both harder to use for all but the most simplistic cases and creates database statements that are hard to debug and very prone to sneaking inefficiencies in.
    Unfortunately, corporate doctrine very often forces you to use it (hence its name ;) ).

    • winkbrace

      well, it is not possible to add a post to the Cribbb entity if the user isn’t part of the Cribbb users. It only is possible by deliberately building your own DQL statement I think. Definitely harder at least.

  • Jebb

    Package mitchellvanw/laravel-doctrine is abandoned, you should avoid using it. No replacement was suggested.