Doctrine 2 CustomStringFunction and Undefined Index

Doctrine 2 allows for user defined functions to be created, this allows us to add vendor specific functions such as MySQL’s CONCAT_WS. I had the need to implement my own functions in a project I’ve been working on as DQL does not support a way to CONCAT expressions that contain null values without returning null (i.e. there is no IFNULL or ISNULL function).

After reading the Adding your own functions to the DQL language documentation and attempting to implement my own function I was repeatedly getting the following error: Undefined index and Class name must be a valid object or a string. I had a feeling that this was to do with my custom function not being auto-loaded although I was certain that I had followed the documentation correctly.

Having looked through Doctrine’s ORM classes I discovered a function named CustomFunctionsReturningStrings inside Parser.php. I set a breakpoint inside the function and was surprised to see that it never gets called. This is a bug in versions of Doctrine prior to 2.0.5.

If you are unable or do not wish to upgrade between versions but still need this fix you can apply the following patch to \Doctrine\ORM\Query\Parser.php:

2304c2304,2305
<                 return $this->FunctionsReturningStrings();
---
>                 // do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
>                 return $this->FunctionDeclaration();

Integrating Doctrine 2 with CodeIgniter 2

An easy to follow tutorial for integrating Doctrine 2 with CodeIgniter 2 is available at doctrine-project. Unfortunately, there are a few configuration problems which would prevent the proper loading of proxies if that configuration were to be used exactly as it is.

The problem is related to how the Proxies ClassLoader has been registered. PHP will attempt to load proxies which have the namespace Proxies from the directory {APPATH}/models/proxies/Proxies.

$proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
$proxiesClassLoader->register();

However, Doctrine has been configured to write proxies to the directory {APPATH}/models/proxies.

$config->setProxyDir(APPPATH.'/models/proxies');
$config->setProxyNamespace('Proxies');

Additionally, the suggested configuration registers a DefaultAnnotationDriver using the directory {APPPATH}/models/Entities which is unlikely to exist.

$driverImpl = $config->newDefaultAnnotationDriver(array(APPPATH.'models/Entities'));
$config->setMetadataDriverImpl($driverImpl);

The configuration and instructions shown below address these issues and contain some other useful notes on the integration.
Continue reading