UserPanel.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\debug\panels;
  8. use Yii;
  9. use yii\base\Controller;
  10. use yii\base\Model;
  11. use yii\base\InvalidConfigException;
  12. use yii\data\ArrayDataProvider;
  13. use yii\data\DataProviderInterface;
  14. use yii\db\ActiveRecord;
  15. use yii\debug\controllers\UserController;
  16. use yii\debug\models\search\UserSearchInterface;
  17. use yii\debug\models\UserSwitch;
  18. use yii\debug\Panel;
  19. use yii\filters\AccessControl;
  20. use yii\filters\AccessRule;
  21. use yii\helpers\ArrayHelper;
  22. use yii\helpers\VarDumper;
  23. use yii\web\IdentityInterface;
  24. /**
  25. * Debugger panel that collects and displays user data.
  26. *
  27. * @property DataProviderInterface $userDataProvider This property is read-only.
  28. * @property Model|UserSearchInterface $usersFilterModel This property is read-only.
  29. *
  30. * @author Daniel Gomez Pan <pana_1990@hotmail.com>
  31. * @since 2.0.8
  32. */
  33. class UserPanel extends Panel
  34. {
  35. /**
  36. * @var array the rule which defines who allowed to switch user identity.
  37. * Access Control Filter single rule. Ignore: actions, controllers, verbs.
  38. * Settable: allow, roles, ips, matchCallback, denyCallback.
  39. * By default deny for everyone. Recommendation: can allow for administrator
  40. * or developer (if implement) role: ['allow' => true, 'roles' => ['admin']]
  41. * @see http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
  42. * @since 2.0.10
  43. */
  44. public $ruleUserSwitch = [
  45. 'allow' => false,
  46. ];
  47. /**
  48. * @var UserSwitch object of switching users
  49. * @since 2.0.10
  50. */
  51. public $userSwitch;
  52. /**
  53. * @var Model|UserSearchInterface Implements of User model with search method.
  54. * @since 2.0.10
  55. */
  56. public $filterModel;
  57. /**
  58. * @var array allowed columns for GridView.
  59. * @see http://www.yiiframework.com/doc-2.0/yii-grid-gridview.html#$columns-detail
  60. * @since 2.0.10
  61. */
  62. public $filterColumns = [];
  63. /**
  64. * @inheritdoc
  65. */
  66. public function init()
  67. {
  68. if (
  69. !$this->isEnabled()
  70. || Yii::$app->getUser()->isGuest
  71. ) {
  72. return;
  73. }
  74. $this->userSwitch = new UserSwitch();
  75. $this->addAccesRules();
  76. if (!is_object($this->filterModel)
  77. && class_exists($this->filterModel)
  78. && in_array('yii\debug\models\search\UserSearchInterface', class_implements($this->filterModel), true)
  79. ) {
  80. $this->filterModel = new $this->filterModel;
  81. } elseif (Yii::$app->user && Yii::$app->user->identityClass) {
  82. if (is_subclass_of(Yii::$app->user->identityClass, ActiveRecord::className())) {
  83. $this->filterModel = new \yii\debug\models\search\User();
  84. }
  85. }
  86. }
  87. /**
  88. * Add ACF rule. AccessControl attach to debug module.
  89. * Access rule for main user.
  90. */
  91. private function addAccesRules()
  92. {
  93. $this->ruleUserSwitch['controllers'] = [$this->module->id . '/user'];
  94. $this->module->attachBehavior(
  95. 'access_debug',
  96. [
  97. 'class' => AccessControl::className(),
  98. 'only' => [$this->module->id . '/user', $this->module->id . '/default'],
  99. 'user' => $this->userSwitch->getMainUser(),
  100. 'rules' => [
  101. $this->ruleUserSwitch,
  102. ],
  103. ]
  104. );
  105. }
  106. /**
  107. * Get model for GridView -> FilterModel
  108. * @return Model|UserSearchInterface
  109. */
  110. public function getUsersFilterModel()
  111. {
  112. return $this->filterModel;
  113. }
  114. /**
  115. * Get model for GridView -> DataProvider
  116. * @return DataProviderInterface
  117. */
  118. public function getUserDataProvider()
  119. {
  120. return $this->getUsersFilterModel()->search(Yii::$app->request->queryParams);
  121. }
  122. /**
  123. * Check is available search of users
  124. * @return bool
  125. */
  126. public function canSearchUsers()
  127. {
  128. return (isset($this->filterModel) &&
  129. $this->filterModel instanceof Model &&
  130. $this->filterModel->hasMethod('search')
  131. );
  132. }
  133. /**
  134. * Check can main user switch identity.
  135. * @return bool
  136. */
  137. public function canSwitchUser()
  138. {
  139. if (Yii::$app->user->isGuest) {
  140. return false;
  141. }
  142. $allowSwitchUser = false;
  143. $rule = new AccessRule($this->ruleUserSwitch);
  144. /** @var Controller $userController */
  145. $userController = null;
  146. $controller = $this->module->createController('user');
  147. if (isset($controller[0]) && $controller[0] instanceof UserController) {
  148. $userController = $controller[0];
  149. }
  150. //check by rule
  151. if ($userController) {
  152. $action = $userController->createAction('set-identity');
  153. $user = $this->userSwitch->getMainUser();
  154. $request = Yii::$app->request;
  155. $allowSwitchUser = $rule->allows($action, $user, $request) ?: false;
  156. }
  157. return $allowSwitchUser;
  158. }
  159. /**
  160. * @inheritdoc
  161. */
  162. public function getName()
  163. {
  164. return 'User';
  165. }
  166. /**
  167. * @inheritdoc
  168. */
  169. public function getSummary()
  170. {
  171. return Yii::$app->view->render('panels/user/summary', ['panel' => $this]);
  172. }
  173. /**
  174. * @inheritdoc
  175. */
  176. public function getDetail()
  177. {
  178. return Yii::$app->view->render('panels/user/detail', ['panel' => $this]);
  179. }
  180. /**
  181. * @inheritdoc
  182. */
  183. public function save()
  184. {
  185. $identity = Yii::$app->user->identity;
  186. if (!isset($identity)) {
  187. return;
  188. }
  189. $rolesProvider = null;
  190. $permissionsProvider = null;
  191. try {
  192. $authManager = Yii::$app->getAuthManager();
  193. if ($authManager instanceof \yii\rbac\ManagerInterface) {
  194. $roles = ArrayHelper::toArray($authManager->getRolesByUser(Yii::$app->getUser()->id));
  195. foreach ($roles as &$role) {
  196. $role['data'] = $this->dataToString($role['data']);
  197. }
  198. unset($role);
  199. $rolesProvider = new ArrayDataProvider([
  200. 'allModels' => $roles,
  201. ]);
  202. $permissions = ArrayHelper::toArray($authManager->getPermissionsByUser(Yii::$app->getUser()->id));
  203. foreach ($permissions as &$permission) {
  204. $permission['data'] = $this->dataToString($permission['data']);
  205. }
  206. unset($permission);
  207. $permissionsProvider = new ArrayDataProvider([
  208. 'allModels' => $permissions,
  209. ]);
  210. }
  211. } catch (\Exception $e) {
  212. // ignore auth manager misconfiguration
  213. }
  214. $identityData = $this->identityData($identity);
  215. foreach ($identityData as $key => $value) {
  216. $identityData[$key] = VarDumper::dumpAsString($value);
  217. }
  218. // If the identity is a model, let it specify the attribute labels
  219. if ($identity instanceof Model) {
  220. $attributes = [];
  221. foreach (array_keys($identityData) as $attribute) {
  222. $attributes[] = [
  223. 'attribute' => $attribute,
  224. 'label' => $identity->getAttributeLabel($attribute),
  225. ];
  226. }
  227. } else {
  228. // Let the DetailView widget figure the labels out
  229. $attributes = null;
  230. }
  231. return [
  232. 'id' => $identity->getId(),
  233. 'identity' => $identityData,
  234. 'attributes' => $attributes,
  235. 'rolesProvider' => $rolesProvider,
  236. 'permissionsProvider' => $permissionsProvider,
  237. ];
  238. }
  239. /**
  240. * @inheritdoc
  241. */
  242. public function isEnabled()
  243. {
  244. try {
  245. Yii::$app->getUser();
  246. } catch (InvalidConfigException $exception) {
  247. return false;
  248. }
  249. return true;
  250. }
  251. /**
  252. * Converts mixed data to string
  253. *
  254. * @param mixed $data
  255. * @return string
  256. */
  257. protected function dataToString($data)
  258. {
  259. if (is_string($data)) {
  260. return $data;
  261. }
  262. return VarDumper::export($data);
  263. }
  264. /**
  265. * Returns the array that should be set on [[\yii\widgets\DetailView::model]]
  266. *
  267. * @param IdentityInterface $identity
  268. * @return array
  269. */
  270. protected function identityData($identity)
  271. {
  272. if ($identity instanceof Model) {
  273. return $identity->getAttributes();
  274. }
  275. return get_object_vars($identity);
  276. }
  277. }