ErrorAction.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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\web;
  8. use Yii;
  9. use yii\base\Action;
  10. use yii\base\Exception;
  11. use yii\base\UserException;
  12. /**
  13. * ErrorAction displays application errors using a specified view.
  14. *
  15. * To use ErrorAction, you need to do the following steps:
  16. *
  17. * First, declare an action of ErrorAction type in the `actions()` method of your `SiteController`
  18. * class (or whatever controller you prefer), like the following:
  19. *
  20. * ```php
  21. * public function actions()
  22. * {
  23. * return [
  24. * 'error' => ['class' => 'yii\web\ErrorAction'],
  25. * ];
  26. * }
  27. * ```
  28. *
  29. * Then, create a view file for this action. If the route of your error action is `site/error`, then
  30. * the view file should be `views/site/error.php`. In this view file, the following variables are available:
  31. *
  32. * - `$name`: the error name
  33. * - `$message`: the error message
  34. * - `$exception`: the exception being handled
  35. *
  36. * Finally, configure the "errorHandler" application component as follows,
  37. *
  38. * ```php
  39. * 'errorHandler' => [
  40. * 'errorAction' => 'site/error',
  41. * ]
  42. * ```
  43. *
  44. * @author Qiang Xue <qiang.xue@gmail.com>
  45. * @author Dmitry Naumenko <d.naumenko.a@gmail.com>
  46. * @since 2.0
  47. */
  48. class ErrorAction extends Action
  49. {
  50. /**
  51. * @var string the view file to be rendered. If not set, it will take the value of [[id]].
  52. * That means, if you name the action as "error" in "SiteController", then the view name
  53. * would be "error", and the corresponding view file would be "views/site/error.php".
  54. */
  55. public $view;
  56. /**
  57. * @var string the name of the error when the exception name cannot be determined.
  58. * Defaults to "Error".
  59. */
  60. public $defaultName;
  61. /**
  62. * @var string the message to be displayed when the exception message contains sensitive information.
  63. * Defaults to "An internal server error occurred.".
  64. */
  65. public $defaultMessage;
  66. /**
  67. * @var string|false|null the name of the layout to be applied to this error action view.
  68. * If not set, the layout configured in the controller will be used.
  69. * @see \yii\base\Controller::$layout
  70. * @since 2.0.14
  71. */
  72. public $layout;
  73. /**
  74. * @var \Exception the exception object, normally is filled on [[init()]] method call.
  75. * @see [[findException()]] to know default way of obtaining exception.
  76. * @since 2.0.11
  77. */
  78. protected $exception;
  79. /**
  80. * {@inheritdoc}
  81. */
  82. public function init()
  83. {
  84. $this->exception = $this->findException();
  85. if ($this->defaultMessage === null) {
  86. $this->defaultMessage = Yii::t('yii', 'An internal server error occurred.');
  87. }
  88. if ($this->defaultName === null) {
  89. $this->defaultName = Yii::t('yii', 'Error');
  90. }
  91. }
  92. /**
  93. * Runs the action.
  94. *
  95. * @return string result content
  96. */
  97. public function run()
  98. {
  99. if ($this->layout !== null) {
  100. $this->controller->layout = $this->layout;
  101. }
  102. Yii::$app->getResponse()->setStatusCodeByException($this->exception);
  103. if (Yii::$app->getRequest()->getIsAjax()) {
  104. return $this->renderAjaxResponse();
  105. }
  106. return $this->renderHtmlResponse();
  107. }
  108. /**
  109. * Builds string that represents the exception.
  110. * Normally used to generate a response to AJAX request.
  111. * @return string
  112. * @since 2.0.11
  113. */
  114. protected function renderAjaxResponse()
  115. {
  116. return $this->getExceptionName() . ': ' . $this->getExceptionMessage();
  117. }
  118. /**
  119. * Renders a view that represents the exception.
  120. * @return string
  121. * @since 2.0.11
  122. */
  123. protected function renderHtmlResponse()
  124. {
  125. return $this->controller->render($this->view ?: $this->id, $this->getViewRenderParams());
  126. }
  127. /**
  128. * Builds array of parameters that will be passed to the view.
  129. * @return array
  130. * @since 2.0.11
  131. */
  132. protected function getViewRenderParams()
  133. {
  134. return [
  135. 'name' => $this->getExceptionName(),
  136. 'message' => $this->getExceptionMessage(),
  137. 'exception' => $this->exception,
  138. ];
  139. }
  140. /**
  141. * Gets exception from the [[yii\web\ErrorHandler|ErrorHandler]] component.
  142. * In case there is no exception in the component, treat as the action has been invoked
  143. * not from error handler, but by direct route, so '404 Not Found' error will be displayed.
  144. * @return \Exception
  145. * @since 2.0.11
  146. */
  147. protected function findException()
  148. {
  149. if (($exception = Yii::$app->getErrorHandler()->exception) === null) {
  150. $exception = new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
  151. }
  152. return $exception;
  153. }
  154. /**
  155. * Gets the code from the [[exception]].
  156. * @return mixed
  157. * @since 2.0.11
  158. */
  159. protected function getExceptionCode()
  160. {
  161. if ($this->exception instanceof HttpException) {
  162. return $this->exception->statusCode;
  163. }
  164. return $this->exception->getCode();
  165. }
  166. /**
  167. * Returns the exception name, followed by the code (if present).
  168. *
  169. * @return string
  170. * @since 2.0.11
  171. */
  172. protected function getExceptionName()
  173. {
  174. if ($this->exception instanceof Exception) {
  175. $name = $this->exception->getName();
  176. } else {
  177. $name = $this->defaultName;
  178. }
  179. if ($code = $this->getExceptionCode()) {
  180. $name .= " (#$code)";
  181. }
  182. return $name;
  183. }
  184. /**
  185. * Returns the [[exception]] message for [[yii\base\UserException]] only.
  186. * For other cases [[defaultMessage]] will be returned.
  187. * @return string
  188. * @since 2.0.11
  189. */
  190. protected function getExceptionMessage()
  191. {
  192. if ($this->exception instanceof UserException) {
  193. return $this->exception->getMessage();
  194. }
  195. return $this->defaultMessage;
  196. }
  197. }