Laravel 路由原始碼分析

chonghua_123發表於2019-02-27

前言 只為學習

Illuminate\Routing\Router 分析

1. 引入

use Closure;//php 匿名類
use ArrayObject;//
use JsonSerializable;//
use Illuminate\Support\Str;//框架支援的str類
use Illuminate\Http\Request;//框架請求類
use Illuminate\Http\Response;//框架響應類
use Illuminate\Http\JsonResponse;//框架json響應類
use Illuminate\Support\Collection;//框架支援的集合類
use Illuminate\Container\Container;//框架容器基類
use Illuminate\Database\Eloquent\Model;//框架資料庫模型基類
use Illuminate\Support\Traits\Macroable;//框架 Macroable  Traits
use Illuminate\Contracts\Support\Jsonable;//框架契約json介面
use Illuminate\Contracts\Events\Dispatcher;//框架契約時間排程介面
use Illuminate\Contracts\Support\Arrayable;//框架契約陣列介面
use Illuminate\Contracts\Support\Responsable;//框架契約響應體介面
use Illuminate\Contracts\Routing\BindingRegistrar;//框架契約路由繫結暫存器介面
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;//
use Illuminate\Contracts\Routing\Registrar as RegistrarContract;//框架契約路由暫存器介面
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;//
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

2. 宣告router類 實現介面

class Router implements RegistrarContract, BindingRegistrar
{
    use Macroable {
        __call as macroCall;//使用Macroable  Traits 並且重名稱__call 方法
    }

    /**
     * The event dispatcher instance.
     * 事件排程器例項
     * @var \Illuminate\Contracts\Events\Dispatcher
     */
    protected $events;

    /**
     * The IoC container instance.
     * 容器例項
     * @var \Illuminate\Container\Container
     */
    protected $container;

    /**
     * The route collection instance.
     * 路由集合例項
     * @var \Illuminate\Routing\RouteCollection
     */
    protected $routes;

    /**
     * The currently dispatched route instance.
     * 當前路由
     * @var \Illuminate\Routing\Route
     */
    protected $current;

    /**
     * The request currently being dispatched.
     * 當前請求
     * @var \Illuminate\Http\Request
     */
    protected $currentRequest;

    /**
     * All of the short-hand keys for middlewares.
     * 中介軟體
     * @var array
     */
    protected $middleware = [];

    /**
     * All of the middleware groups.
     * 中介軟體組
     * @var array
     */
    protected $middlewareGroups = [];

    /**
     * The priority-sorted list of middleware.
     *
     * Forces the listed middleware to always be in the given order.
     * 強制列出的中介軟體始終按給定順序排列。
     * @var array
     */
    public $middlewarePriority = [];

    /**
     * The registered route value binders.
     * 註冊路由繫結
     * @var array
     */
    protected $binders = [];

    /**
     * The globally available parameter patterns.
     * 全域性可用引數模式
     * @var array
     */
    protected $patterns = [];

    /**
     * The route group attribute stack.
     * 路由組屬性堆疊。
     * @var array
     */
    protected $groupStack = [];

    /**
     * All of the verbs supported by the router.
     * 路由器支援的所有動作
     * @var array
     */
    public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];

3. 構造方法

//註冊一個新的router 例項
public function __construct(Dispatcher $events, Container $container = null)
    {
        $this->events = $events;
        $this->routes = new RouteCollection;
        $this->container = $container ?: new Container;
    }

4. get 向路由器註冊新的get 路由

1、addRoute

public function get($uri, $action = null)
    {
        return $this->addRoute(['GET', 'HEAD'], $uri, $action);
    }

5. post 向路由器註冊新的post 路由

1、addRoute

public function post($uri, $action = null)
    {
        return $this->addRoute('POST', $uri, $action);
    }

6. put 向路由器註冊新的put 路由

1、addRoute

public function put($uri, $action = null)
    {
        return $this->addRoute('PUT', $uri, $action);
    }

7. patch 向路由器註冊新的patch 路由

1、addRoute

public function patch($uri, $action = null)
    {
        return $this->addRoute('PATCH', $uri, $action);
    }

8. delete 向路由器註冊新的delete路由

1、addRoute

public function delete($uri, $action = null)
    {
        return $this->addRoute('DELETE', $uri, $action);
    }

9. options 向路由器註冊新的options 路由

1、addRoute

public function options($uri, $action = null)
    {
        return $this->addRoute('OPTIONS', $uri, $action);
    }

10. any 註冊響應所有動詞的新路由。

1、addRoute

public function any($uri, $action = null)
    {
        return $this->addRoute(self::$verbs, $uri, $action);
    }

11. fallback 註冊回退路由

1、addRoute

public function fallback($action)
    {
        $placeholder = 'fallbackPlaceholder';

        return $this->addRoute(
            'GET', "{{$placeholder}}", $action
        )->where($placeholder, '.*')->fallback();
    }

12. redirect 建立重定向路由

1、any
2、defaults

public function redirect($uri, $destination, $status = 302)
    {
        return $this->any($uri, '\Illuminate\Routing\RedirectController')
                ->defaults('destination', $destination)
                ->defaults('status', $status);
    }

13. permanentRedirect 建立從一個URI到另一個URI的永久重定向

1、redirect

public function permanentRedirect($uri, $destination)
    {
        return $this->redirect($uri, $destination, 301);
    }

14. view 註冊返回檢視的新路由。

1、match
2、defaults

public function view($uri, $view, $data = [])
    {
        return $this->match(['GET', 'HEAD'], $uri, '\Illuminate\Routing\ViewController')
                ->defaults('view', $view)
                ->defaults('data', $data);
    }

15. match 註冊多個動作的新路由

1、addRoute

public function match($methods, $uri, $action = null)
    {
        return $this->addRoute(array_map('strtoupper', (array) $methods), $uri, $action);
    }

16. resources 註冊一個資源控制器陣列。

1、resource

public function resources(array $resources, array $options = [])
    {
        foreach ($resources as $name => $controller) {
            $this->resource($name, $controller, $options);
        }
    }

17. resource 新增資源路由到控制器

public function resource($name, $controller, array $options = [])
    {
        if ($this->container && $this->container->bound(ResourceRegistrar::class)) {
            $registrar = $this->container->make(ResourceRegistrar::class);
        } else {
            $registrar = new ResourceRegistrar($this);//   Illuminate\Routing\ResourceRegistrar
        }
        // \Illuminate\Routing\PendingResourceRegistration
        return new PendingResourceRegistration(
            $registrar, $name, $controller, $options
        );
    }

18. apiResources 註冊api路由陣列

1、apiResource

public function apiResources(array $resources, array $options = [])
    {
        foreach ($resources as $name => $controller) {
            $this->apiResource($name, $controller, $options);
        }
    }

19. apiResource 註冊api路由到控制器

1、resource

public function apiResource($name, $controller, array $options = [])
    {
        $only = ['index', 'show', 'store', 'update', 'destroy'];

        if (isset($options['except'])) {
            $only = array_diff($only, (array) $options['except']);
        }
        return $this->resource($name, $controller, array_merge([
            'only' => $only,
        ], $options));
    }

20. group 建立路由組

1、updateGroupStack
2、

public function group(array $attributes, $routes)
    {
        $this->updateGroupStack($attributes);// 更新堆疊
        $this->loadRoutes($routes);
        array_pop($this->groupStack);//刪除最後一個堆疊資料
    }

21. updateGroupStack

1、

protected function updateGroupStack(array $attributes)
    {
        if (! empty($this->groupStack)) {
            $attributes = $this->mergeWithLastGroup($attributes);
        }
        $this->groupStack[] = $attributes;
    }

22. mergeWithLastGroup 將給定陣列與最後一個組堆疊合併

public function mergeWithLastGroup($new)
    {
        return RouteGroup::merge($new, end($this->groupStack));
    }

23. loadRoutes 載入路由資料

protected function loadRoutes($routes)
    {
        if ($routes instanceof Closure) {
            $routes($this);
        } else {
            $router = $this;

            require $routes;
        }
    }

24. getLastGroupPrefix 從堆疊上的最後一個組獲取字首

public function getLastGroupPrefix()
    {
        if (! empty($this->groupStack)) {
            $last = end($this->groupStack);

            return $last['prefix'] ?? '';
        }

        return '';
    }

25. addRoute

1、createRoute
2、add

public function addRoute($methods, $uri, $action)
    {
        return $this->routes->add($this->createRoute($methods, $uri, $action));
    }

26. createRoute 建立路由

1、actionReferencesController
2、convertToControllerAction
3、newRoute
4、prefix
5、hasGroupStack
6、mergeGroupAttributesIntoRoute
7、addWhereClausesToRoute

protected function createRoute($methods, $uri, $action)
    {
        //確定操作是否路由到控制器。
        if ($this->actionReferencesController($action)) {
        //將基於控制器的路由操作新增到運算元組
            $action = $this->convertToControllerAction($action);
        }
        //
        $route = $this->newRoute(
            $methods, $this->prefix($uri), $action
        );

        if ($this->hasGroupStack()) {
            $this->mergeGroupAttributesIntoRoute($route);
        }

        $this->addWhereClausesToRoute($route);

        return $route;
    }

27. actionReferencesController 確定操作是否路由到控制器。

    protected function actionReferencesController($action)
    {
        if (! $action instanceof Closure) {
            return is_string($action) || (isset($action['uses']) && is_string($action['uses']));
        }
        return false;
    }

28. convertToControllerAction 將基於控制器的路由操作新增到運算元組

1、prependGroupNamespace

protected function convertToControllerAction($action)
    {
        if (is_string($action)) {
            $action = ['uses' => $action];
        }
        if (! empty($this->groupStack)) {
            $action['uses'] = $this->prependGroupNamespace($action['uses']);
        }
        $action['controller'] = $action['uses'];

        return $action;
    }

29. prependGroupNamespace 最後一個組名稱空間前置到use子句上

protected function prependGroupNamespace($class)
    {
        $group = end($this->groupStack);

        return isset($group['namespace']) && strpos($class, '\\') !== 0
                ? $group['namespace'].'\\'.$class : $class;
    }

30. newRoute 建立路由物件

protected function newRoute($methods, $uri, $action)
    {
        return (new Route($methods, $uri, $action))
                    ->setRouter($this)
                    ->setContainer($this->container);
    }

31. prefix 給定的url字首

protected function prefix($uri)
    {
        return trim(trim($this->getLastGroupPrefix(), '/').'/'.trim($uri, '/'), '/') ?: '/';
    }

32. addWhereClausesToRoute 新增條款刪除

protected function addWhereClausesToRoute($route)
    {
        $route->where(array_merge(
            $this->patterns, $route->getAction()['where'] ?? []
        ));
        return $route;
    }

33. mergeGroupAttributesIntoRoute 將組堆疊與控制器操作合併

protected function mergeGroupAttributesIntoRoute($route)
    {
        $route->setAction($this->mergeWithLastGroup($route->getAction()));
    }

34. respondWithRoute 返回給定路由返回的響應

1、runRoute

public function respondWithRoute($name)
    {
        $route = tap($this->routes->getByName($name))->bind($this->currentRequest);

        return $this->runRoute($this->currentRequest, $route);
    }

35. dispatch 將請求傳送到應用程式。

public function dispatch(Request $request)
    {
        $this->currentRequest = $request;

        return $this->dispatchToRoute($request);
    }

36. dispatchToRoute 將請求傳送到路由並返回響應

1、runRoute
2、findRoute

public function dispatchToRoute(Request $request)
    {
        return $this->runRoute($request, $this->findRoute($request));
    }

37. findRoute 匹配路由

protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);

        $this->container->instance(Route::class, $route);

        return $route;
    }

38. runRoute 執行路由返回響應

1、prepareResponse
2、runRouteWithinStack

protected function runRoute(Request $request, Route $route)
    {
        $request->setRouteResolver(function () use ($route) {
            return $route;
        });

        $this->events->dispatch(new Events\RouteMatched($route, $request));

        return $this->prepareResponse($request,
            $this->runRouteWithinStack($route, $request)
        );
    }

39. runRouteWithinStack 在堆疊例項中執行給定的路由

1、gatherRouteMiddleware
2、prepareResponse

protected function runRouteWithinStack(Route $route, Request $request)
    {
        $shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
                                $this->container->make('middleware.disable') === true;

        $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);

        return (new Pipeline($this->container))
                        ->send($request)
                        ->through($middleware)
                        ->then(function ($request) use ($route) {
                            return $this->prepareResponse(
                                $request, $route->run()
                            );
                        });
    }

40. gatherRouteMiddleware 獲取當前路由中介軟體

1、sortMiddleware

public function gatherRouteMiddleware(Route $route)
    {
        $middleware = collect($route->gatherMiddleware())->map(function ($name) {
            return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups);
        })->flatten();

        return $this->sortMiddleware($middleware);
    }

41. sortMiddleware 排序中介軟體

1、middlewarePriority

    protected function sortMiddleware(Collection $middlewares)
    {
        return (new SortedMiddleware($this->middlewarePriority, $middlewares))->all();
    }

42. prepareResponse 給定值響應例項

public function prepareResponse($request, $response)
    {
        return static::toResponse($request, $response);
    }

43. toResponse

public static function toResponse($request, $response)
    {
        if ($response instanceof Responsable) {
            $response = $response->toResponse($request);
        }

        if ($response instanceof PsrResponseInterface) {
            $response = (new HttpFoundationFactory)->createResponse($response);
        } elseif ($response instanceof Model && $response->wasRecentlyCreated) {
            $response = new JsonResponse($response, 201);
        } elseif (! $response instanceof SymfonyResponse &&
                   ($response instanceof Arrayable ||
                    $response instanceof Jsonable ||
                    $response instanceof ArrayObject ||
                    $response instanceof JsonSerializable ||
                    is_array($response))) {
            $response = new JsonResponse($response);
        } elseif (! $response instanceof SymfonyResponse) {
            $response = new Response($response);
        }

        if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {
            $response->setNotModified();
        }

        return $response->prepare($request);
    }

44. substituteBindings 將路由繫結替換到路由上

1、binders
2、performBinding

public function substituteBindings($route)
    {
        foreach ($route->parameters() as $key => $value) {
            if (isset($this->binders[$key])) {
                $route->setParameter($key, $this->performBinding($key, $value, $route));
            }
        }
        return $route;
    }

45. substituteImplicitBindings

public function substituteImplicitBindings($route)
    {
        ImplicitRouteBinding::resolveForRoute($this->container, $route);
    }

46. performBinding 呼叫給定鍵的繫結回撥。

protected function performBinding($key, $value, $route)
    {
        return call_user_func($this->binders[$key], $value, $route);
    }

47. matched 註冊路由匹配的事件偵聽器

public function matched($callback)
    {
        $this->events->listen(Events\RouteMatched::class, $callback);
    }

48. getMiddleware 獲取全域性中介軟體

public function getMiddleware()
    {
        return $this->middleware;
    }

49. aliasMiddleware 設定中介軟體別名

public function aliasMiddleware($name, $class)
    {
        $this->middleware[$name] = $class;

        return $this;
    }

50. hasMiddlewareGroup 檢測是否存在中介軟體組中

public function hasMiddlewareGroup($name)
    {
        return array_key_exists($name, $this->middlewareGroups);
    }

51. getMiddlewareGroups 獲取中介軟體組

public function getMiddlewareGroups()
    {
        return $this->middlewareGroups;
    }

52. middlewareGroup 設定中介軟體組

public function middlewareGroup($name, array $middleware)
    {
        $this->middlewareGroups[$name] = $middleware;

        return $this;
    }

53. prependMiddlewareToGroup 頭部插入中介軟體組

public function prependMiddlewareToGroup($group, $middleware)
    {
        if (isset($this->middlewareGroups[$group]) && ! in_array($middleware, $this->middlewareGroups[$group])) {
            array_unshift($this->middlewareGroups[$group], $middleware);
        }

        return $this;
    }

54. pushMiddlewareToGroup 尾部插入中介軟體組

public function pushMiddlewareToGroup($group, $middleware)
    {
        if (! array_key_exists($group, $this->middlewareGroups)) {
            $this->middlewareGroups[$group] = [];
        }

        if (! in_array($middleware, $this->middlewareGroups[$group])) {
            $this->middlewareGroups[$group][] = $middleware;
        }

        return $this;
    }

55. bind

public function bind($key, $binder)
    {
        $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback(
            $this->container, $binder
        );
    }

56. model 為萬用字元註冊模型繫結器

public function model($key, $class, Closure $callback = null)
    {
        $this->bind($key, RouteBinding::forModel($this->container, $class, $callback));
    }

57. getBindingCallback 獲取繫結的回撥函式

public function getBindingCallback($key)
    {
        if (isset($this->binders[$key = str_replace('-', '_', $key)])) {
            return $this->binders[$key];
        }
    }

58. getPatterns 全域性匹配模式

    public function getPatterns()
    {
        return $this->patterns;
    }

59. pattern 設定全域性匹配模式

public function pattern($key, $pattern)
    {
        $this->patterns[$key] = $pattern;
    }

60. patterns 批量設定全域性匹配模式

public function patterns($patterns)
    {
        foreach ($patterns as $key => $pattern) {
            $this->pattern($key, $pattern);
        }
    }

61. hasGroupStack 判斷路由組屬性堆是否存在

public function hasGroupStack()
    {
        return ! empty($this->groupStack);
    }

62. getGroupStack 獲取路由組屬性堆

public function getGroupStack()
    {
        return $this->groupStack;
    }

63. input 獲取當前請求引數

public function input($key, $default = null)
    {
        return $this->current()->parameter($key, $default);
    }

64. getCurrentRequest 獲取當前請求

    public function getCurrentRequest()
    {
        return $this->currentRequest;
    }

65. getCurrentRoute 獲取當前請求路由

public function getCurrentRoute()
    {
        return $this->current();
    }

66. current 獲取當前請求路由

public function current()
    {
        return $this->current;
    }

67. has 檢測路由是否存在

public function has($name)
    {
        $names = is_array($name) ? $name : func_get_args();

        foreach ($names as $value) {
            if (! $this->routes->hasNamedRoute($value)) {
                return false;
            }
        }

        return true;
    }

68. currentRouteName 當前路由名稱

public function currentRouteName()
    {
        return $this->current() ? $this->current()->getName() : null;
    }

69. is

public function is(...$patterns)
    {
        return $this->currentRouteNamed(...$patterns);
    }

70. currentRouteNamed 確定當前路由是否符合模式

public function currentRouteNamed(...$patterns)
    {
        return $this->current() && $this->current()->named(...$patterns);
    }

71. currentRouteAction 獲取當前請求路由控制器

public function currentRouteAction()
    {
        if ($this->current()) {
            return $this->current()->getAction()['controller'] ?? null;
        }
    }

72. uses “currentRouteuses”方法的別名

public function uses(...$patterns)
    {
        foreach ($patterns as $pattern) {
            if (Str::is($pattern, $this->currentRouteAction())) {
                return true;
            }
        }

        return false;
    }

73. currentRouteUses

public function currentRouteUses($action)
    {
        return $this->currentRouteAction() == $action;
    }

74. auth 為應用程式註冊典型的身份驗證路由

public function auth(array $options = [])
    {
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
        if ($options['register'] ?? true) {
            $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'Auth\RegisterController@register');
        }
        if ($options['reset'] ?? true) {
            $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
            $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
            $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
            $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
        }
        if ($options['verify'] ?? false) {
            $this->emailVerification();
        }
    }

75. emailVerification 註冊郵箱驗證路由

public function emailVerification()
    {
        $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
        $this->get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
        $this->get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
    }

76. singularResourceParameters 將未對映的全域性資源引數設定為單數

public function singularResourceParameters($singular = true)
    {
        ResourceRegistrar::singularParameters($singular);
    }

77. resourceParameters 設定全域性資源引數對映

public function resourceParameters(array $parameters = [])
    {
        ResourceRegistrar::setParameters($parameters);
    }

78. resourceVerbs 獲取或設定資源URI中使用的謂詞

public function resourceVerbs(array $verbs = [])
    {
        return ResourceRegistrar::verbs($verbs);
    }

79. getRoutes 獲取路由集合例項

public function getRoutes()
    {
        return $this->routes;
    }

80. setRoutes 設定路由集合例項

public function setRoutes(RouteCollection $routes)
    {
        foreach ($routes as $route) {
            $route->setRouter($this)->setContainer($this->container);
        }

        $this->routes = $routes;

        $this->container->instance('routes', $this->routes);
    }

81. 魔術方法

public function __call($method, $parameters)
    {
        if (static::hasMacro($method)) {
            return $this->macroCall($method, $parameters);
        }

        if ($method === 'middleware') {
            return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);
        }

        return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
    }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章