// +---------------------------------------------------------------------- declare (strict_types = 1); namespace think\route\dispatch; use ReflectionClass; use ReflectionException; use ReflectionMethod; use think\App; use think\exception\ClassNotFoundException; use think\exception\HttpException; use think\helper\Str; use think\route\Dispatch; /** * Controller Dispatcher */ class Controller extends Dispatch { /** * 控制器名 * @var string */ protected $controller; /** * 操作名 * @var string */ protected $actionName; public function init(App $app) { parent::init($app); $result = $this->dispatch; if (is_string($result)) { $result = explode('/', $result); } // 获取应用名 $appName = $result[0] ?: config('app.default_app'); // 获取控制器名 $controller = strip_tags($result[1] ?: $this->rule->config('default_controller')); if (strpos($controller, '.')) { $pos = strrpos($controller, '.'); $this->controller = substr($controller, 0, $pos) . '.' . Str::studly(substr($controller, $pos + 1)); } else { $this->controller = Str::studly($controller); } $app->http->name($appName); $appNamespace = defined('APP_NAMESPACE') ? APP_NAMESPACE : 'app'; $app->setNamespace($appNamespace . '\\' . $appName); // 获取操作名 $result[2] = stristr($result[2], '?', true) ?: $result[2]; $this->actionName = strip_tags($result[2] ?: $this->rule->config('default_action')); // 设置当前请求的控制器、操作 $this->request ->setController($this->controller) ->setAction($this->actionName); } public function exec() { $this->app->event->trigger('ModuleInit'); $appName = $this->app->http->getName(); $appPath = $this->app->getAppPath() . $appName . DIRECTORY_SEPARATOR; // 加载应用event if (is_file($appPath . 'event.php')) { $this->app->loadEvent(include $appPath . 'event.php'); } // 加载应用service if (is_file($appPath . 'service.php')) { $services = include $appPath . 'service.php'; foreach ($services as $service) { $this->app->register($service); } } try { // 实例化控制器 $instance = $this->controller($this->controller); } catch (ClassNotFoundException $e) { throw new HttpException(404, 'controller not exists:' . $e->getClass()); } // 注册控制器中间件 $this->registerControllerMiddleware($instance); return $this->app->middleware->pipeline('controller') ->send($this->request) ->then(function () use ($instance) { // 获取当前操作名 $suffix = $this->rule->config('action_suffix'); $action = $this->actionName . $suffix; if (is_callable([$instance, $action])) { $vars = $this->request->param(); try { $reflect = new ReflectionMethod($instance, $action); // 严格获取当前操作方法名 $actionName = $reflect->getName(); if ($suffix) { $actionName = substr($actionName, 0, -strlen($suffix)); } $this->request->setAction($actionName); } catch (ReflectionException $e) { $reflect = new ReflectionMethod($instance, '__call'); $vars = [$action, $vars]; $this->request->setAction($action); } } else { // 操作不存在 throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); } $this->app->event->trigger('ActionBegin'); $data = $this->app->invokeReflectMethod($instance, $reflect, $vars); return $this->autoResponse($data); }); } /** * 使用反射机制注册控制器中间件 * @access public * @param object $controller 控制器实例 * @return void */ protected function registerControllerMiddleware($controller): void { $class = new ReflectionClass($controller); if ($class->hasProperty('middleware')) { $reflectionProperty = $class->getProperty('middleware'); $reflectionProperty->setAccessible(true); $middlewares = $reflectionProperty->getValue($controller); foreach ($middlewares as $key => $val) { if (!is_int($key)) { if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) { return strtolower($item); }, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) { continue; } elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) { return strtolower($item); }, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) { continue; } else { $val = $key; } } if (is_string($val) && strpos($val, ':')) { $val = explode(':', $val); if (count($val) > 1) { $val = [$val[0], array_slice($val, 1)]; } } $this->app->middleware->controller($val); } } } /** * 实例化访问控制器 * @access public * @param string $name 资源地址 * @return object * @throws ClassNotFoundException */ public function controller(string $name) { $suffix = $this->rule->config('controller_suffix') ? 'Controller' : ''; $controllerLayer = $this->rule->config('controller_layer') ?: 'controller'; $emptyController = $this->rule->config('empty_controller') ?: 'Error'; $class = $this->app->parseClass($controllerLayer, $name . $suffix); if (class_exists($class)) { return $this->app->make($class, [], true); } elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) { return $this->app->make($emptyClass, [], true); } throw new ClassNotFoundException('class not exists:' . $class, $class); } }