How does Laravel "guard" the routes?

Asked

Viewed 1,218 times

1

In the Laravel, both in 4 and 5, we can use a class called Route in order to create certain routes.

My curiosity is: how does the Laravel (or other frameworks) do to "know" which given route corresponds to a url?

By chance all this is saved in some array and then, when the request is made, the route is called?

Where is the list of these routes?

This is important to know, especially for those who want to learn how to make a framework.

  • As far as I know is done a "mapping" between the route, and controller, function or that will be executed, when this route is accessed. I believe some kind of comparison (if nested) is made until I find the definition that matches the required url.

  • By the level of Laravel’s source code, I doubt it’s really "nested ifs". Even Laravel 5 can cache routes, it makes no sense to be "a lot of ifs"

  • 1

    Negative? What’s wrong with the question?

  • Okay, it was just a guess .... But it doesn’t really matter how he does it, because deep down, in any programming language, the task of taking one path, or another, is always done by way of conditionals, whether in the script itself, or at a low level, perhaps in an operation requested by the interpreter from the OS, executed directly on the processor ... hehe ...

3 answers

1


I don’t quite understand the question, but I suppose they do $_SERVER['PATH_INFO'] or $_SERVER['REQUEST_URI'], no. htaccess of Laravel/Symfony should not use PATH_INFO because it is so:

RewriteRule ^ index.php [L]

path_info is only generated in php if you do something similar to this:

RewriteRule (*.?) index.php/$1 [L]

In the case PATH_INFO does not work very well on some servers other than Apache, sometimes the result is different, but the REQUEST_URI works in the same way in Apache, Ngnix, Lighttpd and Iisexpress (I couldn’t test on standard IIS but I believe it’s the same thing).

The PHP structure should look something like this (this is the structure I used in a personal framework, however this simplified, without checking POST, GET, PUT, etc):

class Route
{
    private static $currentPath;
    private static $routes = array();

    public function path()
    {
        if (self::$currentPath) {
            return $currentPath;
        }

        //Pega o nome do script atual
        $sname  = $_SERVER['SCRIPT_NAME'];

        //Remove a query string da url
        $reqUri = empty($_SERVER['REQUEST_URI']) ? null : preg_replace('#\?(.*)$#', '', $_SERVER['REQUEST_URI']);

        //Subtrai o nome do script (se necessário)
        $pathInfo = substr(urldecode($reqUri), strlen(substr($sname, 0, -9)));
        $pathInfo = '/' . ($pathInfo === false ? '' : $pathInfo);

        return self::$currentPath = $pathInfo;
    }

    public function add($path, $controller)
    {
        self::$routes[$path] = $controller;
    }

    public function exec()
    {
         if (empty(self::$routes[$path])) {
              return false;
         }

         return self::$routes[$path];
    }
}

There are many ways to "save" such routes in the case of my class I keep in a array in the same class:

private static $routes = array();

But you can even keep it in separate places, it will depend on the end-use goal.

The use would be something like:

require 'route.php';

Route::add('/', 'ClasseController@indexaction');
Route::add('/blog', 'ClasseController@blogaction');
Route::add('/admin', 'AdminClasse@action');

echo 'Path: ', Route::path(), '<br>', PHP_EOL; //Retorna o PATH equivalente ao PATH_INFO
echo 'Controller: ', Route::exec(), '<br>', PHP_EOL; //Retorna o controler

I can’t say that it works exactly like this in Laravel/Symfony, but this explanation is to understand how to use the $_SERVER['REQUEST_URI'] or PATH_INFO.

Laravel and the Routes cache

In Laravel there is a cache structure for the routes (which you mentioned me) that after the command (does not work with Anonimas functions):

php artisan route:cache

A file is generated in projeto/bootstrap/cache/routes.php, it contains a php variable "serialized" (and encoded in Base64) and uses the method setRoutes to define all routes that are cached pro "Collection", an example cache:

app('router')->setRoutes(
    unserialize(base64_decode('Código base64'))
);

This can be reasonably advantageous for production servers.

  • Yes, the Laravel uses the REQUEST_URI. Actually, it’s not quite the Laravel, is Symfony, which is used by Laravel. The example rather depicts what happens in Laravel, but of course in a more simplified way, since the Laravel uses 3 classes just for routing :d

0

Well, let’s explain in parts:

The Laravel, when we use the class call Route, Actually you’re calling a class facade Illuminate\Routing\Router.

A Router serves to facilitate the creation of routes (Illuminate\Routing\Route), which in turn will be created within a collection of predefined routes (Illuminate\Routing\RouteCollection).

When you invoke the Route::get('/', 'HomeController@getIndex') for example, you are actually doing the following:

 app('route')->get('/', 'HomeController@getIndex');

Which is the same thing :

app('route')->addRoute(['GET', 'HEAD'], '/', 'HomeController@getIndex');

So we have to understand that:

1 - Route is a facade (facade) for class Router.

2 - Router is a class responsible for creating routes within a collection.

3 - RouteCollection is the list of routes. Each time it is called Route::get or Route::post, this route is inserted within this class.

4 - Route (not the stab, but Illuminate\Routing\Route) is the route itself. It is the class representing an entity that is a route.

Internally, the Laravel has a method in RouteCollection which takes the first route that matches the regular expression of URI of route.

When none is found, returns an exception (which is error 404).

See the method RouteCollection::match, who does this job.

/**
 * Find the first route matching a given request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Routing\Route
 *
 * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
 */
public function match(Request $request)
{
    $routes = $this->get($request->getMethod());

    // First, we will see if we can find a matching route for this current request
    // method. If we can, great, we can just return it so that it can be called
    // by the consumer. Otherwise we will check for routes with another verb.
    $route = $this->check($routes, $request);

    if ( ! is_null($route))
    {
        return $route->bind($request);
    }

    // If no route was found, we will check if a matching is route is specified on
    // another HTTP verb. If it is we will need to throw a MethodNotAllowed and
    // inform the user agent of which HTTP verb it should use for this route.
    $others = $this->checkForAlternateVerbs($request);

    if (count($others) > 0)
    {
        return $this->getOtherMethodsRoute($request, $others);
    }

    throw new NotFoundHttpException;
}

Then, we can conclude, as asked, that routes are saved in a collection, which is responsible for returning a recorded route according to the content of the request (the http method and Uri).

  • 1

    But that’s a little different than what you asked... that’s the part where the routes are stored when they’re found.. What I understood from the question is how the Aravel translated the routes..

  • "Not found" when they are "declared". They are "found" (or not) according to last language.

  • didn’t understand. rsr found or declared gives the same because the default logic psr4 is "find (the file)" and load if it is "declared (the class)"

  • Forget it then, let it go. Let’s see if other users are also in doubt about what I asked.

  • 1

    I’m feeling a tone of reprisals in these negatives. I can still see that some users in the community need to mature

-1

Laravel uses autoloader to identify routes. You can also opt for predefined routes. For cases where there are no pre-defined routes and Laravel automatically identifies them, it is most likely applying the standard PSR4, which can be defined in the

 "autoload": {
         "psr-4": {
             "App\\": "app/",
              "Mylib\\": "src/"
        }
    },

illustrative example

https://laracasts.com/lessons/psr-4-autoloading

Whenever a route is invoked and found, it is cached.

I’m not saying that Laravel only uses PSR4. This is optional in the settings.

This route cache is something that can be good or bad. Because it will always load a file containing all the routes at each request or each time it incobes, for example. It is loading a few kb there that can be heavier than checking the route at runtime. In a small project of 10, 20 routes, it can be advantage, but above 100, I believe that.

To optimize, there is the route group where route files can be divided, leaving them in smaller sizes. Therefore, those who use many routes should use this resource.

  • To better understand why you have been negative, please refer to the manual: https://laravel.com/docs/5.4/routing#basic-routing :)

  • Autoload is an essential part of routing. That’s why some here do not understand and so have.

  • This question has no relation to autoloading, not by chance any of the other answers address it. Take Laravel’s routing code, throw it all in one file, add fictional routes with closures, and you can still answer the question. I won’t even get into the merits of caching because your argument is also completely wrong.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.