The Life of RubenV - Peachy Orange!
GSoC, ZF & Doctrine

Some updates from the past week:

Summer of Code
I have submitted my Google Summer of Code proposal for a Banshee project to the Mono Project. I might submit another one to GNOME (just in case), but only if I can work it out in greater detail. I don't want to waste reviewers time by sending in half a proposal.

Zend Framework & Doctrine
After trying out the Zend Framework (a PHP Application Development Framework) and Doctrine (a Object Relational Mapper for PHP) for quite some time, I wrote up an article on Integrating Zend Framework and Doctrine. If you want to play with some of the nicest PHP technologies currently around, check it out!

Oh and this is probably my first message to appear on planet.grep.be. Hi all!

doctrine, gnome, php, summerofcode, zendframework | Saturday March 29 2008 21:35
Comment from ryan
Great articles about ZF and Doctrine! I was trying to put them together, obviously you have showed me a good solution to it.
Thanks!
March 31, 2008 04:57
Comment from RubenV
Glad to be of help Ryan!
www.savanne.be | March 31, 2008 10:08
Comment from Ashley
I followed your tutorial which made a great deal of sense. Many thanks. However I have a question that I don't appear to be able to answer from the doctrine documentation (obviously not written for end users!):

I'm using the Zend recommended layout to split the application into modules e.g.
docroot/
index.php
application/
layouts/
modules/
default/
controllers/
IndexController.php
models/
Message.php
MessageTable.php
generated/
BaseMessage.php
views/
scripts/
index/
helpers/
filters/

and have put in the generated/ directory under models/ as required. Now, although teh application runs as expected using
$layout = Zend_Layout::startMvc($options);
$front->dispatch();

in the bootstrap

I get the following error when the page displays

Fatal error: Uncaught exception 'Doctrine_Exception' with message 'Couldn't find class Message' in /var/www/vhosts/dev/ak/library/Doctrine/Table.php:251 Stack trace: #0

Message.php is in the correct place according to your instructions (it all ran fine before I modularised everything).

Clearly this is an error in that Doctrine cannot locate Message.php to instantiate the Message class. My question is; How do I tell Doctrine where to look additionally for classes? Is there some function like the Zend $front->addControllerDirectory() in Doctrine that I can use to add module paths or do I have to put them into the library path? I'm a bit concerned that this latter method would fall over at some point because the library path becomes too long.

What are your thoughts?
April 16, 2008 09:03
Comment from DangerMouse
Hi there, firstly a great tutorial.

I've gone through this process a few months back, testing out doctrine with ZF and have a query I would like your thoughts on.

Do you think its undesirable to have to use a static call to Doctrine_Query in the Controller? Is'nt this the equivilant of having SQL code there?
April 19, 2008 00:48
Comment from RubenV
Sorry for the late comment, I was a tad busy this week.

Ashley: This is a problem indeed. As far as I know, there's no module support for Doctrine yet. Definitely something to look into though. For now, I'm afraid you'll have to expand the include_path, which is indeed a bit cumbersome.

DangerMouse: Good question! You can indeed compare this to having SQL code in there (with the exception that you're querying over objects instead of database tables). If you scale up your application beyond the one page example, it might be wise to group these queries into a Factory pattern. Doctrine 0.10 even generates Table classes which serve exactly this purpose. I heard they're going to be replaced by a different concept in the next Doctrine though.

Hope this was helpful, let me know if things are unclear.
www.savanne.be | April 19, 2008 16:50
Comment from guenti
Hi Ruben,

Your article is in my mind one of the best points to start working in combination of Doctrine and ZF.

I want to translate your article to german and will publishing this in my blog.
Is it okay for you?

Thanks and Greetings from Germany
April 20, 2008 11:54
Comment from RubenV
Guenti: No problem, let me know where it can be found and I'll add a link to it.
www.savanne.be | April 20, 2008 12:17
Comment from Ashley
RubenV: There is a way around the library path issue. You simply put all the models for all modules into a single directory (or two if you include the generated one.) A bit of a cludge but at least you can modularise even if only partially.
April 21, 2008 09:01
Comment from guenti
Hi Ruben,

it's done. I've finished the translation of your article and put it on the following link.
http://www.havelsoft.org/tutorials/ZF_Doctrine.pdf

Greetings form Germany
April 22, 2008 13:43
Comment from Montana
Was there any significance to your creating the doctrine folder in the application folder?

It seems to me that the other paths (data, migrations, and schema) would be fine in the root of the application folder.
montanaharkin.net | April 22, 2008 22:41
Comment from RubenV
Guenti: Cool! I'll add a link to the article.

Montana: No, it was all a matter of personal taste. For instance, the data directory might not be at the right place inside application/. It just grew while writing this, as there was no real convention yet. Definitely something to discuss and revise later on.

EDIT: corrected typo in name.
www.savanne.be | April 25, 2008 15:57
Comment from RubenV
There have been quite some spam mails getting through the filters recently, my apologies for the emails you've received because of that.

I've added a manual approval step to counter this.
www.savanne.be | May 18, 2008 10:26
Comment from Lee Saferite
Shouldn't this code:

public function indexAction()
{
$form = $this->getForm();
$req = $this->getRequest();
if ($req->getPost() && $form->isValid($req->getPost())) {
$message = new Message();
$message->name = $this->getRequest()->getPost('name');
$message->message = $this->getRequest()->getPost('message');
$message->posted = new Doctrine_Expression('NOW()');
$message->save();
}
$this->view->form = $form;

$messages = Doctrine_Query::create()
->from('Message m')
->orderBy('m.posted DESC')
->execute();
$this->view->messages = $messages;
}

Be like this:

public function indexAction()
{
$form = $this->getForm();
$req = $this->getRequest();
if ($req->getPost() && $form->isValid($req->getPost())) {
$message = new Message();
$message->fromArray($form->getValues(true));
$message->posted = new Doctrine_Expression('NOW()');
$message->save();
}
$this->view->form = $form;

$messages = Doctrine_Query::create()
->from('Message m')
->orderBy('m.posted DESC')
->execute();
$this->view->messages = $messages;
}
June 18, 2008 05:40
Comment from RubenV
Very good suggestion Lee, reduces the maintenance burden when you add a field. I've updated the article. Thanks!
www.savanne.be | June 18, 2008 10:16
Comment from Lee Saferite
It also has another added possibility. If you use sub forms and set the sub form name the same as a Relation on your Doctrine_Record object (User['Address'], subform would be called 'Address') then you could simply call: $user->fromArray($form->getValues(true), true); to do a deep merge. It would update you user entity AND the linked address entity. When you call $user->save(), it would update the entire object graph.
June 18, 2008 14:53
Comment from Ted
When i follow the article over integrating Zend Framework and Doctrine i get an error when executing the command from shell.

Here is what i get:
root@lamp:/var/www/html/zf_doctrine/scripts/doctrine-cli generate-models-yaml
-bash: doctrine-cli: command not found

What could be the problem?
June 23, 2008 23:03
Comment from RubenV
Ted: Either the script isn't in the right place, or it's not set to executable.
www.savanne.be | June 24, 2008 02:19
Comment from SiteX
Hi, RubenV. Great articles! I can translate it to Russian if you don't mind.
July 5, 2008 20:38
Comment from RubenV
SiteX: Feel free to do so as long as you mention my name & website. And let me know where it is, so I can link to it.
www.savanne.be | July 5, 2008 20:59
Comment from Oleg Lobach
Hi Ruben,

I translate this article to Russian. You can see it in my blog - http://lobach.info/develop/zf/integrating-zend-framework-and-doctrine/

Thanks for very clear and usefull article.
lobach.info | July 20, 2008 20:17
Comment from RubenV
Thank you very much Oleg! I added a link to your translation in the article.
www.savanne.be | July 21, 2008 01:28
Comment from gigistouch
Thanks for this great tutorial! Zend framework with Doctryne is so powerfull! ;)
November 16, 2008 22:51
Comment from Oguzhan
Hi Ruben,
I looked at the creation time of your article and nearly 6 months have been passed since you wrote it . The only article using ZF and Doctrine is yours. There is not so much resource in the web. Thanks for your great share. I want to translate it to Turkish if you don't mind.
November 17, 2008 07:59
Comment from RubenV
Oguzhan: Glad that you like it! Feel free to translate it, as long as you link back to me (let me know where it's located so I can link it).

I should probably set up a translation framework to host these translations on my server. That way I'll be able to track how up-to-date these translations are. I love having them around in multiple languages, but it's not useful if that means we'll end up with 20 different versions on the web.

Something to do when things are less busy :-).

I should probably also bring the article up to date with recent versions of ZF and Doctrine.
www.savanne.be | November 23, 2008 15:15
Comment from Willem Luijk
Hi Ruben,

Nice tutorial. I am working offline on Windows and miss the client to compile yml to php. Is there a solution for? Do i need to download the sandbox instead?
March 3, 2009 21:10
Comment from RubenV
Willem: Doesn't really matter if you install the sandbox, or the script from the article, both'll give you the same kind of environment. The only difference is that the sandbox comes with a prepackaged sqlite database, so that you don't need to install a mysql database on your system. You can change the config in the article quite easily to use sqlite though.
www.savanne.be | March 4, 2009 00:35
Comment from RubenV
For windows users, make sure php.exe is added to your PATH environment variable. Then start the cli script by using

php scripts/doctrine-cli

More info here: http://be2.php.net/cli
www.savanne.be | March 6, 2009 12:37
Comment from will
Hi, I'm trying to follow this through with a zf1.8 application, having used the zftool to create my project.

Its going ok, but i'm getting a "There is no open connection" error. I reckon thats because i have no idea where to put this line:

Doctrine_Manager::connection("mysql://root:root@localhost/track");

in the new bootstrap class. Any pointers would be really appreciated. Or are you planning to update the tutorial to the new 1.8 architecture?

Thanks,

Will
May 27, 2009 09:00
Comment from will
ok, self rescue: I put this in my bootstrap class, zf seems to call it for me

protected function _initDatabase()
{
Doctrine_Manager::connection("mysql://root:root@localhost/track");

Zend_Registry::set('doctrine_config', array(
'data_fixtures_path' => dirname(__FILE__).'/doctrine/data/fixtures',
'models_path' => dirname(__FILE__).'/models',
'migrations_path' => dirname(__FILE__).'/doctrine/migrations',
'sql_path' => dirname(__FILE__).'/doctrine/data/sql',
'yaml_schema_path' => dirname(__FILE__).'/doctrine/schema'
));
}


Then in index.php, i added the generated models path, cos the models file structure / class names don't match ZF's autoloading pattern (?)

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
realpath(APPLICATION_PATH . '/models/generated'),
get_include_path(),
)));

oh, its not just generated, so just for a little variation, i added to the incude path in the config by sticking this line in the ini

includePaths.model = APPLICATION_PATH "/models"

presumable ZF adds any includePaths.whatevers to the path, why not say that in the comments is a bit of a mystery to me, i guess they only want *really clever* developers using it. grumble grumble.
aSecondWill.com | May 28, 2009 06:59
Comment from will
Hay, out of interest. you can't really have zend_db models anymore right? wouldn't it be better to have the doctrine models in their own folder? maybe inside the models folder?
aSecondWill.com | May 28, 2009 10:05
Comment from RubenV
I need to update the article for ZF 1.8, but that won't be for any time soon, as I'm bogged down by my masters thesis.
www.savanne.be | May 30, 2009 19:01
Comment from danceric
Hi Ruben, I have updated the instruction here for ZF 1.8 at http://www.danceric.net/2009/06/06/doctrine-orm-and-zend-framework/
feel free to take anything you want if you want to update your great post.
www.danceric.net | June 6, 2009 14:14
Comment from RubenV
@danceric: Cool! Thanks, that'll help to keep people going!
www.savanne.be | June 7, 2009 00:10
Comment from Yuta
Hi Ruben,

I translated your nice tutorial into Japanese and published it.
http://studiokdf.com/blog/2009/06/66.html

Thanks.
studiokdf.com/blog | June 9, 2009 15:39
Comment from Lisa Ridley
Hey! Love your tutorial; however I was getting a PHP Notice when trying to use Doctrine 1.1.3 and Zend Framework 1.8.2 together:

Notice: Zend_Loader::Zend_Loader::registerAutoload is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead in [...]/library/zendframework/Zend/Loader.php on line 207

which stack-traces back to the following line in /application/global.php:

Zend_Loader::registerAutoload('Zend_Loader');

After doing some research it appears that this notice was introduced as of Zend Framework version 1.8 due to the deprecation and future removal of the autoloader feature of Zend_Loader. The fix I found is as follows:

Replace the following lines in /application/global.php:

require_once('Zend/Loader.php');
Zend_Loader::registerAutoload('Zend_Loader');

with these:

require_once('Zend/Loader/Autoloader.php');
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

and your tutorial will run properly, although I don't have a full understanding of the implications of the change since I"m not really clear on why the autoload mechanism in Zend_Loader is being deprecated to begin with, although I think it's related to the introduction of Namespaces in php 5.3.0, and future enhancements to support them properly in the Zend Framework.

A second issue that arose is the following notice when error reporting is set to include E_STRICT:

Strict standards: Only variables should be passed by reference in [...]/library/doctrine/Doctrine/Query.php on line 1187

which appears to be triggered by a call to Doctrine_Query::execute(), as occurs in IndexController::indexAction() on the following lines:

$message_query = Doctrine_Query::create()
->select()
->from('Message m')
->orderBy('m.posted DESC');
$messages = $message_query->execute();

Again, not alot of information, although this appears to be triggered by Doctrine itself.

Great tutorial, by the way.
September 21, 2009 23:42
Comment from Dieter
Great tutorial, it really helped me out in my setup.
More of these after the Master thesis? ;-)
www.dieterprovoost.be | November 8, 2009 09:18
Comment from RubenV
Master thesis has been finished for quite some time now. Right now it's the PhD that's keeping me from updating this to ZF 1.10.
www.savanne.be | November 8, 2009 13:26
Add a comment:
Name
Email (optional)
Website (optional)
Remember my personal details
Email me when there are new comments
Comment
The author:
RubenV
Ruben Vermeersch
Computer Scientist (Software Engineering), GNOME Hacker, PhD Researcher, Photographer, Earthling
More info | Tweets
You are here:
I speak:
More:
The past: