CakePHP: Delegating Actions to Separate Classes
I have just finished one of my most important modifications to CakePHP. In my old framework, I used a similar pattern where in a request is handled as a “mode” plus an “command” with optional parameters. This is similar in spirit to CakePHP’s controller/action way of doing things. In my implementation however, commands (analogous to CakePHP actions) are implemented using separate classes.
While some may argue that this manner of implementing MVC is overkill in typical applications, in very large applications (like PhilWeavers.net) it leads to very quick turn-around when it comes to adding new actions or modifying existing ones.
The full ChangeLog entry pretty much sums it all up:
This modification allows the client code to implement actions in separate classes. It is comprised of two parts:
A custom dispatcher capable of loading an Action class if action is not found to be in the controller’s methods.
An Action base class.
Rationale:
Implementing actions as methods of the controller class can become unwieldy especially with very large applications. Most of the time, only one of those action methods is invoked. The PHP engine still has to parse through the whole controller class file.
By moving out the actions into separate class files that are loaded on demand the overhead of parsing through a large file consisting mainly of dead code is avoided.
Because an action class is self-contained, it is now safe to implement a more structured approach in implementing methods through the use of small helper methods in the action class.
Full Description:
First and foremost, the goal of this modification is to be backwards compatible with existing code. This will help in migration towards using action classes.
Secondly, missing action classes must not disrupt the normal dispatching of the request. Missing action classes will not trigger a special error. Instead, the usual “Missing Method in Controller…” errors will be generated.
Finally, plugins should be able to use action classes as well.
How to implement an action class-based CakePHP app:
Edit app/config/core.php and set CUSTOM_DISPATCHER to ‘acDispatcher’.
For each controller create a folder in app/controllers/ with the same name as the controller following the usual CakePHP naming conventions.
Override app_action.php if desired. Place your custom app_action.php in app/app_action.php.
Create an action class file inside app/controllers/controller_name. We also follow the CakePHP naming conventions here.
Implement the method perform() in your action class. This is the same as creating an action as a method in your controller. If your action accepts parameters, specify them as such in the parameter list for perform().
For example:
http://example.com/ctrl/index/
Create the directory app/controllers/ctrl
Create the file app/controllers/ctrl/index_action.php
Define IndexAction in index_action.php defining the perform() method.
Notes:
You get a reference to the controller in $this->controller.
All the properties of the controller can also be referenced in the context of the action itself. For instance, the $uses property is also available as a reference using $this->uses.
For plugins, simply follow the usual conventions as above in addition to the CakePHP plugin conventions.
I wish to clarify to any CakePHP users who might stumble upon this (and my other modifications) that this modification is meant to serve as a transition point for me to allow me to port my apps to CakePHP from my previous framework.
Also note that this is the first commit of this modification and there may be bugs. If you encounter any, please DO NOT report them to the CakePHP developers nor the CakePHP Google Group. Leave a comment here if you wish to file a bug report.
Lastly: Experimental code. Caveat Programmor
