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!
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!
RubenV
Glad to be of help Ryan!
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?
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?
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.
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
RubenV
Guenti: No problem, let me know where it can be found and I’ll add a link to it.
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.
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
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.
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.
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.
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;
}
RubenV
Very good suggestion Lee, reduces the maintenance burden when you add a field. I’ve updated the article. Thanks!
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.
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?
RubenV
Ted: Either the script isn’t in the right place, or it’s not set to executable.
SiteX
Hi, RubenV. Great articles! I can translate it to Russian if you don’t mind.
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.
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.
RubenV
Thank you very much Oleg! I added a link to your translation in the article.
gigistouch
Thanks for this great tutorial! Zend framework with Doctryne is so powerfull! ;)
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.
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.
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?
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.
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
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
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.
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?
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.
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.
RubenV
@danceric: Cool! Thanks, that’ll help to keep people going!
Yuta
Hi Ruben,
I translated your nice tutorial into Japanese and published it.
http://studiokdf.com/blog/2009/06/66.html
Thanks.
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.
Dieter
Great tutorial, it really helped me out in my setup.
More of these after the Master thesis? ;-)
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.
Abhishek Kushwaha
Yes Ruben,
please make it as soon as possible…..
I am eagerly waiting for the assistance in integrating ZF 1.10 and Doctrine 1.2.2
:)
stackongunsafe
Hello RubenV
Thank you for good tutorial but I found the git server not work.
Do you have the other place to download the code
Ruben
I’ve put a copy online over here: http://ruben.savanne.be/files/articles/integrating-zend-framework-and-doctrine/chatapp.zip
Enjoy!