Introduction

Whilst everyone is buzzing and creating fancy new Symfony2/Doctrine 2 applications, and perhaps even a shift to new frameworks/no frameworks, a great deal of us are still maintaining legacy apps and will be for some time to come. As these apps grow, we occasionally need to look back and scream at our old code and wonder why we didn’t make it more scalable or use neat optimisation tricks back when it was first conceived. The fact is, many of these “tricks” are not necessary at the time for a virgin app, and we need to develop code that is relevant to the task at hand.

That said, being aware of some of the case studies I will present to you now may help you to optimise old code, but may also allow you to think twice when you are working with new code – as the things I will describe do not take too much time to implement first time round.

As a company we have benefited from the Symfony framework in many ways including:

Rapid development

Consistency (easy to bring team members in and out)

Community support

Great documentation

And given back by providing time for our developers to:

File bug reports

Submit patches

Develop plugins

Help other users (particularly in IRC and the Symfony Forum)

Update the documentation

By agreeing to gold sponsorship we are now also making a small financial contribution to the project, whilst at the same time giving ourselves a chance to become more known in the Symfony world, especially with Symfony2 just around the corner and its great support for Varnish!

Brief history of the companies

Until recently, Redpill and Linpro were two separate companies, and the work done by Varnish Software was a part of Linpro. In 2008, Linpro and Redpill merged to form Redpill Linpro, and in 2010 Varnish Software broke away to form a “daughter” company and concentrate on the Varnish cache. Confused?

The most important thing is that all of the companies involved are dedicated to open source, you can read more about Redpill Linpro and Varnish Software on their respective web sites.

Employment Opportunities for Symfony developers in “the North”

If you are looking for a company to work for with a strong PHP team, and either already live in or are considering a move to “the Nordic region¹” please get in touch. We also have opportunities for Java developers and various other posts related to Open Source technologies, and if we don’t have a specific post for you but you are a skilled open source enthusiast, we are also interested in your CV – who knows, we might be able to create one for you.

¹We have offices in Norway, Sweden, Denmark and Finland, the bulk of Symfony operations are presently in Oslo.

“We recently had to implement table prefixes on our tables in Doctrine 2, which turned out to be not so trivial, and led me to a journey inside the Doctrine 2 metadata parser, event hooks and relation mapper. Fun stuff!”

We will be streaming the 10:00 conference on the 22nd June 2010. Refreshments will be served, please give me a shout if you are interested in coming along so we can buy enough conference tickets (we may be less than 5 people otherwise) and arrange a good sized conference room.

Background

It’s been a while since Jonathan announced the availability of Doctrine 2 for Symfony 1.x (wouldn’t recommend trying it with anything less than 1.3) and a a few things have changed since then, so here’s a refresher.

We are at a crossroads now with Symfony 2 looming on the horizon, and many developers may wish to wait until that is more stable (later this year) to make the move to Symfony 2 and Doctrine 2 simultaneously. This is not such a bad idea, however Doctrine 2 is already at a level where you may wish to consider using it in your projects, you won’t be disappointed if you do!

Getting started

Check out the plugin and set up the database as described in Jon’s blog, but don’t configure the schema just yet 😉

We’re going to go all out with the “Doctrine 2” way of doing things, so we’ll be using annotations, not yaml or xml – although you can look up that syntax if you prefer. (A lot of the stuff below won’t work though – you can’t have multiple yaml files for example yet).

In your project configuration class, you will have access to some methods:

In the first of these, you need to add all the things to configure Doctrine before the entity manager can be created. Once Doctrine has created the entity manager, you can use the second method if you need to, to further configure the entity manager. (Registering a Doctrine listener for example).

So, in your configureDoctrineConnection() method, you’ll want to do something like this:

// Decide where you want the proxy classes to be stored, and which namespace they should use$config->setProxyDir(sfConfig::get("sf_cache_dir")."/Proxies");$config->setProxyNamespace("Proxies");// You may want to make this environment specific for performance reasons$config->setAutoGenerateProxyClasses(false);$config->setSqlLogger(null);// This will get things working, but later you will want to use APC// or another "real" cache for production$cache=new \Doctrine\Common\Cache\ArrayCache;$reader=new \Doctrine\Common\Annotations\AnnotationReader($cache);$config->setMetadataCacheImpl($cache);$config->setQueryCacheImpl($cache);// Tell Doctrine where to find your entities (you may have more than one location)// This is mostly required for cli tasks that iterate over all of your entities$paths=array(sfConfig::get("sf_lib_dir")."/Entities");// Populate this with all the locations of your entities$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');$annotation=new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader,$paths);$config->setMetadataDriverImpl($annotation);// Register all the classes that Doctrine needs to autoload$classLoader=new \Doctrine\Common\ClassLoader('Entities\doctrine');$classLoader->setIncludePath(sfConfig::get('sf_lib_dir'));$classLoader->register();$classLoader=new \Doctrine\Common\ClassLoader("Proxies");$classLoader->setIncludePath($cachedir);$classLoader->register();$classLoader=new \Doctrine\Common\ClassLoader("Another\Namespace");$classLoader->setIncludePath(sfConfig::get('sf_lib_dir'));$classLoader->register();

Ok, that was a lot of stuff – but Doctrine 2 is more verbose – meaning less magic, but more explicit code. Some of the above calls may not be necessary – I need to do further testing, and also I’d like to get a lot of these things “standardised” in the plugin, so you can skip a lot of this if you follow a “default” path. The problem with the original release of the plugin was that it was not possible to have multiple class dirs, which makes it impossible to have plugins (for example) that also contain Entities. With the approach above, you explicitly add as many classes as you like to the annotation driver and the autoloader, and your plugin configuration classes can do the same.

Active Entity

The plugin comes bundled with Active Entity – this means that by extending ActiveEntity from our model classes (Entities) we can use our classes in much the same way as in Doctrine 1. Things like the following become available:

ActiveEntity was written and included with good intentions, because for Doctrine 2 to continue to be compatible with symony in the same way as Doctrine 1, a bit of magic needed to be re-introduced. BUT – for anyone that has been excited by Doctrine 2, one of the major breakthroughs is the non-intrusive model, and ActiveEntity kills that (along with a kitten):

So I strongly recommend that you Don’t extend ActiveEntity – and gradually the plugin will be “fixed” so that is never necessary. Currently basic object forms and some widgets are working fine without it, but I haven’t tested it with admin generators or anything like that yet so feedback is appreciated.

If you follow my advice, you have to do everything the “Doctrine 2 way”. That means taking control of your own code! Write your own getters and setters, extend your own classes (if you want to) – be verbose, write OOP code, etc!

Ongoing development

Doctrine 2 is still in Alpha at the moment and is constantly changing. Since we are using it actively in a project at the moment, we normally spot the changes pretty quickly and update the plugin to keep up, however we are not using all the aspects of the plugin (like generators, all the form widgets, etc) so from time to time something might completely fail when you svn up.

We are also trying to slowly, and safely (for BC) remove the need for ActiveEntity – but we’re being careful with this because we don’t want to break existing projects that are using it.

Report bugs in the usual way using the symfony bug tracker (if it’s plugin related) or on Doctrine Jira (if you know it is a Doctrine issue). When reporting plugin bugs, please register the bug under the sfDoctrine component and add the keyword sfDoctrine2Plugin as I use a filtered query to keep an eye on Doctrine 2 related issues.

Coming in part 2…

Will either be based on feedback/suggestions (if any) or I’ll move on to some real world examples and best practices when it comes to integrating symfony and Doctrine 2.