5

I can see in the Yii2 model page (http://www.yiiframework.com/doc-2.0/yii-base-model.html), in the "fields" section that you can set "different lists of fields based on some context information. For example, depending on $scenario or the privilege of the current application user, you may return different sets of visible fields or filter out some fields."

But, scenarios documentation (http://www.yiiframework.com/doc-2.0/guide-structure-models.html#scenarios) says scenarios is for creating different context for model attributes validation.

I'm using Yii2 Restful API, where I have to use default actions (actionIndex, actionView, ...) to get data from model and show as API results. I know I can override those methods (http://www.yiiframework.com/doc-2.0/guide-rest-controllers.html#extending-active-controller), but how can I say in those methods to use different set of fields (depending on different scenarios) ?

What I need is to output field1, field2, field3 for actionIndex (items list), but I want to output field1, field2, field3, field4 for actionView (item list).

FlamingMoe
  • 2,709
  • 5
  • 39
  • 64
  • Not sure, never used the rest api... Derive from you model class, introduce scenarios (and maybe rules) and then override fields()? In the controller you would then have to set the scenario on the model in each action (i.e. you have to override the default implementations). In fields you can then decide which attributes should be enabled for the implicit toArray() call. Does this work for you anyhow? – robsch Sep 19 '15 at 18:51

3 Answers3

6

You do it in your model.

Default REST implementation in Yii2 will only include attributes that are returned by the fields() method. By default, that method returns all attributes. Therefore, you define it like so:

class MyModel extends ActiveRecord
{
    //...
    public function fields()
    {
        switch ($this->scenario) {
            case 'my_scenario_1':
                return ['field1', 'field2'];
            case 'my_scenario_2':
                return ['field3', 'field4'];
        }
    }
}

Also, you have the scenarios() method at your disposal, which returns all active attributes for a given scenario.

Don't forget to set the models' scenario in your controller.

Beowulfenator
  • 2,262
  • 16
  • 26
  • But how do you best do this for actionIndex() which return an array of models? How do you best set the scenario for all those models? (also considering that you might want to use the serializer). This is talking about the same issue: https://stackoverflow.com/a/48063749/2404541 – TheStoryCoder Feb 19 '23 at 15:03
  • I'm beginning to think that for my project I don't wanna use scenarios. I'll use other methods to determine the attributes to show, eg. based on the user role. Reasoning is that no matter what the scenario is, a user should always be able to *view* the same attributes. So it doesn't really pertain to the scenarios concept. – TheStoryCoder Feb 19 '23 at 15:06
2

According to this guide: http://www.yiiframework.com/doc-2.0/guide-structure-models.html#scenarios

first set your scenarios in your model. example:

const SCENARIO_LESS = 'index';
const SCENARIO_MORE = 'view';

public function scenarios()
{
    return [
        self::SCENARIO_LESS => ['field1', 'field2'],
        self::SCENARIO_MORE => ['field1', 'field2', 'field3'],
    ];
}

now in your action(s) just set the scenario like this:

// scenario is set through configuration
public function actionIndex()
{
    $model = new User(['scenario' => User::SCENARIO_LESS]);
    ...
}
...
public function actionView()
{
    $model = new User(['scenario' => User::SCENARIO_MORE]);
    ...
}

that should do it.

leninhasda
  • 1,620
  • 11
  • 18
-1

this is my solution for this problems, using Yii::$app()

public function fields()
{
    if(Yii::$app->controller->action->uniqueId == 'controller/action'){
        return ['field_1','field_2','field_3','field_4'];
    }else{
        return ['field_1','field_3'];
    }
}

hope works for you

  • 1
    I think this solution is very fragile and should not be used. Models should not know about controllers. The solution proposed by Beowulfenator should hold up much better. – Martijn Hols Apr 17 '18 at 07:52