Added by Graham Anderson, last edited by Jurrien Stutterheim on Oct 31, 2008  (view change)

Labels

 
(None)

Zend Framework: Zend_Controller_Action_Helper_ResourceLoader Component Proposal

Proposed Component Name Zend_Controller_Action_Helper_ResourceLoader
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Controller_Action_Helper_ResourceLoader
Proposers Graham Anderson
Zend Liaison TBD
Revision 1.2 - 9th Sept 2008: Initial Draft. (wiki revision: 8)

Table of Contents

1. Overview

The goal of this helper class is provide a standard way to load and share resource classes between Zend Framework modules where the application developer wishes to store such classes inside the module directory. This will help application developers create re-usable modules containing discreet functionality which in turn will benefit the Zend Framework community through greater code sharing.

Currently to share model and form classes among ZF MVC modules, a developer must typically use one of two strategies.

1. Develop his/her own loader class, perhaps extending or using Zend_Loader and using path spec functionality or maybe using the PluginLoader, or do some other thing like manipulate include paths via a dispatch loop plugin.

2. Store models, forms and other classes outside of a module directory, this allows quite easy sharing of resource type classes between modules, but increases the complexity of using re-using modules.

While these strategies work they are many and varied and there is no current official helper that performs loading functionality.

This class will provide a ZF standard way to load models, forms and other resource classes that are stored inside the module directory.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will extend Zend_Controller_Action_Helper_Abstract
  • This component will use Zend_Loader_PluginLoader
  • This component will load model, form and other class files and definitions into the current php execution cycle
  • This component will provide a mechanism for custom resource types and related plugin loaders.
  • This component will return class names of loaded resource classes
  • This component will not instantiate or return objects

4. Dependencies on Other Framework Components

  • Zend_Loader_PluginLoader

5. Theory of Operation

Consider an MVC application with the following 'users' module. Instead of storing the models and forms in a more general location e.g. application/models, application/forms or My/Forms/MyForm.php, storing the resource classes under the module reduces complexity for re-using and sharing modules.

It should be noted that this directory structure need not be used but is provided for the sake of example, though it is intended for a default module directory to be used for model and form resources.

application/
    modules/
        default
        users/
            controllers
            forms/
                LoginForm.php
                AccountDetailsForm.php
                RegisterForm.php
            models/
                UserModel.php
                GroupModel.php
            db/
                UserTable.php
                UserTableRow.php
            views

Resource class naming

Example class naming using resources from the above example. Classes are named to provide information as to which module and resource type they belong to e.g. Modulename_Resourcetype_* this also reflects the function of the resource class and the general location within the module.

This allows us to use data containing details of known application modules and this helpers internal list of known resource types to assemble prefixes for each plugin loader.

Now our loader helper class can use prefix paths and the Zend_Loader_PluginLoader class to load these resource classes.

6. Milestones / Tasks

  • Working prototype [DONE] http://andtech.googlecode.com/svn/trunk/
  • Draught initial proposal [DONE]
  • Collect initial feedback and refine proposal/prototype
  • Submit proposal for review
  • Pending review outcome - inclusion to laboratory/incubator
  • Docs & unit tests

7. Class Index

  • Zend_Controller_Action_Helper_ResourceLoader

8. Use Cases

UC-01

See theory of operation, further use cases to follow

9. Class Skeletons

Zend_Controller_Action_Helper_ResourceLoader

I very much like the idea of thie proposal. I do not like the naming conventions you suggest. I'd prefer something along the line of:

  • Users_Form_Login
  • Users_Table_User
  • Users_Model_User
  • Users_Model_Group

This better reflects both the directory hierarchy and the taxonomy of the classes.

That sounds sensible but just to clarify, do you mean for a class to be loaded in this fashion:

or in this way:

Using $dirs = Zend_Controller_Front::getInstance()->getControllerDirectory(); provides initially a rather handy associative list of module names and paths, so it's simple to use either "Users_" or "Users_Model_" as the prefix for the plugin loader prefix paths stack.

I actually like both. BTW, Zend_Controller_Front has a getModuleDirectory() method now that maps modules to the base directory of the module (not the controllers directory).

Part of the reason I suggest this change it possible for you to use the PluginLoader easily with the component – if the class names follow this format, you can easily specify different plugin resource types, and have it automagically do lookups. Additionally, this would allow somebody else to create a component using a PluginLoader that can find the same set of classes. Alternately, a developer could write up their own PluginLoader implmentation (we have a PluginLoader interface) and attach it to the component – giving full customization.

Matthew, do you think it's to late or unnecessary to introduce a Directory class or something else to deal with directory names and paths? I've spent some time working with legacy code and migrating applications and I think it could be very helpful. Having the getModuleDirectory() method inside the front controller doesn't help much, because although I can extend the Zend_Controller_Front class, other ZF components will still be getting an instance of the parent class: Zend_Controller_Front::getInstance(). That's one of the reasons why I suggested moving all this to a different class, that way the front controller delegates this responsibility to the Directory object and we can extend it.

Ifind your proposal interesting, but it's not something we can introduce until 2.0 at the earliest – it represents a fairly large BC break, even if it makes the component more flexible.

We'll discuss more on this in the coming months.

In the first version of my prototype code for this, when I had initially kept the domain of the helper to models only, I had additional setters/getters and configuration of the PluginLoader, with a view to allowing developers to use their own plugin loader.

I'd removed them as the domain of the loader helper changed from models only to models + forms + X. I wanted to keep the initial proposal as simple as possible. However I think that as long as the customization is limited to specifying additional resource types (with optional custom plugin loaders using the implementing the interface) adding this would not only be desirable but perhaps should be a requirement of the design/proposal.

So unless there's more comments on the naming of the resource classes, I'll update the proposal later today to reflect encouraging or enforcing prefixes/class names in the form Modulename_Resourcetype_* for at least the default functionality (models & forms).

By the way, the way we accomplished multiple plugin types in Zend_Form was to have multiple plugin loaders I would suggest going this route with ResourceLoader.

Question: how does the resource loader know what module to load the resource from?

An associative array of prefixes and paths is assembled for each resource type, this will be used by a plugin loader object which assembles the class name, checks to see if the class exists already and so on and if not loads it. The prefix will contain the name of the module, the classname will also contain the name of the module as the prefix must match a substring of the resource class name. This is similar to the way in which other plugin classes are loaded elsewhere in the framework.

Module names and paths to modules are derived from querying the front controller object.

http://framework.zend.com/apidoc/core/Zend_Loader/PluginLoader/Zend_Loader_PluginLoader.html

As stated in the proposal, the resource loader would be dependent on Zend_Loader_PluginLoader, or at very least a plugin loader implementing Zend_Loader_PluginLoader_Interface.

Posted by Graham Anderson at Aug 27, 2008 19:12 Updated by Graham Anderson

Proposal updated to v1.1

  • Added requirement to allow for custom resource types/plugin loaders
  • Changed naming of example resource classes, added short note on rational behind class naming
  • Updated example of using loader in theory of operation

If there are no further comments at this stage on naming, scope of operation, customization I'll aim to modify the class skeleton and publish a prototype within a day or so. Use cases will be added at this point.

Proposal updated to v1.2

Restricting loading to the current module and/or specifying the module to load from is implemented in the most basic fashion in the prototype. While the way it works in the prototype could obviously be improved, it looks like there's a valid argument for perhaps using a different implementation of Zend_Loader_PluginLoader_Interface, or perhaps a more structured definition of a "resource type" within a class of it's own. This would perhaps allow greater flexibility for customizing resource loading.

Hi Graham,

Your proposal looks good. Am I correct in assuming it's pretty much "done", seeing as it hasn't received updates in a while? If so, I'm actually considering implementing your prototype in an application. In any case you should definitely move your proposal to Ready For Review. Although, judging from the state of the proposal and comments, you might just as well move it to Ready For Recommendation directly

P.S.: I've moved it to Ready for Review for you

A question that just occurred to me... why is this an action helper? There are probably other instances where you will need to load models as well. For example, in other models.

Having an action helper for this makes complete sense and is a good thing. However, I would like to propose that this functionality is refactored into Zend_Loader_ResourceLoader and the ResourceLoader action helper actually uses the Zend_Loader_ResourceLoader.

In theory the Controller updates and moves data between models, so you should delegate this responsibility to the Controller. There's some logic behind this, the direction of the data flow defines how data flows through the system, therefore it makes the system easier to understand and maintain.