Deep Integration between Zend and Doctrine 1.2

January 13th, 2010

There’s been a lot of talk online about finding the best approach for bringing Zend and Doctrine 1.x together. This video is my humble approach of combining some of the learning brought about over the last few weeks on Zendcasts, as well as suggestions from Doctrine developers.

The goal of this video is to show how you leverage the existing resource loading tools in Zend to have a model structure that reflects Zend’s best practices. This video builds on the last Doctrine video, but if you’re familiar with both frameworks, you should be able to follow along. Enjoy!

Grab a copy of the project or browse the repository.

Also, a big thank you to ServerGrove for extending their support of Zendcasts for January. ServerGrove specializes in Zend Framework hosting and they’ve offered a 10% rebate on hosting with coupon code “zc”. If you’re looking for a host, be sure to check them out. They’ve also added an additional coupon for “Mini Hosting” plans, get $2 off by using code “zcmini”.

 

discuss video in the forum

31 Responses to “Deep Integration between Zend and Doctrine 1.2”

  1. nORKy says:

    Good job.

    This is some tips :

    you don’t need to set ‘aggressive’ for the cli and ‘conservative’ for the ‘http’ request.
    You don’t need to use Doctrine.php
    You don’t need to copy/link vendor.

    how ?

    In _initDoctrine :
    remove
    Doctrine,autoload and modelsAutoload

    add (need only for the class ’sfYmal’ )
    $this->getApplication()->getAutoloader()->pushAutoloader(array(‘Doctrine_Core’, ‘autoload’));

    add
    $manager->setAttribute(Doctrine_Core::ATTR_MODEL_CLASS_PREFIX, ‘Model_’);

    update
    $manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_PEAR);

    update all ref Doctrine to Doctrine_Core

    That’all.

  2. Jeremy Hicks says:

    Why did you create the _initAppAutoload method?

  3. jon says:

    this ensures that we get the proper Model_ loading behaviour since models are considered a “resource” in Zend (like the application/forms/ folder contains Form_ objects.) Not sure if this is a hold-over or if ZF is moving more in this direction though…

  4. umpirsky says:

    Isn’t the right way for setting up doctrine implementing application resource, instead having _initDoctrine in your bootstrap?

  5. [...] on the ZendCasts.com site is this recent screencast about the best approach for integration of the popular Doctrine ORM and the Zend Framework. his [...]

  6. jon says:

    @umpirsky: The application resource is a good move, however it adds yet another level of indirection, which when you’re trying to get the two frameworks to work properly initially, can simply add confusion. I’ve seen implementations of the application resource, however if you’re not going to be running the resource in more than one place and its a database-driven website, what’s the point?

  7. vlad says:

    I watched all the casts from this awesome site, and just wanted to thank you for what you’re doing!!!

  8. Jeremy Hicks says:

    In the past I have used

    Doctrine_Core::loadModels($doctrineConfig['models_path']);

    in my _initDoctine method instead of creating the _initAppAutoload method. I guess that’s where my confusion came from. Any real difference behind the scenes between the two approaches?

    Great screencast! Keep them coming.

  9. ahue says:

    Hm… everything worked fine (except of the things you already mentioned) until I changed from CONSERVATIVE to AGGRESSIVE when using CLI. Now when I have deleted all Model and Base/Model classes and run build-all-reload it works, DB is created, tables are creates, fixtures are filled and the Application runs without erros afterwards. BUT if I do changes to the schema and want to run build-all-reload again (now Models and auto-generated Base Model files exist) I get a fatal error:

    Fatal error: Class ‘Model_Base_Album’ not found in C:\…\Album.php on line 14

    So the generated Base Models are not found. Can anyone help me with this?

  10. ahue says:

    Unbelievable… I renamed “Album” to “Music” and it worked? WTF???

  11. Jochen says:

    @ahue

    I think the reason could be that aggressive loading just recurses through your models directory and loads everything it finds. Since “Album” is alphabetically before “Base”, the Base_ classes just aren’t loaded yet when it gets to Album.php. When it loads Music.php, it has already recursed into the Base directory and loaded the base classes.

    WTF???

  12. Mischosch says:

    Hehe, the “a” Problem. Every Model starting with an a causes that problem. Give it a try, strange voodoo!

  13. Sandor says:

    Hi, after I’ve set the model loading to aggressive creating the tables failed silently. I figured out that there is an issue with class_exists php internal function at line 782 in doctrine_core class’s isValidModelClass function. Somehow it throws a silent error that preventing to function properly I replaced it with “in_array($class, get_declared_classes())” and the tables have been created successfully. That’s probably my compiled MAMP 1.8.2 or ZF’s (1.9.5) autoload mechanism related bug or something other.

    If somebody encountered the same problem maybe that helps.

    r. Sandor

  14. the.ufon says:

    same problem.. I need at least three models beginning at ‘a’, so it’s quite fed-upping every time delete this three models and recovering all methods after rebuild models or db..

    any solution Jon? :) )

  15. jon says:

    that’s a pretty strange bug! I’d try and hold out for Doctrine 2 if I could… The Doctrine team is pretty responsive as well, I would shoot them an email or check the bug tracker.

  16. tobias says:

    Hi Jon, thanks for your casts, they are very interesting. But after the “deep integration” of doctrine my phpunit test fails.

    “create-tables – Created tables successfully
    SQLSTATE[42S02]: Base table or view not found: 1146 Table ‘apptest.car’ doesn’t exist”

    My database “apptest” ist created but there is no table in it.

    greeting
    tobias

  17. [...] figure out what was going on, not to find a solution, I did that downloading the application from here and looking into their code.) This will get rid of the generated folder and instead create all base [...]

  18. Ryan Horn says:

    Tobias, try putting

    doctrine.model_autoloading = 1

    in your “testing” section of application.ini if it’s not there already.

  19. [...] Jon Lebensold hat ein Video über die Integration von Doctrine 1.2 veröffentlicht. [...]

  20. Fernando says:

    Hello, nice tutorial. I ran into some troubles, the Cli just couldn’t run when the models were already generated. It just kept throwing exceptions that “Model_Base_MyTable” wasn’t found. To solve it i added the following code in the cli “scripts/doctrine.php”: $application->getBootstrap()->bootstrap(‘autoload’);

    Just before the bootstrap of ‘doctrine’.

    Thanks, Regards.

  21. mysticav says:

    I’m having a BIG issue with phpunit and doctrine (deep integration).

    Baically, the problem happens when I run phpunit and the code coverage report takes
    place.

    It starts by looking the classes in models directory.

    When it finds the first class, let say “User”
    and because “User” class is defined as
    “Model_User extends Model_Base_User”

    it throws an error:
    “Generating code coverage report, this may take a moment.
    Fatal error: Class ‘Model_Base_User’ not found in [mypath]\application\models\User.php on line 14″

    Jon, Can you please let us know what changes we should make in “tests/boostrap.php” so we can follow this video without break our phpunit testing capabilities ?

    A very dirty solution could be adding a “require_once(Base/User.php)” in the Model File. Unacceptable solution, indeed.

  22. Rafa says:

    Hi everyone!

    Just a question a little bit offtopic:

    Is there any way to pass the doctrine_collection object to a partial (partialLoop)? It seems that it implements iterator, but I can’t use the objects (car and user) into the “partial” code. Should I use the foreach statement and forget the partialLoop?

    Thanks a lot

  23. Funk Face says:

    Great work here, this page has really helped me get going with Zend/Doctrine integration, thanks.

    I think the problem with using Doctrine_Core::MODEL_LOADING_PEAR with CLI mode originates in scripts/doctrine.php where you do:

    $application->getBootstrap()->bootstrap(‘doctrine’);

    This calls _initDoctrine() but never _initAppAutoload(). The best way to correct the situation is to add this line to _initDoctrine():

    $this->bootstrap(‘appAutoload’);

  24. Sirio says:

    Very good job, but what about doctrine extensions? How to autoload them?

  25. Jeremy says:

    @Funk Face
    Your comment was a life saver!

    I would do one thing differently though. Since all _init methods get run on each request, instead of adding that line to the _initDoctrine method, I just took the contents of my _initAppAutoload method and stuck them at the beginning of _initDoctrine. This way the _initAppAutoload code only gets run once inside a normal application (not cli).

    @jon
    I find myself continually returning to your site as a reference. Thanks for all the hard work!

  26. Tobi says:

    Nice Vid!
    I am also working on a Doctrine 1.2 / ZF integration right now.
    I have used Doctrine for the past 2 years now (before 1.0). You don’t have to write your own findAll function, doctrine has one fore you (http://www.doctrine-project.org/projects/orm/1.2/docs/manual/dql-doctrine-query-language/en#magic-finders)
    in your case u can simply write:

    Doctrine_Core::getTable(‘Model_Car’)->findAll();

    which will also work if you do not have generated the Table class.

    most of the time i use this only for building the views, cause i need to add some filtering and ordering to the queries

  27. Patois says:

    Hi there!

    Great casts here. So far they’ve been really helpful. I’ve got a question though.

    I’ve integrated Doctrine & Zend and I changed the class prefix for the Doctrine models to Model_ as suggested in this cast.

    I’m wondering if it is somehow possible to configure Doctrine to use that standard class prefix, so I can use the ‘old’ class names in my queries without the prefix (i.e: User instead of Model_User)?
    I can relate to the $user = new Model_User() as a classname, but somehow I find the Doctrine::getTable(‘Model_User’)->findAll(); statement a bit odd.

    I’d prefer the Doctrine::getTable(‘User’)->findAll(); statement with Doctrine configured to add the class prefix Model_ automatically.

    Does anyone know if this is possible? Any help would be appreciated…

  28. Arthur says:

    Great video.

    I’m having tons of trouble getting this working. I have latest Zend (1.10.x) and Doctrine (1.2) and I can’t get it working. NOTE: I’m on Windows.

    I keep getting:
    LogicException: Passed array does not specify an existing static method in C:\verisign\trusted\application\Bootstrap.php on line 15

    and Warning: include_once() [function.include]: Failed opening ‘Doctrine.php’ for inclusion

    I have under /library
    /library/Zend
    /library/Doctrine

    Any suggestions?

  29. Arthur says:

    I think I fixed this. I just needed to change many of the references in bootstrap from Doctrine to Doctrine_Core.

  30. Miha says:

    Hi!

    Great casts! Thank you for them!
    Can you make Doctrine 2.0 integration video?

Leave a Reply

Desktop RSS feed iPhone + iPod