Behavior loading

32 views
Skip to first unread message

Andy Hobbs

unread,
Sep 25, 2013, 7:25:29 AM9/25/13
to cakeph...@googlegroups.com
Hi,

I have come across a couple of scenarios the last week or so where I have tried to implement functionality in the setup() callback of a behavior and failed because of the way behaviors are currently loaded by the BehaviorCollection.

Scenario 1:

In a plugin I wanted a behavior to be disabled by the app using configuration (the behavior is attached to a Model in a plugin so I really don't want to edit the plugin just for this project). I tried to have the behavior disable itself based on a Configure value by doing $Model->Behaviors->disable('MyBehavior'); This didn't work because the Behavior isn't yet "enabled" when the setup callback is called.

Scenario 2:

In the behavior setup callback I wanted to call one of the behavior methods the same way as I would everywhere else in my code i.e. $model->behaviorMethod() but this didn't work because the methods and mapped methods haven't been processed by the loading method before the setup() callback is called. I realise that I can get round this by doing $this->behaviorMethod($model); in my setup callback but then the method calling is different from anywhere else I use it in my code.

Is there any reason the setup() callback is called before the behavior methods have been processed and the behavior has been enabled? especially as there is no way to affect either of these from within the setup() callback. If not then is this a possible change for 2.5?

I have tried moving the setup() call to after the method/mapped method processing and the behavior enable/disable and all the core tests still pass. 

Thanks
Andy

mark_story

unread,
Sep 25, 2013, 8:45:06 PM9/25/13
to cakeph...@googlegroups.com
The only reason I can think of would be because that is how things have always worked. There could be issues moving things around if userland behaviours rely on being able to define pattern based method mappings in their setup function.

Could you not solve the enabled issue using the existing setting?

-Mark

Andy Hobbs

unread,
Sep 26, 2013, 4:16:38 AM9/26/13
to cakeph...@googlegroups.com
Using the existing setting would enable/disable the behavior for all models which is not what I'm after. I need to turn it on/off per model without editing code in my plugins for each project.

I can override the <Plugin>AppModel::__constructor() in each plugin and make it enable/disable the behaviors after the parent::__constructor() has executed but this then means that each plugin has to know about the others. Although this is possible and might be my only solution it does mean maintainability of the code becomes more complex as our code base gets bigger.

What I am doing:

I have a CMS which is built from a few plugins like core CMS, user/permissions, perma links and a couple of others. I also have a versioning plugin which adds the ability to version control all tables in the database. The version control needs to be able to be turned on/off on a per model basis depending on what a client want to have controlled. I am trying to achieve this through use of configuration to avoid changing the plugins per project.

Calling setup before the methods/mapped methods are handled is not too much of a problem for me as I can easily call them directly on the behavior. Not being able to disable the behavior is a big problem though as doing it post setup in the plugins AppModel is messy.

One other thought I had was to mode the setting of $configDisabled to after setup was called, this way the setup method could alter $config that is passed in to set 'enabled' to false. This shouldn't impact any existing user land behaviors.



-Mark

--
You received this message because you are subscribed to the Google Groups "cakephp-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cakephp-core...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

rchavik

unread,
Sep 26, 2013, 5:22:30 AM9/26/13
to cakeph...@googlegroups.com, an...@hobbs.uk.net
On Thursday, September 26, 2013 3:16:38 PM UTC+7, Andy Hobbs wrote:
Using the existing setting would enable/disable the behavior for all models which is not what I'm after. I need to turn it on/off per model without editing code in my plugins for each project.

I did something similar for an Audit plugin [1].



I can override the <Plugin>AppModel::__constructor() in each plugin and make it enable/disable the behaviors after the parent::__constructor() has executed but this then means that each plugin has to know about the others. Although this is possible and might be my only solution it does mean maintainability of the code becomes more complex as our code base gets bigger.


What I am doing:


I have a CMS which is built from a few plugins like core CMS, user/permissions, perma links and a couple of others. I also have a versioning plugin which adds the ability to version control all tables in the database. The version control needs to be able to be turned on/off on a per model basis depending on what a client want to have controlled. I am trying to achieve this through use of configuration to avoid changing the plugins per project.


Calling setup before the methods/mapped methods are handled is not too much of a problem for me as I can easily call them directly on the behavior. Not being able to disable the behavior is a big problem though as doing it post setup in the plugins AppModel is messy.


One other thought I had was to mode the setting of $configDisabled to after setup was called, this way the setup method could alter $config that is passed in to set 'enabled' to false. This shouldn't impact any existing user land behaviors.


I don't have a solution for you, but I can share a bit on how Croogo does it:

- During plugin bootstraps, plugin registers behaviors against each model, eg: Croogo::hookBehavior('User', 'Acl.UserAro') [2]
- Croogo::hookBehavior() will store a map of models and dynamically registered behavior.
- CroogoAppModel::__construct() reads that map, and 'injects' the behavior and its setting into the 'actsAs' property. [3]

Once that infrastructure is in place, that 'Audit' plugin simply stores them in a Configure array, iterate the values and enable the behaviors [4]

1. Audit Plugin Screenshot: http://i.imgur.com/iQDey3v.png
2. https://github.com/croogo/croogo/blob/master/Plugin/Croogo/Lib/Croogo.php#L50-52
3. https://github.com/croogo/croogo/blob/master/Plugin/Croogo/Model/CroogoAppModel.php#L54-57
4. https://github.com/xintesa/Audit/blob/master/Config/bootstrap.php#L3-10

Hope this helps

Andy Hobbs

unread,
Sep 26, 2013, 5:43:23 AM9/26/13
to cakeph...@googlegroups.com
yes, that is helpful, thank you

I could do a similar thing to the Croogo bootstrapping by enabling the behavior in a bootstrap file for the models it is required for.


--
Reply all
Reply to author
Forward
0 new messages