| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- <?php
- /**
- * This file is part of webman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link http://www.workerman.net/
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
- namespace Webman;
- use FastRoute\Dispatcher\GroupCountBased;
- use FastRoute\RouteCollector;
- use FilesystemIterator;
- use RecursiveDirectoryIterator;
- use RecursiveIteratorIterator;
- use Webman\Route\Route as RouteObject;
- use function array_diff;
- use function array_values;
- use function class_exists;
- use function explode;
- use function FastRoute\simpleDispatcher;
- use function in_array;
- use function is_array;
- use function is_callable;
- use function is_file;
- use function is_scalar;
- use function is_string;
- use function json_encode;
- use function method_exists;
- use function strpos;
- /**
- * Class Route
- * @package Webman
- */
- class Route
- {
- /**
- * @var Route
- */
- protected static $instance = null;
- /**
- * @var GroupCountBased
- */
- protected static $dispatcher = null;
- /**
- * @var RouteCollector
- */
- protected static $collector = null;
- /**
- * @var null|callable
- */
- protected static $fallback = [];
- /**
- * @var array
- */
- protected static $nameList = [];
- /**
- * @var string
- */
- protected static $groupPrefix = '';
- /**
- * @var bool
- */
- protected static $disableDefaultRoute = [];
- /**
- * @var RouteObject[]
- */
- protected static $allRoutes = [];
- /**
- * @var RouteObject[]
- */
- protected $routes = [];
- /**
- * @var Route[]
- */
- protected $children = [];
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function get(string $path, $callback): RouteObject
- {
- return static::addRoute('GET', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function post(string $path, $callback): RouteObject
- {
- return static::addRoute('POST', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function put(string $path, $callback): RouteObject
- {
- return static::addRoute('PUT', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function patch(string $path, $callback): RouteObject
- {
- return static::addRoute('PATCH', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function delete(string $path, $callback): RouteObject
- {
- return static::addRoute('DELETE', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function head(string $path, $callback): RouteObject
- {
- return static::addRoute('HEAD', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function options(string $path, $callback): RouteObject
- {
- return static::addRoute('OPTIONS', $path, $callback);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function any(string $path, $callback): RouteObject
- {
- return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback);
- }
- /**
- * @param $method
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- public static function add($method, string $path, $callback): RouteObject
- {
- return static::addRoute($method, $path, $callback);
- }
- /**
- * @param string|callable $path
- * @param callable|null $callback
- * @return static
- */
- public static function group($path, callable $callback = null): Route
- {
- if ($callback === null) {
- $callback = $path;
- $path = '';
- }
- $previousGroupPrefix = static::$groupPrefix;
- static::$groupPrefix = $previousGroupPrefix . $path;
- $previousInstance = static::$instance;
- $instance = static::$instance = new static;
- static::$collector->addGroup($path, $callback);
- static::$groupPrefix = $previousGroupPrefix;
- static::$instance = $previousInstance;
- if ($previousInstance) {
- $previousInstance->addChild($instance);
- }
- return $instance;
- }
- /**
- * @param string $name
- * @param string $controller
- * @param array $options
- * @return void
- */
- public static function resource(string $name, string $controller, array $options = [])
- {
- $name = trim($name, '/');
- if (is_array($options) && !empty($options)) {
- $diffOptions = array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
- if (!empty($diffOptions)) {
- foreach ($diffOptions as $action) {
- static::any("/$name/{$action}[/{id}]", [$controller, $action])->name("$name.{$action}");
- }
- }
- // 注册路由 由于顺序不同会导致路由无效 因此不适用循环注册
- if (in_array('index', $options)) static::get("/$name", [$controller, 'index'])->name("$name.index");
- if (in_array('create', $options)) static::get("/$name/create", [$controller, 'create'])->name("$name.create");
- if (in_array('store', $options)) static::post("/$name", [$controller, 'store'])->name("$name.store");
- if (in_array('update', $options)) static::put("/$name/{id}", [$controller, 'update'])->name("$name.update");
- if (in_array('patch', $options)) static::patch("/$name/{id}", [$controller, 'patch'])->name("$name.patch");
- if (in_array('show', $options)) static::get("/$name/{id}", [$controller, 'show'])->name("$name.show");
- if (in_array('edit', $options)) static::get("/$name/{id}/edit", [$controller, 'edit'])->name("$name.edit");
- if (in_array('destroy', $options)) static::delete("/$name/{id}", [$controller, 'destroy'])->name("$name.destroy");
- if (in_array('recovery', $options)) static::put("/$name/{id}/recovery", [$controller, 'recovery'])->name("$name.recovery");
- } else {
- //为空时自动注册所有常用路由
- if (method_exists($controller, 'index')) static::get("/$name", [$controller, 'index'])->name("$name.index");
- if (method_exists($controller, 'create')) static::get("/$name/create", [$controller, 'create'])->name("$name.create");
- if (method_exists($controller, 'store')) static::post("/$name", [$controller, 'store'])->name("$name.store");
- if (method_exists($controller, 'update')) static::put("/$name/{id}", [$controller, 'update'])->name("$name.update");
- if (method_exists($controller, 'patch')) static::patch("/$name/{id}", [$controller, 'patch'])->name("$name.patch");
- if (method_exists($controller, 'show')) static::get("/$name/{id}", [$controller, 'show'])->name("$name.show");
- if (method_exists($controller, 'edit')) static::get("/$name/{id}/edit", [$controller, 'edit'])->name("$name.edit");
- if (method_exists($controller, 'destroy')) static::delete("/$name/{id}", [$controller, 'destroy'])->name("$name.destroy");
- if (method_exists($controller, 'recovery')) static::put("/$name/{id}/recovery", [$controller, 'recovery'])->name("$name.recovery");
- }
- }
- /**
- * @return RouteObject[]
- */
- public static function getRoutes(): array
- {
- return static::$allRoutes;
- }
- /**
- * disableDefaultRoute.
- *
- * @return void
- */
- public static function disableDefaultRoute($plugin = '')
- {
- static::$disableDefaultRoute[$plugin] = true;
- }
- /**
- * @param string $plugin
- * @return bool
- */
- public static function hasDisableDefaultRoute(string $plugin = ''): bool
- {
- return static::$disableDefaultRoute[$plugin] ?? false;
- }
- /**
- * @param $middleware
- * @return $this
- */
- public function middleware($middleware): Route
- {
- foreach ($this->routes as $route) {
- $route->middleware($middleware);
- }
- foreach ($this->getChildren() as $child) {
- $child->middleware($middleware);
- }
- return $this;
- }
- /**
- * @param RouteObject $route
- */
- public function collect(RouteObject $route)
- {
- $this->routes[] = $route;
- }
- /**
- * @param string $name
- * @param RouteObject $instance
- */
- public static function setByName(string $name, RouteObject $instance)
- {
- static::$nameList[$name] = $instance;
- }
- /**
- * @param string $name
- * @return null|RouteObject
- */
- public static function getByName(string $name): ?RouteObject
- {
- return static::$nameList[$name] ?? null;
- }
- /**
- * @param Route $route
- * @return void
- */
- public function addChild(Route $route)
- {
- $this->children[] = $route;
- }
- /**
- * @return Route[]
- */
- public function getChildren()
- {
- return $this->children;
- }
- /**
- * @param string $method
- * @param string $path
- * @return array
- */
- public static function dispatch(string $method, string $path): array
- {
- return static::$dispatcher->dispatch($method, $path);
- }
- /**
- * @param string $path
- * @param callable|mixed $callback
- * @return callable|false|string[]
- */
- public static function convertToCallable(string $path, $callback)
- {
- if (is_string($callback) && strpos($callback, '@')) {
- $callback = explode('@', $callback, 2);
- }
- if (!is_array($callback)) {
- if (!is_callable($callback)) {
- $callStr = is_scalar($callback) ? $callback : 'Closure';
- echo "Route $path $callStr is not callable\n";
- return false;
- }
- } else {
- $callback = array_values($callback);
- if (!isset($callback[1]) || !class_exists($callback[0]) || !method_exists($callback[0], $callback[1])) {
- echo "Route $path " . json_encode($callback) . " is not callable\n";
- return false;
- }
- }
- return $callback;
- }
- /**
- * @param array|string $methods
- * @param string $path
- * @param callable|mixed $callback
- * @return RouteObject
- */
- protected static function addRoute($methods, string $path, $callback): RouteObject
- {
- $route = new RouteObject($methods, static::$groupPrefix . $path, $callback);
- static::$allRoutes[] = $route;
- if ($callback = static::convertToCallable($path, $callback)) {
- static::$collector->addRoute($methods, $path, ['callback' => $callback, 'route' => $route]);
- }
- if (static::$instance) {
- static::$instance->collect($route);
- }
- return $route;
- }
- /**
- * Load.
- * @param mixed $paths
- * @return void
- */
- public static function load($paths)
- {
- if (!is_array($paths)) {
- return;
- }
- static::$dispatcher = simpleDispatcher(function (RouteCollector $route) use ($paths) {
- Route::setCollector($route);
- foreach ($paths as $configPath) {
- $routeConfigFile = $configPath . '/route.php';
- if (is_file($routeConfigFile)) {
- require_once $routeConfigFile;
- }
- if (!is_dir($pluginConfigPath = $configPath . '/plugin')) {
- continue;
- }
- $dirIterator = new RecursiveDirectoryIterator($pluginConfigPath, FilesystemIterator::FOLLOW_SYMLINKS);
- $iterator = new RecursiveIteratorIterator($dirIterator);
- foreach ($iterator as $file) {
- if ($file->getBaseName('.php') !== 'route') {
- continue;
- }
- $appConfigFile = pathinfo($file, PATHINFO_DIRNAME) . '/app.php';
- if (!is_file($appConfigFile)) {
- continue;
- }
- $appConfig = include $appConfigFile;
- if (empty($appConfig['enable'])) {
- continue;
- }
- require_once $file;
- }
- }
- });
- }
- /**
- * SetCollector.
- * @param RouteCollector $route
- * @return void
- */
- public static function setCollector(RouteCollector $route)
- {
- static::$collector = $route;
- }
- /**
- * Fallback.
- * @param callable|mixed $callback
- * @param string $plugin
- * @return void
- */
- public static function fallback(callable $callback, string $plugin = '')
- {
- static::$fallback[$plugin] = $callback;
- }
- /**
- * GetFallBack.
- * @param string $plugin
- * @return callable|null
- */
- public static function getFallback(string $plugin = ''): ?callable
- {
- return static::$fallback[$plugin] ?? null;
- }
- /**
- * @return void
- * @deprecated
- */
- public static function container()
- {
- }
- }
|