With the LazyLoading Model from Lorenzo (there are other sources as well) we already speed up the application by 20-40% (depending on the application size and amount of models).
Something i never really liked is that components and helpers can only be added to controllers globally in $components and $helpers. Unlike behaviors (attach/detach).
What if we need some of them only in a single action? Seems to be overhead to include it in every action of the controller.
I used to patch around that problem with App::import() and all kinds of init stuff in the action itself.
Now I wrote this (and suddenly my code is so much cleaner):
class CommonComponent extends Object {
/**
* for automatic startup
* for this helper the controller has to be passed as reference
* 2009-12-19 ms
*/
function initialize($Controller) {
$this->Controller = $Controller;
}
/**
* add helper just in time (inside actions - only when needed)
* aware of plugins
* @param mixed $helpers (single string or multiple array)
* 2010-10-06 ms
*/
function loadHelper($helpers = array()) {
$this->Controller->helpers = array_merge($this->Controller->helpers, (array)$helpers);
}
/**
* add lib just in time (inside actions - only when needed)
* aware of plugins and config array (if passed)
* ONLY works if constructor consists only of one param!
* @param mixed $libs (single string or multiple array)
* 2010-11-10 ms
*/
function loadLib($libs = array()) {
foreach ((array)$libs as $lib => $config) {
if (is_int($lib)) {
$lib = $config;
$config = null;
}
list($plugin, $libName) = pluginSplit($lib);
if (isset($this->Controller->{$libName})) {
continue;
}
App::import('Lib', $lib);
$lib = new $libName($config);
$this->Controller->{$libName} = $lib;
}
}
/**
* add component just in time (inside actions - only when needed)
* aware of plugins and config array (if passed)
* @param mixed $helpers (single string or multiple array)
* 2010-11-08 ms
*/
function loadComponent($components = array()) {
foreach ((array)$components as $component => $config) {
if (is_int($component)) {
$component = $config;
$config = null;
}
list($plugin, $componentName) = pluginSplit($component);
if (isset($this->Controller->{$componentName})) {
continue;
}
App::import('Component', $component);
$componentFullName = $componentName.'Component';
$component = new $componentFullName($config);
if (method_exists($component, 'initialize')) {
$component->initialize($this->Controller);
}
if (method_exists($component, 'startup')) {
$component->startup($this->Controller);
}
$this->Controller->{$componentName} = $component;
}
}
}
Now the following is possible (inside controller actions):
$this->Common->loadComponent('RequestHandler');
$this->Common->loadComponent('Tools.Currency');
$this->Common->loadComponent(array('RequestHandler', 'Test'=>array('x'=>'y'))); # passing options
$this->Common->loadLib('Tools.RandomLib');
$this->Common->loadLib(array('Tools.RandomLib', 'MarkupLib'));
$this->Common->loadLib(array('Tools.RandomLib', 'MarkupLib'=>array('x'=>'y'))); # passing options
$this->Common->loadHelper('Text');
$this->Common->loadHelper(array('Text', 'Tools.Datetime'));
etc.
Maybe without "Common->" or any other helping component some time in the future 🙂
I hope the enhancement ticket will soon be patched into the core. Feel free to vote it up:
cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/1277
Works well but I seem to have found a glitch. By bypassing the usual Component->init(), it seems that sub-components are not loaded.
So if in my Test component I have:
the Session component won’t be loaded for Test.
I narrowed this down to
Controller->contructClasses();
and
Component->init()
They seem to be very intertwined so it’s complex to run ->init() by itself from within another component.
Any ideas?
.
Well, after some testing, I seem to have figured it out:
I also moved the $config to the component->initialize() call instead of the component constructor call.
nice work. i will try it out.
with cake2.0 most of that stuff is available in the core anyway.
but for 1.3 we still need those hacks 🙂