I know that behaviors can be customized by overriding the behaviors method, which will return an array with the configurations of each attached behavior. I want to have, besides this method, another, suppose, behaviors2, the format of which was indentive, which would do exactly the same thing - keep the data on the behaviors.

The challenge is this: collect behavioral information from both methods.

Investigating the component code, I realized that the collection of information from the behaviors method is responsible for ensuring Behaviors, which in turn is launched almost at the beginning of every other method that is somehow related to behaviors. The first thought is to redefine it:

public function ensureBehaviors() { parent::ensureBehaviors(); $this->ensureBehaviors2();//для красоты можно использовать static:: } 

Where am I to ensureBehaviors2 just attach all other behaviors.

Difficulty: the method that is responsible for attaching the behavior to the component, attachBehaviorInternal is private, and the attachBehavior method calls to ensureBehaviors. Total: recursion.

Output: add property to class:

 private $_ensureBehaviorsLock = false; 

And write like this:

 public function ensureBehaviors() { if ($this->_ensureBehaviorsLock) { return; } $this->_ensureBehaviorsLock = true; parent::ensureBehaviors(); $this->ensureBehaviors2(); } 

And then I wondered .. It seems to be working, but it seems like a big and heavy crutch. But it works. I would like to know your opinion and possible solutions to this problem.

Here is my sketch to make it clear what I want: http://pastebin.com/1pVaVvmq

A few reservations:

The functionality of the behaviors method should remain the same. I know that it would be possible to use behaviors2 and behaviors3, and in behaviors just to merge the results of these methods. Or in behaviors to add functionality which took an array which in it, and with others. But then it would be impossible to use inheritance.

Ps who have the privilege to edit questions, format, please, humanly. I am writing from the phone, there is no such possibility.

  • Mdaaa ... Xenial Xerus. Задача такова: собирать информацию о поведениях из обоих методов. It is possible in more detail, why such distortions? Do you need to keep the state of behavior before a certain action and after? - romeo
  • Divide the area of ​​responsibility and add additional functionality without affecting the previous one. Maybe the way to solve my original problem is not very, but it greatly simplifies my life. - Vitaly Zaslavsky
  • OK. Suppose you have two sets of behaviors. Next, how are you going to determine which set to pull, and which not? How will this be done through routing? Usually to extend the functionality without affecting the legacy code, use the "decorator" pattern - romeo
  • Didn’t I describe how it should work? I need not to rewrite the class, but to create a new one, inheriting from it and adding functionality. - Vitaly Zaslavsky
  • All the names of the methods and properties are very conditional and written solely for example. In a real project, things are a little different. - Vitaly Zaslavsky

1 answer 1

I will advise you to abandon the idea of ​​separating plug-in behaviors into several methods. Here are my arguments:

  • Non-standard mechanism. Yes, we have to program using the framework, not on the framework. But the first argument is that everyone knows what behaviors . What is analyticsBehaviors , customBehaviors will have to explain to everyone.

  • False flexibility. It’s not enough for you to add behaviors2 in one place. I assume that you choose another name and the question is whether all models will need it. And what if some need behaviors3 ? The code that you brought is not a crutch, maybe only a little. It adequately solves the separation problem, but I do not think that it will be flexible enough.

The standard solution to this problem for me looks quite normal and as flexible as possible.

 class Model extends \yii\base\Model { public function behaviors() { return ArrayHelper::merge([ 'AnalyticBehavior' => [ 'class' => AnalyticBehavior::className() ] ], $this->getCustomBehaviors()); } private function getCustomBehaviors() { return [ 'NotifyBehavior' => [ 'class' => NotifyBehavior::className() ] ]; } } 

No need to guess what and where. Standard behaviors, a large number of them can be scattered as you like.

The problem with inheritance is solved as follows:

 class ChildModel extends Model { public function behaviors() { return ArrayHelper::merge([ 'StrictAnalyticBehavior' => [ 'class' => StrictAnalyticBehavior::className() ] ], parent::behaviors()); } } 

The programmer will always work with behaviors , the formation of which will be determined by the task. It is simple and cool.