Labels
| Proposal Superceded This proposal has been superceded by the Zend_Loader_Autoloader_Resource proposal. |
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 | Matthew Weier O'Phinney |
| Revision | 1.2 - 9th Sept 2008: Initial Draft. (wiki revision: 12) |
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 / Zend_Loader_PluginLoader_Interface
- 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
| Useful Information To fully satisfy some of the requirements from comments, it may be necessary to implement the plugin loader interface and consume a loader class with functionality more suited to the scope of this proposal. |
4. Dependencies on Other Framework Components
- Zend_Loader_PluginLoader / Zend_Loader_PluginLoader_Interface
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 [DONE]
- Submit proposal for review [DONE]
- 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
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.
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).
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.
13 more comments by: Aaron Heimlich, Matthew Weier O'Phinney, Maurice Fonk, Federico Cargnelutti, 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
- Modified class skeleton to reflect previous comments
- Prototype published to SVN - http://andtech.googlecode.com/svn/trunk/
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 ![]()
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.
There's a couple of things that might make more sense to have in another class consumed by the action helper. Your point about loading models from models is noted, thanks. I'll wait and see how this goes forward in the proposal process as I feel this proposal is fleshed out enough for consideration at this point.
| Zend Comment This proposal is being superceded in large part by Zend_Loader_Autoloader_Resource - Matthew Weier O'Phinney; our recommendation is for Graham to work with Matthew to see that proposal to completion. In the meantime, this proposal will be archived, and a note added to it pointing reviewers to the new proposal. |
ZF Home Page
Code Browser
Wiki Dashboard
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:
This better reflects both the directory hierarchy and the taxonomy of the classes.