Zend Framework 2 and Doctrine 2 ORM Integration

So, finally I’ve found time to start a new approach of migrating older Zend Framework (ZF) 1 projects to ZF2. To get most out of ZF2 and its new modular design I’ve decided to simultaneously try out the Doctrine 2 ORM module. These are the steps I’ve used to integrate Doctrine 2 into ZF2.

Skeleton ZF2 Project

First off, setup your skeleton ZF2 project as usual. Using Netbeans (or any IDE of your choice) download the ZendSkeletonApplication and create a new project. You will also need to setup composer to manage your ZF2 project – so do so as well.

Then, initialize your skeleton application by issuing the install command:

$ php composer.phar install
Warning: This development build of composer is over 30 days old. It is recommended to update it by running "composer.phar self-update" to get the latest version              .
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing zendframework/zendxml (1.0.0)
    Downloading: 100%

  - Installing zendframework/zendframework (2.3.0)
    Downloading: 100%

zendframework/zendframework suggests installing ext-intl (ext/intl for i18n features (included in default builds of PHP))
zendframework/zendframework suggests installing doctrine/annotations (Doctrine Annotations >=1.0 for annotation features)
zendframework/zendframework suggests installing ircmaxell/random-lib (Fallback random byte generator for ZendMathRand if OpenSSL/Mcrypt extensions are unavailable)
zendframework/zendframework suggests installing ocramius/proxy-manager (ProxyManager 0.5.* to handle lazy initialization of services)
zendframework/zendframework suggests installing zendframework/zendpdf (ZendPdf for creating PDF representations of barcodes)
zendframework/zendframework suggests installing zendframework/zendservice-recaptcha (ZendServiceReCaptcha for rendering ReCaptchas in ZendCaptcha and/or ZendForm)
Writing lock file
Generating autoload files

This sets up your dev environment by downloading ZF2 into your project’s vendor folder. Based on the shiny new modular design composer also suggests to install additional modules, such as ext-intl and doctrine-annotations. We ignore theses suggestions for now and continue to install the Doctrine ORM module first.

Creating ZF2 Modules via command line

You can use the Zend Framework Tool (ZFTool) to create ZF2 modules from the command line too, just in case you want to start from scratch. Setup ZFTool via composer (zendframework/zftool) and run the following command to create a ZF2 module:

zf.php.bat create YourModule

Make sure to run zf.php(.bat) from the root of your project – otherwise you’ll get an error saying

I cannot find the autoloader of the application.

Additional Modules

In order to install additional modules you basically have two options with composer:

  1. Add required modules in the require-section in composer.json
  2. Install module(s) via composer from command line

I tend to choose the first option. Thus, we need to add the following lines to the require section in composer.json:

{
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.3.*",
        "doctrine/doctrine-module": "dev-master",
        "doctrine/doctrine-orm-module": "dev-master"
    }
}

Since doctrine-orm-module requires doctrine-module we include it explicitely. Optionally, you could use specific vesions for both modules but since this is a plain dev project dev-master is just fine. Make sure to use specific versions for production environments!

To update your ZF2 project with these new requirements simply call composer with the update switch:

$ php composer.phar update
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing symfony/console (v2.4.3)
    Downloading: 100%

  - Installing doctrine/lexer (v1.0)
    Downloading: 100%

  - Installing doctrine/annotations (v1.1.2)
    Downloading: 100%

  - Installing doctrine/collections (v1.2)
    Downloading: 100%

  - Installing doctrine/cache (v1.3.0)
    Downloading: 100%

  - Installing doctrine/inflector (v1.0)
    Downloading: 100%

  - Installing doctrine/common (v2.4.1)
    Downloading: 100%

  - Installing doctrine/doctrine-module (dev-master 3af3a00)
    Cloning 3af3a000644eeee27e76f53ece644333caf957e8

 - Installing doctrine/dbal (v2.4.2)
    Downloading: 100%

  - Installing doctrine/orm (v2.4.2)
    Downloading: 100%

  - Installing doctrine/doctrine-orm-module (dev-master 0aac7bd)
    Cloning 0aac7bd1a9948418156178977c21cfd4d93aee41

Writing lock file
Generating autoload files

We have successfully added the Doctrine 2 ORM module to our ZF2 project – congratulations 🙂

Zend Developer Tools

Optionally, you can also install the Zend Developer Tools module which is highly recommended at this point:

{
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.3.*",
        "zendframework/zend-developer-tools": "dev-master",
        "doctrine/doctrine-module": "dev-master",
        "doctrine/doctrine-orm-module": "dev-master"
    }
}

… and update your project with the new dependency:

$ php composer.phar update
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing zendframework/zend-developer-tools (dev-master 763cecf)
    Cloning 763cecf9d68fc0d3765d45847047817a47ecdd4a

Writing lock file
Generating autoload files

In order to use Zend Developer Tools with need to auto-load its configuration. Thus, copy the module’s dist file to your application’s autoload folder and remove the .dist extension to make it a regular PHP file:

cp vendor/zendframework/zend-developer-tools/config/zenddevelopertools.local.php.dist config/autoload/zenddevelopertools.local.php

Also, add this module to the application.config.php:

<?php
  return array(
    // This should be an array of module namespaces used in the application.
    'modules' => array(
        'Application',
        'ZendDeveloperTools',
        ...
    ),

To test the developer tools simply refresh your skeleton application. At the bottom you should now see some development output, as shown below:

zdt-zf2-toolbar

Setup Doctrine 2

Next, we need to actually setup our shiny new Doctrine 2 module.

First, activate it by updating your config/application.config.php:

return array(
  'modules' => array(
        'ZendDeveloperTools',
        'DoctrineModule',
        'DoctrineORMModule',
        'Application',
    ),
    // more config...

Now we need to configure the database connection so let’s create a config/autoload/doctrine.local.php with our credentials:

<?php

$dbParams = array(
    'hostname' => 'localhost',
    'port' => 3306,
    'username' => 'root',
    'password' => '',
    'database' => 'zf2doctrine2'
);

return array(
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'params' => array(
                    'host' => $dbParams['hostname'],
                    'port' => $dbParams['port'],
                    'user' => $dbParams['username'],
                    'password' => $dbParams['password'],
                    'dbname' => $dbParams['database'],
                    'driverOptions' => array(
                        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
                    ),
                )
            )
        )
    )
);

Note that you can also simply put the database connection details in local.php and/or global.php depending on your environment (dev vs production) but I tend to seperate these configuration options into different files.

Optional: You can also setup query debugging tools, such as BjyProfiler. Like the Zend Developer Tools you can easily set it up via composer:

"bjyoungblood/BjyProfiler": "dev-master"

and activate by configuring bjyprofiler.local.php in autoload.

Setting Annotation Driver

That’s it! Now you are ready to create your first Entity file:

To use the modules auto-sync funtionality we need to add support for annotation mappings in the corresponding module’s module.config.php:

'doctrine' => array(
        'driver' => array(
            'application_entities' => array(
                'class' => 'DoctrineORMMappingDriverAnnotationDriver',
                'cache' => 'array',
                'paths' => array(__DIR__ . '/../src/Application/Entity')
            ),
            'orm_default' => array(
                'drivers' => array(
                    'ApplicationEntity' => 'application_entities'
                )
            ))),

As specified by the paths option make sure to put Entity files in src/Application/Entity for the Application module.

Now let’s create our first entity file:

<?php

namespace ApplicationEntity;

use DoctrineORMMapping as ORM;

/** @ORMEntity */
class User {

    /**
     * @ORMId
     * @ORMGeneratedValue(strategy="AUTO")
     * @ORMColumn(type="integer")
     */
    protected $id;

    /** @ORMColumn(type="string") */
    protected $fullName;

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

    /**
     * Set fullname
     *
     * @param string $fullname
     * @return User
     */
    public function setFullname($fullname) {
        $this->fullName = $fullname;

        return $this;
    }

}

Upon reload of your application you will notice 1 mapping:

zdt-zf2-toolbar-mapping

As you can see the dynamic mapping already works!

Let’s validate the database sync status:

$ vendor/bin/doctrine-module.bat orm:validate-schema
[Mapping]  OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.

Obviously, the local entities are not in snc with our database. So let’s sync it:

$ vendor/bin/doctrine-module.bat orm:schema-tool:create
ATTENTION: This operation should not be executed in a production environment.

Creating database schema...
Database schema created successfully!

And finally test it:

public function indexAction() {
    $objectManager = $this
        ->getServiceLocator()
        ->get('DoctrineORMEntityManager');

    $user = new ApplicationEntityUser();
    $user->setFullName('Some great developer :)');

    $objectManager->persist($user);
    $objectManager->flush();

    die('Hello there '.$user->getId());
}

Check the debug tools:

zdt-zf2-toolbar-debugger

That’s it!

Want to know how to generate Entity model mapping classes at ease based on YAML files? Then read on: Using YamlDriver to generate Entity model mapping classes via YAML files.

You may also like...

8 Responses

  1. wimarbueno says:

    zend framework 2 or without doctrine? which is recommended?

    • Hi, this depends in your preference whether to use Zend_Db or an external ORM framework such as doctrine. I for my part tend to use Doctrine for smaller projects too since it offers significant improvements (fixtures, migration, etc.) over Zend_Db. Cheers

  2. kuko says:

    hihi;
    how do i configure modules so i dont have to copy/paste doctrine config for each module?

    thx

  3. Edem says:

    Hi, good job!
    u help me to have a better understanding on ‘zend-developer-tools’ installation and ‘Doctrine-ORMModule’

  4. Twan says:

    I’m trying to run vendor/bin/doctrine-module.bat orm:validate-schema but I’m getting the following errors:

    vendor/bin/doctrine-module.bat: line 1: @echo: command not found
    vendor/bin/doctrine-module.bat: line 10: syntax error: unexpected end of file

    the .bat file:

    @echo off

    if “%PHPBIN%” == “” set PHPBIN=@php_bin@
    if not exist “%PHPBIN%” if “%PHP_PEAR_PHP_BIN%” neq “” goto USE_PEAR_PATH
    GOTO RUN
    :USE_PEAR_PATH
    set PHPBIN=%PHP_PEAR_PHP_BIN%
    :RUN
    “%PHPBIN%” “@bin_dir@\doctrine-module.php” %*

  5. Tomasz says:

    I think, I have found a little mistake – in chapter “Setting Annotation Driver” in line:

    ‘class’ => ‘DoctrineORMMappingDriverAnnotationDriver’,

    should be:

    ‘class’ => ‘Doctrine\ORM\Mapping\Driver\AnnotationDriver’,

  1. 06/04/2014

    […] post continues my approach to integrate Doctrine 2 into Zend Framework 2 by additionally setting up YamlDriver to generate and manage Doctrine 2 Entity model mapping […]

Leave a Reply

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