I was thinking that I needed something similar to scenarios so, building on that idea I have now tried to make a solution where I create a method called viewable
on my model, which returns a list of attributes that should be visible for the current scenario of the model. For example:
public function viewable() {
$scenario = $this->getScenario();
if ($scenario == self::SCENARIO_DEFAULT) {
return [];
} elseif ($scenario == self::SCENARIO_EV_ADMIN) {
return $this->attributes(); //admin is allowed to see all attributes on the model
} elseif ($scenario == self::SCENARIO_EV_ORGANIZER_INSERT || $scenario == self::SCENARIO_EV_ORGANIZER_UPDATE) {
$attributes = $this->activeAttributes(); //use list of attributes they can edit as the basis for attributes they can view
array_push($attributes, 'ev_approved', 'ev_status'); //add a few more they are allowed to view
return $attributes;
} else {
return [];
}
}
Then eg. in GridView
or DetailView
I pass the list of columns/attributes through a helper that will filter out any attributes that were not returned by viewable
. Eg.:
'attributes' => MyHelper::filterAttributes([
'eventID',
[
'attribute' => 'organizerID',
'value' => \app\models\Organizer::findOne($model->organizerID)['org_name'],
],
'ev_name',
....
], $model->viewable()),
My helper method being like this:
public static function filterAttributes($all_attributes, $attributes_to_keep) {
$output = [];
foreach ($all_attributes as $value) {
if (is_string($value)) {
$colon = strpos($value, ':');
if ($colon === false) {
$name = $value;
} else {
$name = substr($value, 0, $colon);
}
} elseif (is_array($value)) {
if ($value['attribute']) {
$name = $value['attribute'];
} elseif ($value['class']) {
// always leave special entries intact (eg. class=yii\grid\ActionColumn)
$output[] = $value;
continue;
} else {
new UserException('Attributes name not found when filtering attributes.');
}
} else {
new UserException('Invalid value for filtering attributes.');
}
if (in_array($name, $attributes_to_keep)) {
$output[] = $value;
}
}
return $output;
}
And in create.php/update.php (or _form.php actually) I do this:
$editAttribs = $model->activeAttributes();
$viewAttribs = $model->viewable();
....
if (in_array('organizerID', $viewAttribs)) {
echo $form->field($model, 'organizerID')->textInput(['disabled' => !in_array('organizerID', $editAttribs) ]);
}
....
Feedback is welcome!