Integrating CodeIgniter and Doctrine 2 ORM with Composer

Oct 02, 2013

For a side project, I needed a very simple PHP Framework, and my choice was CodeIgniter. I also wanted to use an ORM, so I decided to use Doctrine. Integrating these can be a bit tricky, since all the documentation I could find was either incomplete and/or quite old. Here's how I integrated CodeIgniter 3 with Doctrine ORM, using Composer.<!--more-->

<span style="color: #999999;">This tutorial was written using CodeIgniter 3 and Doctrine 2.4.7, but it should work with other versions as well.</span>
<h3>1. Get CodeIgniter Up And Running</h3>
Your first step, of course, is to <a href="http://www.codeigniter.com/" target="_blank">download CodeIgniter</a> and install it in a location accessible to your webserver. For this tutorial, I created a sample project and made it accessible via <code>http://localhost/codeigniter-doctrine-sample/</code>. Opening this URL should yield the default CodeIgniter welcome page.
<h3>2. Get Doctrine Using Composer</h3>
Open the command line and go to the folder you just put composer into. Before you download Doctrine, you should set Composer's <code>vendor-dir</code> config option to the path where CodeIgniter expects it:
<pre>$ composer config --file="composer.json" vendor-dir application/vendor</pre>
After that, your local <code>composer.json</code> file is updated with the correct vendor path (you could also do it manually, of course). Download Doctrine using Composer now:
<pre>$ composer require doctrine/orm 2.4.*</pre>
Doctrine should now be available in your <code>application/vendor</code> directory along with its dependencies.
<h3>3. Create The Doctrine Library</h3>
To make Doctrine known to CodeIgniter, you must wrap it inside a CodeIgniter library. Create the library file <code>Doctrine.php</code> and put it into the <code>application/libraries</code> folder. This file was taken from the <a href="http://doctrine-orm.readthedocs.org/en/latest/cookbook/integrating-with-codeigniter.html#now-to-use-it" target="_blank">Doctrine documentation</a> and slightly adapted to fit our needs.
<pre>&lt;?php
use Doctrine\Common\ClassLoader,
    Doctrine\ORM\Configuration,
    Doctrine\ORM\EntityManager,
    Doctrine\Common\Cache\ArrayCache,
    Doctrine\DBAL\Logging\EchoSQLLogger;

class Doctrine {

    public $em = null;

    public function __construct()
    {
        // load database configuration from CodeIgniter
        require_once APPPATH.'config/database.php';

        // Set up class loading. You could use different autoloaders, provided by your favorite framework,
        // if you want to.
        //require_once APPPATH.'libraries/Doctrine/Common/ClassLoader.php';

        // We use the Composer Autoloader instead - just set
        // $config['composer_autoload'] = TRUE; in application/config/config.php
        //require_once APPPATH.'vendor/autoload.php';

        //A Doctrine Autoloader is needed to load the models
        $entitiesClassLoader = new ClassLoader('Entities', APPPATH."models");
        $entitiesClassLoader-&gt;register();

        // Set up caches
        $config = new Configuration;
        $cache = new ArrayCache;
        $config-&gt;setMetadataCacheImpl($cache);
        $driverImpl = $config-&gt;newDefaultAnnotationDriver(array(APPPATH.'models/Entities'));
        $config-&gt;setMetadataDriverImpl($driverImpl);
        $config-&gt;setQueryCacheImpl($cache);

        $config-&gt;setQueryCacheImpl($cache);

        // Proxy configuration
        $config-&gt;setProxyDir(APPPATH.'/models/proxies');
        $config-&gt;setProxyNamespace('Proxies');

        // Set up logger
        $logger = new EchoSQLLogger;
        $config-&gt;setSQLLogger($logger);

        $config-&gt;setAutoGenerateProxyClasses( TRUE );

        // Database connection information
        $connectionOptions = array(
            'driver' =&gt; 'pdo_mysql',
            'user' =&gt;     $db['default']['username'],
            'password' =&gt; $db['default']['password'],
            'host' =&gt;     $db['default']['hostname'],
            'dbname' =&gt;   $db['default']['database']
        );

        // Create EntityManager
        $this-&gt;em = EntityManager::create($connectionOptions, $config);
    }
}</pre>
<h3>4. Configure CodeIgniter To Use Doctrine</h3>
Open CodeIgniter's <code>config.php</code> file and tell it to use Composer's autoloading so Doctrine can be autoloaded correctly.
<pre>$config['composer_autoload'] = TRUE;</pre>
Older versions of CodeIgniter do not have this option. You can simply uncomment the following line in the Doctrine library's constructor instead:
<pre>require_once APPPATH.'vendor/autoload.php';</pre>
You should also enable autoloading for Doctrine by setting the following option in CodeIgniter's <code>autoload.php</code>:
<pre>$autoload['libraries'] = array('doctrine');</pre>
CodeIgniter should now already be able to work with Doctrine. You can check your progress by opening the welcome page in your browser. If everything loads without any PHP errors, you're fine.
<h3>5. Configure The Doctrine CLI</h3>
One of Doctrine's greatest assets is its command line tool that allows you to generate your database schema automatically. To make it work, you need to create a <code>cli-config.php</code> file in your project's root directory. It should have the following contents:
<pre>&lt;?php
/**
 * CLI Config file for the Doctrine2 CLI.
 */

use Doctrine\ORM\Tools\Console\ConsoleRunner;

//Do the bootstrap manually
define('APPPATH', dirname(__FILE__) . '/application/');
define('BASEPATH', APPPATH . '/../system/');
define('ENVIRONMENT', 'development');

chdir(APPPATH);
require APPPATH . '/libraries/Doctrine.php';

// replace with mechanism to retrieve EntityManager in your app
$doctrine = new Doctrine();
$entityManager = $doctrine-&gt;em;

return ConsoleRunner::createHelperSet($entityManager);</pre>
This is not perfectly pretty since we're duplicating code from CodeIgniter's <code>index.php</code>, but I haven't found a better way that works without modifying the original <code>index.php</code> file.

Once again, you can check your progress with the CLI. If the command shows no errors, the Doctrine CLI is now working with CodeIgniter.
<pre>$ ./application/vendor/bin/doctrine -V
Doctrine Command Line Interface version 2.4.7</pre>
<h3>6. Create Your First Entity</h3>
The last thing that remains to do is to actually create your first Doctrine entity file. It needs to go into application/models/Entities/Product.php.
<pre>&lt;?php
// src/Product.php
/**
 * @Entity @Table(name="products")
 **/
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;
    /** @Column(type="string") **/
    protected $name;

    public function getId()
    {
        return $this-&gt;id;
    }

    public function getName()
    {
        return $this-&gt;name;
    }

    public function setName($name)
    {
        $this-&gt;name = $name;
    }
}</pre>
<h3>You're Done!</h3>
You should now be able to generate your database schema from this entity:
<pre>$ ./application/vendor/bin/doctrine orm:schema-tool:create
ATTENTION: This operation should not be executed in a production environment.
Creating database schema...
Database schema created successfully!</pre>
If that works as well, then you've successfully integrated Doctrine and CodeIgniter. Congrats!

I used the following tutorials as resources to create this one. Thanks to their authors!
<ul>
<li><a href="http://wildlyinaccurate.com/integrating-doctrine-2-with-codeigniter-2/" target="_blank">WildlyInaccurate</a></li>
<li><a href="http://joelverhagen.com/blog/2011/05/setting-up-codeigniter-2-with-doctrine-2-the-right-way/" target="_blank">Joel Verhagen</a></li>
</ul>