I have a form, when clicking on the icon the class should switch to enabled/disabled
$options = [
'enablePushState' => false,
'timeout' => 5000,
'options' => ['tag'=>'span', 'class'=>'access']
];
$id = \Yii::$app->request->get('_pjax');
if($id){$options['id'] = str_replace('#', '', $id);}
?>
<?php Pjax::begin($options); ?>
<?= Html::a('<i class="fa fa-users"></i>', ['/request/'.$id.'/access'], [
'class' => ($access['provider'] ?? null) ? 'enabled' : 'disabled'
]) ?>
<?php Pjax::end(); ?>
public function actionAccess($id){
$requestModel = $this->model->getRequestModel($id);
$this->model->requestToggleAccess($requestModel);
$access = $requestModel->checkAccess();
return $this->renderPartial('access.php', [
'id' => $id,
'access' => $access
]);
}
public function getRequestModel($id)
{
$requestModel = RequestModel::findOne($id);
return $requestModel;
}
public function requestToggleAccess($requestModel)
{
if (Yii::$app->request->isPjax) {
$access = $requestModel->checkAccess();
if( $access['provider'] ){
$request->accessRoleIds = null;
}else{
$request->accessRoleIds = [ROLE_PROVIDER, ROLE_PROVIDER_WORKER];
}
$request->saveAccess();
}
}
public function checkAccess()
{
return self::checkAccessBy($this->access);
}
public static function checkAccessBy($arr)
{
$access = [];
if(empty($arr)){return $access;}
foreach ($arr as $acc){
if(in_array($acc->role_id, [ROLE_PROVIDER, ROLE_PROVIDER_WORKER])){
$access['provider'] = true;
}
}
return $access;
}
The thing is that when initially the class is enabled
and I switch to disabled
, then everything works well, but when I switch in the reverse order from disabled
to enabled
, then I just go to this link '/request /'.$id.'/access'
and returns an empty page, it gives an error 500 without any details.
I'm trying to dump to find the problem
In the actionAccess
function after calling the function checkAccess()
, I added
var_dump($access['provider']);
exit();
And got an error
Undefined array key "provider"
Although in the neighboring function requestToggleAccess
there is the same checkAccess()
call, after which I added the same dump, and instead of an error I get boolean(true)
, which is what it should be
What could be the problem?
Look into requestToggleAccess
. The problem is that you assume $access['provider']
to exist. But inside checkAccessBy
(which is called by checkAccess
and whose return value will be assigned to $access
) you will see that $access['provider']
is not necessarily defined. We will return to this problem at the end of this answer, but first, let's make requestToggleAccess
less error-prone:
public function requestToggleAccess($requestModel)
{
if (Yii::$app->request->isPjax) {
$access = $requestModel->checkAccess();
if( $access['provider'] ?? false ){
$request->accessRoleIds = null;
}else{
$request->accessRoleIds = [ROLE_PROVIDER, ROLE_PROVIDER_WORKER];
}
$request->saveAccess();
}
}
I have merely added a ?? false
to your if
condition, that is, we know that $access
is defined at this point, but we avoid assuming that it has a value. Instead, we evaluate it and gather its value if it exists, defaulting to false
if it did not exist.
Now, let's see why checkAccessBy
did not specify $access['provider']
. There you receive an array (after self::checkAccessBy($this->access)
is called) and you loop that array. For each item in that array, you check whether in_array($acc->role_id, [ROLE_PROVIDER, ROLE_PROVIDER_WORKER])
and if so, then you set $access['provider']
to true
. But you never ever set it to false
. This is an improved version of the same method:
public static function checkAccessBy($arr)
{
$access = [
'provider' => false //We initialize provider with false and override it later if needed
];
if(empty($arr)){return $access;}
foreach ($arr as $acc){
if(in_array($acc->role_id, [ROLE_PROVIDER, ROLE_PROVIDER_WORKER])){
$access['provider'] = true;
}
}
return $access;
}
I have changed the initialization of $access
so it will have a provider element, which is initialized with true
and overriden later if needed.
Another change you might want to make is to return $access
inside the loop if its provider is to be set to false
, but I did not do that, because you might prefer to return it at the end of the method for styling or other purposes.