2

I am using a Behavior to add an action to a few controllers, the oversimplified behavior is defined as

public class GreetBehavior extends Behavior {
    public function sayHello() {
        return "Hello"
    }

    public function actionGreet() {
        return "Hello";
    }
}

The behavior is attached successfully. From within a Controller (f.i. Person) method I can access sayHello with $this->sayHello();. The actionGreet however, is not recognized if I call it from the address bar: ...index.php?r=person/greet. It gives the message that it cannot be resolved. Is it possible to add actions to a controller with behaviors anyway? If so, can you give me a hint what to do/what I am doing wrong. If not, do you know an alternative?

userlond
  • 3,632
  • 2
  • 36
  • 53
Barry
  • 3,683
  • 1
  • 18
  • 25

4 Answers4

3

In Yii2 there are two ways to add actions to a controller; standalone and inline. You are trying to add an inline action - which means that it is declared as a method on the controller's class with the 'action' prefix.

The other way to load actions are as 'standalone' files, that are defined in the controller's 'actions' method. This returns an array of references to action classes that exist elsewhere.


If you look at the createAction method on yii\base\Controller (which loads the action when your app runs) you can see that it first looks through its actions array (the standalone ones) and if it can't find it it looks through its own methods (after formatting the name and adding the 'action' prefix - see lines 224-225).

The problem you have is that when the base controller looks for the inline method it uses php's method_exists function, which is totally blind to yii2's behavior functionality.

I don't know why it doesn't use the 'hasMethod' method on the base controller instead, which would know about the behavior methods. I'm only just looking at Yii2 at this level of detail though so there may be a reason I'm unaware of.


So the answer to your question is that the way Yii2 is currently coded you cannot put an inline action on a controller's behavior - because it won't be seen when Yii2 comes to look for it.

And the solution is to switch to standalone actions, which you can read about on this guide page.

Sean Toru
  • 349
  • 2
  • 17
0

You can not do that, since actions must be extended from a Controller class, so a method in a behavior class can not be replaced with a controller action.

You can achieve this goal, by creating a base controller and change your other controllers to extend from that controller. Like below:

use yii\web\Controller;
class BaseCont extends Controller{
    public function actionGreat(){
        return "Hello";
    }
}

Then by creating a controller which extends it like below:

class MyController extends BaseCont{
    //rest of code
}

You will have greatAction in addition to your other actions in MyController.

Ali MasudianPour
  • 14,329
  • 3
  • 60
  • 62
0

Use Controller::actions()

public function actions() {
    return [
        'ajaxsearch' => [
            'class'=>'app\components\searchlinewidget\AjaxSearchAction',
            'searchClass'=>PublisherSearch::className()
        ]
    ];
}
-1

You can add actions with the Actions class definition. See item 3 here http://www.yiiframework.com/doc/guide/1.1/en/basics.controller

Your issues is being discussed here:

No this is not possible yet because CController::createAction() checks if "actionExample" is a valid method for the given controller. Behavior methods are no real methods within a controller since they get called via magic __get().

For now, as workaround I guess you can override CController::createAction() or CController::missingAction() in some way to get it work.

http://www.yiiframework.com/forum/index.php/topic/10652-actions-by-behavioring/

Pentium10
  • 204,586
  • 122
  • 423
  • 502