Components, Helpers, Behaviors and Tasks all share a similar structure and set of behaviors. For 2.0, they were given a unified API for interacting with collections of similar objects. The collection objects in CakePHP, give you a uniform way to interact with several different kinds of objects in your application.
While the examples below, will use Components, the same behavior can be expected for Helpers, Behaviors, and Tasks in addition to Components.
Loading objects on every kind of collection can be done using the load()
method:
$this->Prg = $this->Components->load('Prg');
$this->Prg->process();
When loading a component, if the component is not currently loaded into the collection, a new instance will be created. If the component is already loaded, another instance will not be created. When loading components, you can also provide additional configuration for them:
$this->Cookie = $this->Components->load('Cookie', array('name' => 'sweet'));
Any keys & values provided will be passed to the Component’s constructor. The
one exception to this rule is className
. ClassName is a special key that is
used to alias objects in a collection. This allows you to have component names
that do not reflect the classnames, which can be helpful when extending core
components:
$this->Auth = $this->Components->load(
'Auth',
array('className' => 'MyCustomAuth')
);
$this->Auth->user(); // Actually using MyCustomAuth::user();
The inverse of loading an object, is unloading it. Unloaded objects are removed from memory, and will not have additional callbacks triggered on them:
$this->Components->unload('Cookie');
$this->Cookie->read(); // Fatal error.
Callbacks are supported by collection objects. When a collection has a callback triggered, that method will be called on all enabled objects in the collection. You can pass parameters to the callback loop as well:
$this->Behaviors->trigger('afterFind', array($this, $results, $primary));
In the above $this
would be passed as the first argument to every
behavior’s afterFind method. There are several options that can be used to
control how callbacks are fired:
breakOn
Set to the value or values you want the callback propagation to stop on.
Can either be a scalar value, or an array of values to break on. Defaults to false
.
break
Set to true to enabled breaking. When a trigger is broken, the last returned value
will be returned. If used in combination with collectReturn
the collected results will be returned.
Defaults to false
.
collectReturn
Set to true to collect the return of each object into an array.
This array of return values will be returned from the trigger() call. Defaults to false
.
triggerDisabled
Will trigger the callback on all objects in the collection even the non-enabled
objects. Defaults to false.
modParams
Allows each object the callback gets called on to modify the parameters to the next object.
Setting modParams to an integer value will allow you to modify the parameter with that index.
Any non-null value will modify the parameter index indicated.
Defaults to false.
Using the break
and breakOn
options you can cancel a callback loop
midway similar to stopping event propagation in JavaScript:
$this->Behaviors->trigger(
'beforeFind',
array($this, $query),
array('break' => true, 'breakOn' => false)
);
In the above example, if any behavior returns false
from its beforeFind
method, no further callbacks will be called. In addition, the return of
trigger()
will be false.
Once an object is loaded into a collection you may need to disable it.
Disabling an object in a collection prevents future callbacks from being fired
on that object unless the triggerDisabled
option is used:
// Disable the HtmlHelper
$this->Helpers->disable('Html');
// Re-enable the helper later on
$this->Helpers->enable('Html');
Disabled objects can still have their normal methods and properties used. The
primary difference between an enabled and disabled object is with regards to
callbacks. You can interrogate a collection about the enabled objects, or check
if a specific object is still enabled using enabled()
:
// Check whether or not a specific helper is enabled.
$this->Helpers->enabled('Html');
// $enabled will contain an array of helper currently enabled.
$enabled = $this->Helpers->enabled();
You can prioritize the triggering object callbacks similar to event callbacks. The handling of priority values and order of triggering is the same as explained here. Here’s how you can specify priority at declaration time:
class SomeController {
public $components = array(
'Foo', //Foo gets default priority 10
// Bar's callbacks are triggered before Foo's
'Bar' => array('priority' => 9)
);
public $helpers = array(
// Cache's callbacks will be triggered last
'Cache' => array('priority' => 12),
'Asset',
'Utility' //Utility has priority 10 same as Asset and its callbacks
//are triggered after Asset's
);
}
class Post {
public $actsAs = array(
'DoFirst' => array('priority' => 1),
'Media'
);
}
When dynamically loading objects to a collection you can specify the priority like this:
$this->MyComponent = $this->Components->load(
'MyComponent',
array('priority' => 9)
);
You can also change priorities at run time using the ObjectCollection::setPriority()
function:
//For a single object
$this->Components->setPriority('Foo', 2);
//For multiple objects
$this->Behaviors->setPriority(array('Object1' => 8, 'Object2' => 9));