Action.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <?php
  2. /**
  3. * @link https://github.com/yii2tech
  4. * @copyright Copyright (c) 2015 Yii2tech
  5. * @license [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
  6. */
  7. namespace backend\actions;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\base\Model;
  11. use yii\db\ActiveRecordInterface;
  12. use yii\helpers\Inflector;
  13. use yii\helpers\StringHelper;
  14. use yii\web\NotFoundHttpException;
  15. /**
  16. * Action is a base class for administration panel actions.
  17. *
  18. * @author Paul Klimov <klimov.paul@gmail.com>
  19. * @since 1.0
  20. */
  21. class Action extends \yii\base\Action
  22. {
  23. /**
  24. * @var callable a PHP callable that will be called to return the model corresponding
  25. * to the specified primary key value. If not set, [[findModel()]] will be used instead.
  26. * The signature of the callable should be:
  27. *
  28. * ```php
  29. * function ($id, $action) {
  30. * // $id is the primary key value. If composite primary key, the key values
  31. * // will be separated by comma.
  32. * // $action is the action object currently running
  33. * }
  34. * ```
  35. *
  36. * The callable should return the model found, or throw an exception if not found.
  37. */
  38. public $findModel;
  39. /**
  40. * @var string ID of the controller action, which user should be redirected to on success.
  41. * This property overrides the value set by [[setReturnAction()]] method.
  42. * @see getReturnAction()
  43. * @see returnUrl
  44. */
  45. public $returnAction;
  46. /**
  47. * @var string|array|callable URL, which user should be redirected to on success.
  48. * This could be a plain string URL, URL array configuration or callable, which returns actual URL.
  49. * The signature for the callable is following:
  50. *
  51. * ```
  52. * string|array function (Model $model) {}
  53. * ```
  54. *
  55. * Note: actual list of the callable arguments may vary depending on particular action class.
  56. *
  57. * Note: this option takes precedence over [[returnAction]] related logic.
  58. *
  59. * @see returnAction
  60. */
  61. public $returnUrl;
  62. /**
  63. * Returns the data model based on the primary key given.
  64. * If the data model is not found, a 404 HTTP exception will be raised.
  65. * @param string $id the ID of the model to be loaded. If the model has a composite primary key,
  66. * the ID must be a string of the primary key values separated by commas.
  67. * The order of the primary key values should follow that returned by the `primaryKey()` method
  68. * of the model.
  69. * @return ActiveRecordInterface|Model the model found
  70. * @throws NotFoundHttpException if the model cannot be found
  71. * @throws InvalidConfigException on invalid configuration
  72. */
  73. public function findModel($id)
  74. {
  75. if ($this->findModel !== null) {
  76. return call_user_func($this->findModel, $id, $this);
  77. } elseif ($this->controller->hasMethod('findModel')) {
  78. return call_user_func([$this->controller, 'findModel'], $id, $this);
  79. } else {
  80. throw new InvalidConfigException('Either "' . get_class($this) . '::findModel" must be set or controller must declare method "findModel()".');
  81. }
  82. }
  83. /**
  84. * Checks whether action with specified ID exists in owner controller.
  85. * @param string $id action ID.
  86. * @return boolean whether action exists or not.
  87. */
  88. public function actionExists($id)
  89. {
  90. $inlineActionMethodName = 'action' . Inflector::camelize($id);
  91. if (method_exists($this->controller, $inlineActionMethodName)) {
  92. return true;
  93. }
  94. if (array_key_exists($id, $this->controller->actions())) {
  95. return true;
  96. }
  97. return false;
  98. }
  99. /**
  100. * Sets the return action ID.
  101. * @param string|null $actionId action ID, if not set current action will be used.
  102. */
  103. public function setReturnAction($actionId = null)
  104. {
  105. if ($actionId === null) {
  106. $actionId = $this->id;
  107. }
  108. if (strpos($actionId, '/') === false) {
  109. $actionId = $this->controller->getUniqueId() . '/' . $actionId;
  110. }
  111. $sessionKey = '__adminReturnAction';
  112. Yii::$app->getSession()->set($sessionKey, $actionId);
  113. }
  114. /**
  115. * Returns the ID of action, which should be used for return redirect.
  116. * If action belongs to another controller or does not exist in current controller - 'index' is returned.
  117. * @param string $defaultActionId default action ID.
  118. * @return string action ID.
  119. */
  120. public function getReturnAction($defaultActionId = 'index')
  121. {
  122. if ($this->returnAction !== null) {
  123. return $this->returnAction;
  124. }
  125. $sessionKey = '__adminReturnAction';
  126. $actionId = Yii::$app->getSession()->get($sessionKey, $defaultActionId);
  127. $actionId = trim($actionId, '/');
  128. if ($actionId === 'index') {
  129. return $actionId;
  130. }
  131. if (strpos($actionId, '/') !== false) {
  132. $controllerId = StringHelper::dirname($actionId);
  133. if ($controllerId !== $this->controller->getUniqueId()) {
  134. return 'index';
  135. }
  136. $actionId = StringHelper::basename($actionId);
  137. }
  138. if (!$this->actionExists($actionId)) {
  139. return 'index';
  140. }
  141. return $actionId;
  142. }
  143. /**
  144. * @param string $defaultActionId default action ID.
  145. * @param ActiveRecordInterface|Model|null $model model being processed by action.
  146. * @return array|string URL
  147. */
  148. public function createReturnUrl($defaultActionId = 'index', $model = null)
  149. {
  150. if ($this->returnUrl !== null) {
  151. if (is_string($this->returnUrl)) {
  152. return $this->returnUrl;
  153. }
  154. if (!is_callable($this->returnUrl, true)) {
  155. return $this->returnUrl;
  156. }
  157. $args = func_get_args();
  158. array_shift($args);
  159. return call_user_func_array($this->returnUrl, $args);
  160. }
  161. $actionId = $this->getReturnAction($defaultActionId);
  162. $queryParams = Yii::$app->request->getQueryParams();
  163. unset($queryParams['id']);
  164. $url = array_merge(
  165. [$actionId],
  166. $queryParams
  167. );
  168. if (is_object($model) && in_array($actionId, ['view', 'update'], true)) {
  169. $url = array_merge(
  170. $url,
  171. ['id' => implode(',', array_values($model->getPrimaryKey(true)))]
  172. );
  173. }
  174. return $url;
  175. }
  176. /**
  177. * Sets a flash message.
  178. * @param string|array|null $message flash message(s) to be set.
  179. * If plain string is passed, it will be used as a message with the key 'success'.
  180. * You may specify multiple messages as an array, if element name is not integer, it will be used as a key,
  181. * otherwise 'success' will be used as key.
  182. * If empty value passed, no flash will be set.
  183. * Particular message value can be a PHP callback, which should return actual message. Such callback, should
  184. * have following signature:
  185. *
  186. * ```php
  187. * function (array $params) {
  188. * // return string
  189. * }
  190. * ```
  191. *
  192. * @param array $params extra params for the message parsing in format: key => value.
  193. */
  194. public function setFlash($message, $params = [])
  195. {
  196. if (empty($message)) {
  197. return;
  198. }
  199. $session = Yii::$app->session;
  200. foreach ((array)$message as $key => $value) {
  201. if (is_scalar($value)) {
  202. $value = preg_replace_callback("/{(\\w+)}/", function ($matches) use ($params) {
  203. $paramName = $matches[1];
  204. return isset($params[$paramName]) ? $params[$paramName] : $paramName;
  205. }, $value);
  206. } else {
  207. $value = call_user_func($value, $params);
  208. }
  209. if (is_int($key)) {
  210. $session->setFlash('success', $value);
  211. } else {
  212. $session->setFlash($key, $value);
  213. }
  214. }
  215. }
  216. }