User one behavior to add/remove other behaviors?

I try to use one behavior(ActionFilter) to control other behaviors(ActionFilter) whether to work or not.

For exp.

In my TestController




public function behaviors()

{

    $behaviors['A'] = [

        //ActionFilter A determine B or C which to run .....

    ];

    $behaviors['B'] = [

        //ActionFilter B .....

    ];

    $behaviors['C'] = [

        //ActionFilter C .....

    ];

    return $behaviors;

}



In behavior A class,

I attach more behaviors to TestController works fine, but when I detach B or C,comes the problem.

Call to a member function on() on a non-object

The code was ActionFilter::beforeFilter($event)




        $event->isValid = $this->beforeAction($event->action);

        if ($event->isValid) {

            // call afterFilter only if beforeFilter succeeds

            // beforeFilter and afterFilter should be properly nested

            $this->owner->on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);

        }



Then I look into it.I found filters not removed were all fine, Their owner is TestController,that’s correct.

But the filter detached by A is not really detached, and which has an owner(yii\base\ActionFilter)???

In my TestController.php:




public function behaviors()

{

	  $behaviors['temperatureAdaptor'] = [

        'class' => TemperatureFilter::className(),

        'hotFilters' => [

            [

                'class' => IcyDrink::className(),

            ],

        ],

        'coldFilters' => [

            [

                'class' => HotDrink::className(),

            ],

        ],

    ];

    $behaviors['hotFilter'] = [

        'class' => IcyDrink::className(),

    ];

    $behaviors['coldFilter'] = [

        'class' => HotDrink::className(),

    ];

    return $behaviors;

}



Here’s the filter:




class TemperatureFilter extends ActionFilter

{


    protected $hotFilters = [];


    protected $coldFilters = [];


    public function setHotFilters($hotFilters)

    {

        $this->hotFilters = $hotFilters;

    }


    public function setColdFilters($coldFilters)

    {

        $this->coldFilters = $coldFilters;

    }


    public function beforeAction($action)

    {

        $temperatureType = Temperature::hotOrCold();


        //1. add corresponding filters

        $matchedProperty = strtolower($temperatureType) . 'Filters';

        foreach ($this->{$matchedProperty} as $filter) {

            $this->attachFilter($action->controller, $filter);

        }


        //2.remove correspoding filters

        $mismatchedType = ($temperatureType == "HOT") ? "COLD" : "HOT";

        $mismatchedProperty = strtolower($mismatchedType) . 'Filters';

        foreach ($this->{$mismatchedProperty} as $filter) {

            $this->detachFilter($action->controller, $filter);

        }


        return parent::beforeAction($action); // TODO: Change the autogenerated stub

    }




    protected function attachFilter($controller, $filter)

    {

        $behaviors = $controller->getBehaviors();

        foreach ($behaviors as $behavior) {

            if (is_a($behavior, $filter['class'])) {

                Yii::info(StringHelper::basename($behavior->className()) . " ALREADY INSTALLED");

                return;

            }

        }

        $filterName = ($filter['name']) ? $filter['name'] : StringHelper::basename($filter['class']);

        $controller->attachBehavior($filterName, $filter);

    }


    

    protected function detachFilter($controller, $filter)

    {

        $behaviors = $controller->getBehaviors();

        foreach ($behaviors as $name => $behavior) {

            if (is_a($behavior, $filter['class'])) {

                $controller->detachBehavior($name);

                return;

            }

        }

    }

}



Code above went wrong:

PHP Fatal Error – yii\base\ErrorException

Call to a member function on() on a non-object

Then I trace and found the IcyDrink or HotDrink was detached, but they were still invoke by owner yii\base\ActionFilter.

So weird.