<?php<liu21st@gmail.com>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;
class Controller extends Dispatch
{
protected $controller;
protected $actionName;
public function init(App $app)
{
parent::init($app);
$result = $this->dispatch;
if (is_string($result)) {
$result = explode('/', $result);
}
$controller = strip_tags($result[0] ?: $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);
}
$this->actionName = strip_tags($result[1] ?: $this->rule->config('default_action'));
$this->request
->setController($this->controller)
->setAction($this->actionName);
}
public function exec()
{
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 . '()');
}
$data = $this->app->invokeReflectMethod($instance, $reflect, $vars);
return $this->autoResponse($data);
});
}
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);
}
}
}
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);
}
}