Profiling Doctrine 2 with Zend Framework

We have been working on a few projects using Doctrine 2 and Zend Framework (ZF). We are using the Bisna Package (some additional documentation available here) as the glue to get everything working together nicely.

When working with any application it is always useful to have some kind of reporting mechanism for execution time, number of queries, memory use etc and we have used the following to help us profile our applications.

Doctrine 2 provides a simple interface for logging, namely

\Doctrine\DBAL\Logging\SQLLogger()

and the following resources implement it.

Using ZFDebug and the Doctrine 2 plugin

Download and unpack the ZFDebug package from https://github.com/MontmereLimited/ZFDebug

Drop the ZFDebug folder found in the ‘library’ directory of the unzipped package next to your Zend folder in the library directory of your application.

The ZFDebug plugin includes the following code for bootstrapping the ZFDebug bar with Doctrine 2

Location – Bootstrap.php

protected function _initZFDebug()
{
        if (APPLICATION_ENV == 'development')
        {
            $autoloader = Zend_Loader_Autoloader::getInstance();
            $autoloader->registerNamespace('ZFDebug');
            $em = $this->bootstrap('doctrine')->getResource('doctrine')->getEntityManager();
            $em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\DebugStack());

            $options = array(
                'plugins' => array(
                    'Variables',
                    'ZFDebug_Controller_Plugin_Debug_Plugin_Doctrine2'  => array(
                        'entityManagers' => array($em),
                     ),
                     'File' => array('basePath' => APPLICATION_PATH . '/application'),
                     'Exception',
                     'Html',
                     'Memory',
                     'Time',
                 )
             );

             $debug = new ZFDebug_Controller_Plugin_Debug($options);
             $this->bootstrap('frontController');
             $frontController = $this->getResource('frontController');
             $frontController->registerPlugin($debug);
        }
}

As our Doctrine 2 configuration is set in the application.ini we are using the following code

Location – application.ini

resources.doctrine.dbal.connections.default.sqlLoggerClass  = "Doctrine\DBAL\Logging\DebugStack"
ZFDebug = 1

Location – Bootstrap.php

if($this->getOption('ZFDebug') == '1')
{
    $autoloader = Zend_Loader_Autoloader::getInstance();
    $autoloader->registerNamespace('ZFDebug');
    $em = $this->bootstrap('doctrine')->getResource('doctrine')->getEntityManager();
    $options = array(
        'plugins' => array(
            'Variables',
            'ZFDebug_Controller_Plugin_Debug_Plugin_Doctrine2'  => array(
               'entityManagers' => array($em),
            ),
           'File'          => array('basePath' => APPLICATION_PATH . '/application'),
           'Exception',
           'Html',
           'Memory',
           'Time',
        )
    );
    $debug = new ZFDebug_Controller_Plugin_Debug($options);
    $this->bootstrap('frontController');
    $frontController = $this->getResource('frontController');
    $frontController->registerPlugin($debug);
}

 

You can also install and enable the python-sqlparse on your development environment to prettify the SQL output, however this will increase your script execution time for each application, I noticed an increase of ~1 second locally.

 

Using FirePHP to profile Doctrine 2

Micheal Ridgway’s package is also very easy to get up and running. First make sure you have Firefox, Firebug and FirePHP installed.

Then download https://github.com/mridgway/ZendX_Doctrine2/ and extract the above package from github.

Grab the ZendX directory found inside lib in the package, and drop it into your application’s library directory (next to your Zend folder as with ZFDebug).

You can then load the plugin with the following code

Location – application.ini

resources.doctrine.dbal.connections.default.sqlLoggerClass     = "ZendX\Doctrine2\FirebugProfiler"

Then load up your app in firefox and check out the console in Firebug for query logging goodness.

N.B. There appears to be a FirePHP extension for Chrome, but I couldn’t get it working, so I would recommend using ZFDebug if Chrome is your browser of choice.

There is also a plugin for Doctrine 1 and ZFDebug

 

Using MySQL’s UNIX_TIMESTAMP in Doctrine 2.0

I’ve been working with timestamps quite a lot recently and although my Doctrine DATE_FORMAT function is proving pretty useful, I came across a bit of stumbling block today where it could not help….the unix timestamp format. I needed to perform a comparison using UNIX Timestamps, which cannot be generated by DATE_FORMAT.
In raw SQL , you can use the function UNIX_TIMESTAMP to do this. However, similarly to DATE_FORMAT, UNIX_TIMESTAMP has not been included as a standard function in Doctrine 2….Therefore, a new User-Defined function was required.

The source code is available on our Uvd Github account here : https://github.com/uvd/Doctrine

In order to configure this in your application you should:

  • Add our UVd library to you library folder
  • Ensure the UVd namespace is included has been boostrapped by your zend/doctrine application
  • Instantiate UnixTimestamp as a custom DQL Function in your doctrine ORM boostrap process.
  • This will be dependant on your specific implemenation, but if you are using Guilherme Blanco’s Doctrine 2/Zend implementation you can add this line your application.ini
    resources.doctrine.orm.entityManagers.default.DQLFunctions.string.UNIX_TIMESTAMP = "UVd\DoctrineFunction\UnixTimestamp"
  • If you follow the Doctrine reference manual :
    $config = new \Doctrine\ORM\Configuration();
    $config->addCustomStringFunction('UNIX_TIMESTAMP', 'UVd\DoctrineFunction\UnixTimestamp');

You can use the function in the same way as you would in SQL, but remember your timestamp should be a reference to a PHP Object variable, not a database table field.

  • UNIX_TIMESTAMP(User.dateRegistered)

Please re-use this code as you see fit, however don’t forget to drop you comments below!

Flex/Flash Builder not connecting to debugger (hangs at 57%)

At some unknown juncture the ability to use the native Flash Player debugger (for either Netscape compatible browsers or IE) to debug my Flash applications from Flash/Flex builder stopped working. Whenever I debugged/launched the application (F11) the  progress would stick at 57% and eventually the attempted connection would timeout.

I have found various suggested solutions and workarounds including reinstalling Flash Player debugger and using the standalone debugger outside of the browser.  None were successful.

*SOLUTION*

The eventual solution was found here.

The jist is that you need to right click on an instance of the Flash Player in the browser or standalone instance and click on ‘Debugger’ in the context menu displaying the following dialogue box:

 

Then select ‘Other Machine’ and enter 127.0.0.1 as the IP address and click connect. This solved the problem entirely for me.  It also implicated the initial problem, which seems most likely to be  missing a value in the Windows hosts file (127.0.0.1    localhost).

I hope that this might help someone resolve this problem since it was the bane of my (working) existence for a while.

****UPDATE*****

After a little bit more digging and the re-occurrence of the problem I discovered that the problem is actually caused by the lack of a following record in the hosts file on Windows:

localhost    127.0.0.1

It appears that Flash Player debugger is floundering because it is referencing localhost but there is no domain to IP mapping in this hosts file. On Windows 7 (also on Vista and XP I believe) the location of that hosts file is here:

c:\Windows\System32\drivers\etc 

Using MySQL’s DATE_FORMAT in Doctrine 2.0

Since starting out with Zend + Doctrine at the beginning of the year, all of our projects have involved administration interfaces of some description. These have, in the most part, provided our client’s with the ability to manage their application data by interfacing with filtered and paginated tables of data, such as users and contacts.

In almost all instances it has been necessary for us to filter these lists on a specific date range, (often implemented onscreen with a jQuery data picker). This undoubtedly involves comparing a date string from the HTML filters with a specific time stamp field in the database in order to select the correct data set.

In standard MySQL, my favoured technique to compare 2 timestamps was always to use the DATE_FORMAT function to convert the timestamp into an integer of format YYYYMMDD. I could then perform a simple integer comparison as follows :

where (DATE_FORMAT(user.date_registered,%Y%m%d) > 20110504)

The same technique is also very useful for collecting certain records within a time range. For example pulling all users who registered between the hours of 10am and 11am:

where (DATE_FORMAT(user.date_registered,%H%i) > 1000)
AND (DATE_FORMAT(user.date_registered,%H%i) < 1100)

To perform all of our filtered queries in Doctrine we have been using the Doctrine Query Language (DQL). DQL allows you to query your model directly using an object syntax and the Doctrine ORM converts this to an SQL statement and executes it on your database server.

I soon realised after starting out with Doctrine that, ‘out of the box’ the ORM understands only a handful of SQL functions. (I imagine these are the common ones which have the same syntax across the popular DB vendors). Unfortunately my favoured DATE_FORMAT function was not included, so I was left with 2 options to be able to compare a timestamp in my PHP code.

  • Use Doctrine’s NativeSQL functions to write an SQL statement
  • Write a User-Defined Function so that Doctrine recognises DATE_FORMAT when written in DQL and can successfully transform it into SQL.

Considering we do these comparisons so much, I went with option 2 and wrote DateFormat, a PHP class to extend Doctrines grasp of SQL

The source code is available on our Uvd Github account here : https://github.com/uvd/Doctrine

In order to configure this in your application you should:

  • Add our UVd library to you library folder
  • Ensure the UVd namespace is included has been boostrapped by your zend/doctrine application
  • Instantiate DateFormat as a custom DQL Function in your doctrine ORM boostrap process.
  • This will be dependant on your specific implemenation, but if you are using Guilherme Blanco’s Doctrine 2/Zend implementation you can add this line your application.ini
    resources.doctrine.orm.entityManagers.default.DQLFunctions.string.DATE_FORMAT = "UVd\DoctrineFunction\DateFormat"
  • If you follow the Doctrine reference manual :
    $config = new \Doctrine\ORM\Configuration();
    $config->addCustomStringFunction('DATE_FORMAT', 'UVd\DoctrineFunction\DateFormat');

You can use the function in the same way as you would in SQL, but remember your timestamp should be a reference to a PHP Object variable, not a database table field.

(DATE_FORMAT(User.dateRegistered,”%H%i”) > 1000)

Please re-use this code as you see fit, however don’t forget to drop you comments below!

Search