Controller.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think\route\dispatch;
  13. use ReflectionClass;
  14. use ReflectionException;
  15. use ReflectionMethod;
  16. use think\App;
  17. use think\exception\ClassNotFoundException;
  18. use think\exception\HttpException;
  19. use think\helper\Str;
  20. use think\route\Dispatch;
  21. /**
  22. * Controller Dispatcher
  23. */
  24. class Controller extends Dispatch
  25. {
  26. /**
  27. * 控制器名
  28. * @var string
  29. */
  30. protected $controller;
  31. /**
  32. * 操作名
  33. * @var string
  34. */
  35. protected $actionName;
  36. public function init(App $app)
  37. {
  38. parent::init($app);
  39. $result = $this->dispatch;
  40. if (is_string($result)) {
  41. $result = explode('/', $result);
  42. }
  43. // 获取应用名
  44. $appName = $result[0] ?: config('app.default_app');
  45. // 获取控制器名
  46. $controller = strip_tags($result[1] ?: $this->rule->config('default_controller'));
  47. if (strpos($controller, '.')) {
  48. $pos = strrpos($controller, '.');
  49. $this->controller = substr($controller, 0, $pos) . '.' . Str::studly(substr($controller, $pos + 1));
  50. } else {
  51. $this->controller = Str::studly($controller);
  52. }
  53. $app->http->name($appName);
  54. $appNamespace = defined('APP_NAMESPACE') ? APP_NAMESPACE : 'app';
  55. $app->setNamespace($appNamespace . '\\' . $appName);
  56. // 获取操作名
  57. $result[2] = stristr($result[2], '?', true) ?: $result[2];
  58. $this->actionName = strip_tags($result[2] ?: $this->rule->config('default_action'));
  59. // 设置当前请求的控制器、操作
  60. $this->request
  61. ->setController($this->controller)
  62. ->setAction($this->actionName);
  63. }
  64. public function exec()
  65. {
  66. $this->app->event->trigger('ModuleInit');
  67. $appName = $this->app->http->getName();
  68. $appPath = $this->app->getAppPath() . $appName . DIRECTORY_SEPARATOR;
  69. // 加载应用event
  70. if (is_file($appPath . 'event.php')) {
  71. $this->app->loadEvent(include $appPath . 'event.php');
  72. }
  73. // 加载应用service
  74. if (is_file($appPath . 'service.php')) {
  75. $services = include $appPath . 'service.php';
  76. foreach ($services as $service) {
  77. $this->app->register($service);
  78. }
  79. }
  80. try {
  81. // 实例化控制器
  82. $instance = $this->controller($this->controller);
  83. } catch (ClassNotFoundException $e) {
  84. throw new HttpException(404, 'controller not exists:' . $e->getClass());
  85. }
  86. // 注册控制器中间件
  87. $this->registerControllerMiddleware($instance);
  88. return $this->app->middleware->pipeline('controller')
  89. ->send($this->request)
  90. ->then(function () use ($instance) {
  91. // 获取当前操作名
  92. $suffix = $this->rule->config('action_suffix');
  93. $action = $this->actionName . $suffix;
  94. if (is_callable([$instance, $action])) {
  95. $vars = $this->request->param();
  96. try {
  97. $reflect = new ReflectionMethod($instance, $action);
  98. // 严格获取当前操作方法名
  99. $actionName = $reflect->getName();
  100. if ($suffix) {
  101. $actionName = substr($actionName, 0, -strlen($suffix));
  102. }
  103. $this->request->setAction($actionName);
  104. } catch (ReflectionException $e) {
  105. $reflect = new ReflectionMethod($instance, '__call');
  106. $vars = [$action, $vars];
  107. $this->request->setAction($action);
  108. }
  109. } else {
  110. // 操作不存在
  111. throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
  112. }
  113. $this->app->event->trigger('ActionBegin');
  114. $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);
  115. return $this->autoResponse($data);
  116. });
  117. }
  118. /**
  119. * 使用反射机制注册控制器中间件
  120. * @access public
  121. * @param object $controller 控制器实例
  122. * @return void
  123. */
  124. protected function registerControllerMiddleware($controller): void
  125. {
  126. $class = new ReflectionClass($controller);
  127. if ($class->hasProperty('middleware')) {
  128. $reflectionProperty = $class->getProperty('middleware');
  129. $reflectionProperty->setAccessible(true);
  130. $middlewares = $reflectionProperty->getValue($controller);
  131. foreach ($middlewares as $key => $val) {
  132. if (!is_int($key)) {
  133. if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) {
  134. return strtolower($item);
  135. }, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) {
  136. continue;
  137. } elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) {
  138. return strtolower($item);
  139. }, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) {
  140. continue;
  141. } else {
  142. $val = $key;
  143. }
  144. }
  145. if (is_string($val) && strpos($val, ':')) {
  146. $val = explode(':', $val);
  147. if (count($val) > 1) {
  148. $val = [$val[0], array_slice($val, 1)];
  149. }
  150. }
  151. $this->app->middleware->controller($val);
  152. }
  153. }
  154. }
  155. /**
  156. * 实例化访问控制器
  157. * @access public
  158. * @param string $name 资源地址
  159. * @return object
  160. * @throws ClassNotFoundException
  161. */
  162. public function controller(string $name)
  163. {
  164. $suffix = $this->rule->config('controller_suffix') ? 'Controller' : '';
  165. $controllerLayer = $this->rule->config('controller_layer') ?: 'controller';
  166. $emptyController = $this->rule->config('empty_controller') ?: 'Error';
  167. $class = $this->app->parseClass($controllerLayer, $name . $suffix);
  168. if (class_exists($class)) {
  169. return $this->app->make($class, [], true);
  170. } elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) {
  171. return $this->app->make($emptyClass, [], true);
  172. }
  173. throw new ClassNotFoundException('class not exists:' . $class, $class);
  174. }
  175. }