<?php
namespace laytp\library;
use think\exception\HttpException;
use think\facade\Config;
use think\facade\Middleware;
use think\facade\Request;
use think\Response;
use think\Route;
class PluginRoute extends Route
{
protected $middleware;
protected $actionName;
public function execute($plugin = null)
{
$this->middleware = Middleware::instance();
$this->request = Request::instance();
$url = $this->request->url();
$urlArr = array_filter(explode('/', $url));
$controller = isset($urlArr[3]) ? $urlArr[3] : 'Index';
$plugin = $plugin ? trim(strtolower($plugin)) : $plugin;
if (!defined('LT_PLUGIN')) {
define('LT_PLUGIN', $plugin);
}
$controller = $controller ? str_replace('.', '\\', trim($controller)) : 'Index';
$classAndAction = $this->getPluginClassAndAction($plugin, $controller);
$this->request->setController($controller)->setAction($classAndAction['action']);
$common_func_file = app()->getRootPath() . DS . 'plugin' . DS . $plugin . DS . 'common.php';
if (file_exists($common_func_file)) {
include_once app()->getRootPath() . DS . 'plugin' . DS . $plugin . DS . 'common.php';
}
$class = $classAndAction['class'];
$action = $classAndAction['action'];
$instance = app()->make($class, [], true);
$this->actionName = $action;
try {
$this->registerControllerMiddleware($instance);
} catch (\ReflectionException $e) {
throw new HttpException(500, $e->getMessage());
}
return $this->middleware->pipeline('controller')
->send($this->request)
->then(function () use ($instance) {
$suffix = Config::get('route.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 (\Exception $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);
});
}
public function getPluginClassAndAction($plugin, $controller)
{
$request = Request::instance();
$url = $request->url();
$urlArr = array_filter(explode('/', $url));
$controllerArr = explode("\\", $controller);
$controllerArr[count($controllerArr) - 1] = ucfirst($controllerArr[count($controllerArr) - 1]);
$controller = implode("\\", $controllerArr);
$class = 'plugin\\' . $plugin . '\\controller\\' . $controller;
if (!class_exists($class)) {
throw new HttpException(404, $class . '类不存在');
}
$class = 'plugin\\' . $plugin . '\\controller\\' . $controller;
if (isset($urlArr[4])) {
$action_param = explode('?', $urlArr[4]);
$action = $action_param[0];
} else {
$action = 'index';
}
$action = $action ? str_replace('.' . Config::get("route.url_html_suffix"), '', trim($action)) : 'index';
if (!method_exists($class, $action)) {
throw new HttpException(404, $class . '->' . $action . '()' . '方法不存在');
}
return ['class' => $class, 'action' => $action];
}
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->middleware->controller($val);
}
}
}
protected function autoResponse($data): Response
{
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
$type = $this->request->isJson() ? 'json' : 'html';
$response = Response::create($data, $type);
} else {
$data = ob_get_clean();
$content = false === $data ? '' : $data;
$status = '' === $content && $this->request->isJson() ? 204 : 200;
$response = Response::create($content, 'html', $status);
}
return $response;
}
}