Attaching and detaching model behaviors on-the-fly
A feature recently added to CakePHP is the possibility to attach and detach model behaviors on-the-fly (see changeset 6415). Let’s have a look at this feature with a simple example.
First we create a behavior which outputs a text before a find operation is performed:
// app/models/behaviors/example.php
class ExampleBehavior extends ModelBehavior {
private $text = 'this is an example text';
function setUp(&$model, $config) {
if (isset($config['text'])) {
$this->text = $config['text'];
}
}
function beforeFind(&$model, $query) {
echo $this->text;
return true;
}
}
The usual way to use a behavior is to define it with the $actsAs variable in the model. For example, to use the ExampleBehavior with the Post model, we would define it in the following way:
// app/models/post.php
class Post extends AppModel {
var $actsAs = array('Example' => array('text' => 'some text'));
}
Every time we execute a find method of the Post model, the string “some text” is echoed.
With the new methods Model::attach() and Model::detach() more flexible scenarios are possible (even though I can’t think of any real use cases at the moment). If we want our Post model to act as Example only temporarily, we could write the following code:
// app/models/post.php
class Post extends AppModel {
}
// action in our controller
function index() {
$this->Post->attach('Example', array('text' => 'hello world'));
$this->set('all_posts', $this->Post->findAll());
$this->Post->detach('Example');
$this->set('first_post', $this->Post->findById(1));
}
When we perform the findAll statement, our Post model acts as Example, i.e. the specified text is echoed, whereas with the findById statement, it no longer acts as Example, and so there is no output.
Happy baking :)




[...] Cakebaker blog tells us that attaching and detaching behaviors on the fly is now built in CakePHP core (we obviously have [...]
Thanks for the heads up - have updated our old blog entry on how to do this….
Nice, this could be useful. It is always a good feature to be able to remove/add behaviors, helpers, model relationships, etc on-the-fly.
@Tarique, Marc: Thanks for your comments!
I have tried this with the Translate behaviour and it didn’t work
class Page extends AppModel
{
var $displayField = ‘name’;
var $actsAs = array();
function setLanguage($lang=null)
{
if($lang==null)
$lang = Configure::read(’Config.language’);
else
Configure::write(’Config.language’,$lang);
if(DEFAULT_LANGUAGE!=$lang)
$this->actsAs = array(’Translate’ => array(’content’, ‘name’, ‘title’));
$this->__construct(false, null, null);
}
}
This is my model Page, when I set up to the default language it retrives information from the pages tables, but if I change the language it retrives using the Translate behaviour from i18n table.
What I should do I have tried this and didn’t work
class Page extends AppModel
{
var $displayField = ‘name’;
var $actsAs = array(’Translate’ => array(’content’, ‘name’, ‘title’));
function setLanguage($lang=null)
{
if($lang==null)
$lang = Configure::read(’Config.language’);
else
Configure::write(’Config.language’,$lang);
if(DEFAULT_LANGUAGE==$lang)
$this->detach(’Translate’);
}
}
@Boris: Hm, do you use the CakePHP version from the development branch?
[...] CakePHP 1.2 から追加されたビヘイビアが動的に追加、削除できるようになるようです。 Attaching and detaching model behaviors on-the-fly - cakebaker [...]
I use the beta version 1.2.0.6311-beta
So I think it should work the attach and detach behaviours.
@Boris: No, this feature is not yet in a release. As I have mentioned in the article it has been added in changeset 6415. So to use this feature you either have to use the version from the development branch or to wait for the next release…
[...] CakePHP 1.2 から追加されたビヘイビアが動的に追加、削除できるようになるようです。 Attaching and detaching model behaviors on-the-fly - cakebaker [...]