Archive for June, 2009

Lazy class loading with Zend_Loader_PluginLoader

without comments

In applications built on top of a library of reusable code, you may want to load your custom class components before those of the library. For example, your library has a user model of Lib_Model_User. In general, this class is enough for your needs, but for a particular case, you’d like to use a custom implementation specific to your application called Custom_Model_User. Furthermore, say you have a controller that needs the user model to perform some action, say Lib_Controller_User. Typically, your code for that controller might look something like this:

1
2
3
4
5
6
7
8
9
10
class Lib_Controller_User extends Lib_Controller
{
    public function registerAction()
    {
        if (!empty($_POST)) {
            $model = new Lib_Model_User;
            $model->save($_POST);
        }
    }
}

For your particular app, you want to use Custom_Model_User instead of Lib_Model_User… in order to do this, you’d probably subclass Lib_Controller_User and override the registerAction method. This definitely works, but there are a few better ways.

You could inject the model at some point before registerAction gets run. This might look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Lib_Controller_User extends Lib_Controller
{
    protected $_model = null;
 
    public function __construct($model = null)
    {
        if ($model === null) {
            $model = new Lib_Model_User;
        }
        $this->setModel($model);
    }
 
    public function setModel($model)
    {
        $this->_model = $model;
    }
 
    public function registerAction()
    {
        if (!empty($_POST)) {
            $this->_model->save($_POST);
        }
    }
}
 
// In your bootstrap process
$user_controller->setModel(new Custom_User_Model);

This works fine, but I think that Zend_Plugin_Loader gives you a much nicer way of achieving this. Here is the same code refactored to use the plugin loader instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Lib_Controller_User extends Lib_Controller
{
    protected $_modelLoader = null;
 
    public function registerAction()
    {
        if (!empty($_POST)) {
            $this->_getModel('user')->save($_POST);
        }
    }
 
    protected function _getModel($name)
    {
        if ($this->_modelLoader === null) {
            $pl = new Zend_Loader_PluginLoader;
            $pl->addPrefixPath('Lib_Model', 'Lib/Model/');
            $pl->addPrefixPath('Custom_Model', 'Custom/Model/');
            $this->_modelLoader = $pl;
        }
        $model = $this->_modelLoader->load(ucfirst($name));
        return new $model;
    }
}

This will first look to see if Custom_Model_User exists, if it’s not found, it will load Lib_Model_User instead. It lazy loads your models using the order you specify. This makes your controller a lot more reusable and cuts down on the amount of bootstrap code you need. Note, if you wanted to use this in a real world scenario, you’d probably want to specify your custom loader paths through configuration instead.

Zend Framework makes use of plugin loaders quite a bit. Zend_Form is a great example because it allows you to specify where to load elements when using the available factory methods like Zend_Form::createElement and Zend_Form::addElement. Doing this makes code much more flexible, I like the approach.

Written by steve

June 18th, 2009 at 9:45 pm

Posted in PHP, zend framework