
В более-менее крупных проектах большое значение имеет принцип единственной ответственности https://ru.wikipedia.org . В рамках данной статьи - класс сущности (модели) User не должен содержать в себе методы связанные с авторизацией пользователей, этим должен заниматься другой класс. Теперь подробнее.
Откроем класс сущности User (обычно в common\models или app\models), видим:
class User extends ActiveRecord implements IdentityInterface
класс реализует интерфейс IdentityInterface, а значит содержит в себе методы этого интерфейса:
public static function findIdentity($id)
public static function findIdentityByAccessToken($token, $type = null)
public function getId()
public function getAuthKey()
public function validateAuthKey($authKey)
Данные методы используются при авторизации/идентификации пользователей.
Сам IdentityInterface можно открыть в файле vendor/yiisoft/yii2/web/IdentityInterface.php
В конфигурационных файлах (frontend, backend ...) config/main.php для Yii-2 версии advanced или config/web.php для Yii-2 версии basic указано (по-умолчанию):
'user' => [ 'identityClass' => 'app\models\User', …видно, что компонент приложения «user» (находится в vendor/yiisoft/yii2/web/User.php) получает в качестве значения для своего свойства identityClass класс сущности app\models\User и использует его методы.
Иногда класс сущности слишком разрастается за счет создания все новых методов, особенно если необходимо создавать дополнительные способы авторизации пользователей, например для API с помощью OAuth.
Поэтому имеет смысл вынести методы касающиеся авторизации в отдельный класс и уже там что-то добавлять/менять, не трогая User.
Поэтому, создаем например в common\auth\Identity.php:
<?php namespace common\auth; use Yii; use shop\entities\User\User; use shop\repositories\UserRepository; use yii\base\NotSupportedException; use yii\web\IdentityInterface; class Identity implements IdentityInterface { private $user; public function __construct(User $user) { $this->user = $user; } /** * {@inheritdoc} */ public static function findIdentity($id) { $user = User::findOne(['id' => $id, 'status' => User::STATUS_ACTIVE]); return $user ? new self($user): null; } /** * {@inheritdoc} */ public static function findIdentityByAccessToken($token, $type = null) { throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); } /** * {@inheritdoc} */ public function getId(): int { return $this->user->getPrimaryKey(); } /** * {@inheritdoc} */ public function getAuthKey(): string { return $this->user->auth_key; } /** * {@inheritdoc} */ public function validateAuthKey($authKey) { return $this->getAuthKey() === $authKey; } /** * При обращении к свойствам сущности user * @param $name * @return mixed */ public function __get($name) { return $this->user->$name; } /** * При обращении к методам сущности user * @param $methodName * @param $args * @return mixed */ public function __call($methodName, $args) { return $this->user->$methodName($args); } }
Т.е. переносим сюда указанные выше 5 методов из сущности User. Дополнительно, для доступа к сущности создаем конструктор и методы __get, __call которые позволят получать доступ к свойствам и методам сущности авторизованного пользователя таким образом:
Yii::$app->user->getIdentity()->isAdmin()или
/** @var $user User */ $user = Yii::$app->user->getIdentity(); $email = $user->email
Соответственно удаляем эти 5 методов из User и его привязку к интерфейсу:
… implements IdentityInterface
Теперь осталось указать в конфигурации, что используется наш класс Identity вместо сущности User. Для этого во всех конфигах (и фронтенда и бэкенда) поменять
'user' => [ 'identityClass' => 'shop\entities\User\User',на
'user' => [ 'identityClass' => \common\auth\Identity::class,
Потом везде где встречается вызов
Yii::$app->user->login($user, …)
меняем на
Yii::$app->user->login(new Identity($user), …)
Если вы сохранили стандартную структуру фреймворка по части авторизации, то в таких файлах:
в models/LoginForm.php меняем
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);на
return Yii::$app->user->login(new Identity($this->getUser()), $this->rememberMe ? 3600 * 24 * 30 : 0);
Для версии advanced так же в SiteController (frontend и backend) в методе actionSignup меняем
if (Yii::$app->getUser()->login($user)) {на
if (Yii::$app->getUser()->login(new Identity($user))) {
Таким образом мы вынесли методы связанные с авторизацией пользователей в отдельный класс который теперь можно отдельно расширять и наследовать и разгрузили сущность User.