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!

40 Responses to “GSoC, ZF & Doctrine”

  1. 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!

    Reply
  2. 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?

    Reply
  3. 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?

    Reply
  4. Author

    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.

    Reply
  5. 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

    Reply
  6. 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.

    Reply
  7. 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.

    Reply
  8. Author

    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.

    Reply
  9. Author

    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.

    Reply
  10. 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;
    }

    Reply
  11. Author

    RubenV

    Very good suggestion Lee, reduces the maintenance burden when you add a field. I’ve updated the article. Thanks!

    Reply
  12. 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.

    Reply
  13. 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?

    Reply
  14. SiteX

    Hi, RubenV. Great articles! I can translate it to Russian if you don’t mind.

    Reply
  15. Author

    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.

    Reply
  16. 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.

    Reply
  17. Author

    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.

    Reply
  18. 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?

    Reply
  19. Author

    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.

    Reply
  20. 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

    Reply
  21. 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.

    Reply
  22. 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?

    Reply
  23. Author

    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.

    Reply
  24. 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.

    Reply
  25. Author

    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.

    Reply
  26. 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
    :)

    Reply

Leave a Reply

  • (will not be published)