How to implement a Route System in MVC?

5

I'm creating an MVC framework (more for studies), and I'm trying to implement a route system , but I'm not sure how to execute the routes. So I would like to know if there is any execution flow for an MVC project.

Mine looks something like this:

// Função que inicia a aplicação
RUN() {

   // Aqui faço as chamadas padrões, detecto qual é o Controller e Action
   // da requisição
   Request $request = new Request();

   // Pego o Controller;
   string $controller = $request->getController();

   // Pego a Action
   string $action = $request->getAction();

   // Instâncio o Controller
   Controller $app = New $controller($request);

   string $output = $app->{$action}();

   // Imprimo o resultado (view)
   output($output);

}

Source Code

Would the execution of the controller and action continue in the scope above, or within the scope of the route?

I saw that some route systems (almost all actually) use a " Handler " (_callback) for the route. In that case where would the action be?

I'm doing the framework in PHP, but I'm looking for a more "theoretical" answer as an independent language algorithm, just the same logic.

Obs2: The answer does not have to be a CBT. : P

    
asked by anonymous 16.06.2016 / 15:01

1 answer

3

I usually do this:

Collection - The collection that will save all routes.

Route - The class that represents a route. You should provide information like the uri you want to capture and http verbs accepted.

Router - The class that serves to bridge the Route and Collection. It is a facilitator for creating routes within the collection.

DispatcherInterface - The interface that provides a method to be run as the route dispatcher. I preferred to make an interface to be able to attend to several implementations, for example, someone who wants to use a more complex library or who simply wanted to use less resources.

So, in this context, we would have a structure something like this:

$router = new Router(new Collection);

// Cria a instância de Route, coloca dentro da Collection
// E retorna Rota recém-criada, para possíveis outra definições 

$router->get('/', 'HomeController::getIndex'); 

$router->get('/login', function () {})->setName('home.login');

// Classe que implementa DispatcherInterface
$router->dispatch(new Dispatcher());

Based on the context presented in the question, I think an interesting one would be:

$request = new Request();

// retorna new Response se tudo der certo

$response = $router->dispatch(new RequestDispatcher($request)); 


$response->send();

Within your RequestDispatcher , you could apply the proper operations to call Controller and Method.

For example:

   class RequestDispatcher implements DispatcherInterface {

       public function __construct(Request $request) {
               $this->request = $request;
       }

       public function dispatch(Router $router) {
            $route = $router->findByRequest($this->request);

            if (! $route) return $this->notFound();

            $response = call_user_func($route->callAction(), $route->getParameters());

            return $response;


       }
   }

That is, in your Dispatcher, you can add the operations required to search the route within the collection. When it is not found, you can invoke an action for the 404 error loop. When it is found, you can call the action defined for the given url and call it, then return a Response.

Trying to summarize it all:

The Dispatcher looks for the route within a route collection, which was created by the router. Then, if the Dispatcher finds the route, it converts the return of the route action (it can be a method of a Controller or a Closure) to a Response, which is finally sent to the output.

You mentioned in your question about a Handler, which is passed through a callback.

I think you're talking about an anonymous function, which some libraries often use to "tie" a particular functionality to a route in order to run at the end.

In my library I also did this. Can I use either a method of a class (the Controller) or an anonymous function. I think this is very useful in cases where the route does not make sense to point to a specific controller, because it is not something that does not have "relationship" with the rest.

Example:

   $router->get('/json/cep/{num}', function ($number) {

        $url = sprintf('https://cep.correios.com.br/%s.json', $number);

        $dados = json_decode(file_get_contents($url));

        // Transforma em JsonResponse
        return $dados;
   });
    
16.06.2016 / 22:50