Disable behavior temporarily

Hi,

I have a custom behavior ‘MyBehavior’ that extends CActiveRecordBehavior and has an implementation of afterFind() callback. How would I disable this behavior, and hence the afterFind() call, on a findAll() AR query? I tried these two different methods but neither worked and MyBehavior::afterFind() method gets called in both cases:




Office::model()->disableBehavior('MyBehavior');

$offices = Office::model()->findAll();

Office::model()->enableBehavior('MyBehavior');


$office = new Office;

$office->disableBehavior('MyBehavior');

$offices = $office->findAll();



Please advise. Thanks.

I tried detachBehavior() and it did work:




$model = Office::model();

$model->detachBehavior('MyBehavior');

$offices = $model()->findAll();



Make sure that ‘MyBehavior’ is the name of the behavior you declared like this:




public function behaviors()

{

	return array(

		'MyBehavior' => array(...)

        );

}



Best regards…

Thanks, c@cba. I do have MyBehavior defined as you mention and it extends CActiveRecordBehavior.

I tried detachBehavior() as well. Both disable and detach behaviors per se work fine but the subsequent findAll() seems to take the execution through to MyBehavior::afterFind() which is exactly what I want to avoid. What am I missing?

Figured out the following. As can be seen from the methods populateRecord() and instantiate() in CActiveRecord.php, any call to findAll() is going to create new instances of a model and attach default behaviors. So, disabling/detaching behaviors for a findAll() query can’t be done the way I was trying.

Any pointers on how to accomplish this? Should I override instantiate() or init() methods by extending CActiveRecord maybe?

Test isnewRecord in the behavior?

/Tommy

No. The behavior has just two methods - beforeSave($event) and afterFind($event) neither of which has isNewRecord test.

Check if you can use this conditionally in your use case. if (!$this->owner->isNewRecord) or something like that.

/Tommy

@tri: $this->owner->isNewRecord will always evaluate to false in afterFind() but I agree that the problem should be solved in the behavior itself, if possible.

@yiifan: What does your behavior actually do?

Yeah, my bad. We are talking about model instances that will only be created by the find() methods.

What about store and/or interrogate the "no behavior please" state in the class instance Office::model()? Should at least not introduce any dependencies to MyBehavior. Interrogate "MyBehavior attached and enabled" should do it without dependencies.

/Tommy

@phtamas: MyBehavior has two callbacks afterFind() and beforeSave() both of which essentially convert date formats between php and database, and do nothing more. I can’t think of a way to solve it inside the behavior because CActiveRecord::populateRecord() attaches all behaviors to the AR no matter what. Do you mean it has to be done after the ARs are fetched and when the execution gets to MyBehavior::afterFind() by checking if behavior is enabled. If so, I’d think it is sub-optimal compared to just detaching the behavior apriori and the execution never getting to MyBehavior::afterFind().

@tri: Is it not the same as what I am trying (first post) by calling disable/detach behaviors after instantiating an instance of Office::model(). Maybe I don’t quite understand what you mean - please clarify.

Not digging into the source at this time, I would say that the class instance will be the only place where one can find information about the state change (detach). So you may want to interrogate the class instance from your behavior (attached to discrete instances representing found records). I guess you may have to extend CActiveRecord e.g. with a method for deciding the attach/detach state.

/Tommy

Hi all,

anyone solved this? I had the same issue: i need to detach/disable a behavior before a findAll.

I managed to pass this issue with setting specific scenario that will not use behavior, for example:

$model = new ModelClass();

$model->scenario = ‘noBehavior’;

$model->findAll();

and in behavior U can plase condition:

public function beforeFind($event)

{

 if($this->owner->scenario == 'noBehavior')


     return;


 ...... your code for behavior.....

}

I’m not sure if that’s what will suite U, but for my case (have behaviors that are adding condition), this works ok

1 Like

not sure its realted, but this still does not work - i have made an issue a few years (yes :smiley:) ago.