Januar 31st, 2010
While playing a bit with Doctrine ORM (1.2.1) for PHP, I encountered problems with autoloading my model classes. The autoload mechanism is described here. But as far as I see they changed this behaviour in doctrine 1.2.x but they didn’t updated the documentation yet. So it took me a while to find a solution. Here are the steps to reproduce the problem and my solution for this. I have simplified the original steps from the doctrine documentation a bit.
First I created a `user` table in the database:
CREATE TABLE IF NOT EXISTS `user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `username` VARCHAR(255) COLLATE utf8_unicode_ci DEFAULT NULL, `password` VARCHAR(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
In the next step I created the model classes using doctrine. First we’ll create a little bootstrap script that contains the database and doctrine configs and later on the model generator script itself.
<?php // bootstrap.php // make sure you have the doctrine package in your classpath (!) require_once 'Doctrine.php' spl_autoload_register(array('Doctrine', 'autoload')); $dsn = 'mysql:dbname=doctrine_test;host=127.0.0.1'; $user = 'user'; $password = 'secret'; $dbh = new PDO($dsn, $user, $password); $conn = Doctrine_Manager::connection($dbh);
… and here comes the model genarator script:
<?php // generate_model.php require_once 'bootstrap.php'; // this method does the dirty work Doctrine::generateModelsFromDb( 'models', // the folder where the classes should be stored array('doctrine_test'), // array with database names array('generateTableClasses' => true) // array with options ); ?>
Then I run the script via php-cgi and doctrine created the following model class files for me.
$ php generate_model.php $ find models/ -type f | sort models/generated/BaseUser.php models/User.php models/UserTable.php
All runs fine until here. Now I tried to write a bit of code to insert a new user into the database. As the doctrine documentation says we have to modify the bootstrap.php a bit to set the model loading option to ‚lazy-loading‘, and add the
<?php require_once 'Doctrine.php'; spl_autoload_register(array('Doctrine_Core', 'autoload')); $manager = Doctrine_Manager::getInstance(); // set the model loading attribute to lazy loading // @see $manager->setAttribute( Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE ); // load the model classes from the folders 'models' Doctrine::loadModels('models'); $dsn = 'mysql:dbname=doctrine_test;host=127.0.0.1'; $user = 'user'; $password = 'secret'; $dbh = new PDO($dsn, $user, $password); $conn = Doctrine_Manager::connection($dbh);
Now we write a simple save_user.php which uses the User model – class generated by doctrine and which should be ‚auto-included‘ by the
Doctrine class. (Remember, we don’t need a
<?php // save_user.php require_once 'bootstrap.php'; $user = new User(); $user->username = 'thorsten'; $user->password = 'secret'; $user->save(); printf("New user created. id: %d\n", $user->id); ?>
But when I run the save_user.php via cli I got the following error:
$ php save_user.php Fatal error: Class 'User' not found in /var/www/doctrine/save_user.php on line 7
Boom!. The autoload mechanism seems not to work!
But thanks to the open source licence of doctrine I digged a bit in the code and found a change between the 1.1.x version of
Doctrine::autoload and the version 1.2.x one. Remember, we have registered this method in boostrap.php as the autload method.
// bootstrap.php // ... spl_autoload_register(array('Doctrine', 'autoload')); // ...
In prior 1.2 version the method was responsible for (auto)loading of Doctrine framework classes such as
Doctrine_Manager and for autoloading the model classes. In the new version the method is only responsible for framework classes. But digging a bit more I found a solution
If you want to autoload your model classes via doctrine you have to register
Doctrine::modelsAutoload() too. This method is responsible for model classes. Modify your boostrap.php..
// bootstrap.php // ... spl_autoload_register(array('Doctrine', 'autoload')); spl_autoload_register(array('Doctrine', 'modelsAutoload')); // ...
And when you now run save_user.php…
$ php save_user.php New user created. id:1
.. the User class was auto imported by the doctrine framework.. .