Kategorier
Yii Framework

Different fontend views based on user role, with Yii2 Framework

Or what I like to call “frontend environments”.

Before reading on, please note that this method depends on using the Yii2 authManager with Role Based Access Control (RBAC) and the yii2-app-advanced template.

“Environments” are located inside:
frontend/environments/{role_name}/

This path contains the controllers and views directories, etc.

First step is to “configure” the environments. The array key is the name of the directory where controllers and views are located (and the name of the user role), and the array value is the name of the user identityClass.

frontend/config/params.php

...
    'environments' => [
        'type1' => 'common\models\UserType1',
        'type2' => 'common\models\UserType2',
    ],
...

Next you will have to extend the UrlManager where controllerNamespace and viewPath are dynamically set based on the current identityClass.

common\components\web\UrlManager.php

<?php
namespace common\components\web;

use Yii;

class UrlManager extends \yii\web\UrlManager
{
    /**
     * {@inheritdoc}
     */
    public function parseRequest($request)
    {
        if (isset(Yii::$app->params['environments']) && !empty(Yii::$app->params['environments']) && ($identity = Yii::$app->user->identity)) {
            if ($key = array_search(get_class($identity), Yii::$app->params['environments'])) {
                Yii::$app->controllerNamespace = sprintf('frontend\environments\%s\controllers', $key);
                Yii::$app->viewPath = sprintf('@frontend/environments/%s/views', $key);
            }
        }

        return parent::parseRequest($request);
    }
}

For this to work, you will need to actually change the users identityClass. For this I use the authManager, where users are assigned the “type1” or “type2” role. To change the identityClass dynamically you will need to extend the default yii\web\User class.

common\components\web\User.php

<?php
namespace common\components\web;

use Yii;

class User extends \yii\web\User
{
    /**
     * {@inheritdoc}
     */
    public function getIdentity($autoRenew = true)
    {
        if (isset(Yii::$app->params['environments']) && !empty(Yii::$app->params['environments'])) {
            $session = Yii::$app->getSession();
            $id      = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null ;

            if ($this->identityClass == 'common\models\User' && $id !== null) {
                foreach (Yii::$app->params['environments'] as $key => $value) {
                    if (Yii::$app->authManager->getAssignment($key, $id)) {
                        $this->identityClass = $value;
                        break;
                    }
                }
            }
        }

        return parent::getIdentity($autoRenew);
    }
}

Now there is only one thing left. You need to configure Yii2 to use your extended components.

frontend/config/main.php

...
'user' => [
    'class' => 'common\components\web\User',
    ...
],
...
'urlManager' => [
    'class' => 'common\components\web\UrlManager',
    ...
],
...