menu

Phatto

Router

Hoje em dia não é mais necessário explicar a necessidade e a importância de se ter um Router em sua aplicação. Se você não conhece, entenda que o Router é responsável por analisar as requisições ao seu aplicativo web ( site, etc ) e responder com o controlador pré configurado ou uma página estática, um arquivo, etc.

Veja o arquivo de inicialização ( no front controller ) para acionar o roteador em sua aplicação web:

<?php

include "/.php/Composer/autoload.php";

( new Lib\Router )->run();

Esta inicialização simples carrega o "autoload" do Composer e, em seguida, cria uma instância do "Lib\Router" ( entre parenteses ) e chama o método "run" desse objeto. O router usará a configuração ( Config/Lib/Router ) para analisar as requisições e responde-las adequadamente.

O seguinte trecho do Config\Lib\Router é usado para chamar o controlador da página "home":

$router->respond('get', '/', 'Phatto/Controller::home' [, action, extra ]);

** Entre colchetes são parâmetros opcionais.

Usamos o método "respond" para configurar as rotas. Os parametros desse método são os seguintes:

Method: [ 'get' ] - Pode ser qualquer um dos métodos HTTP válidos ( get,push, put... ). Para usar mais de um método com a mesma configuração você os separará com a barra "|" ( get|push|put ) e, em caso de responder a todos os métodos, use a palavra "all".

Request: [ '/' ] - Aqui você indica o que espera receber na URL de acesso de forma estática ( ex.: /produtos/ ) ou com o uso de expressões regulares do PHP ( ex.: /produtos/(\+d) ). Para deixar as configurações bem flexíveis e fáceis de usar, não existe uma "linguagem" específica do Router (como acontece com outros similares). Você usa simplesmente as expressões regulares e pronto!
No final desse artigo temos alguns exemplos de configurações para facilitar o aprendizado.

Controller: [ 'Phatto/Controller::home' ] - Aqui você indica o controlador que responderá a requisição.Pode ser uma classe e método, uma função anônima ou uma chamada direta a classe NTag e método "show" ( Lib\NTag::show()). O objeto receberá dois parâmetros: o primeiro é uma string contendo a requisição (sem o domínio) e o segundo é umarray com os parâmetros capturados pela expressão regular.

Action:  Opcionalmente, você pode indicar o método (action) da classe separadamente do controlador. Ficariaassim:

$router->respond('get', '/', 'Phatto/Controller', 'home');         

Extra:  Você pode passar parâmetros extras para o controlador/action usando um array, aqui.

Configurações do Router

O router vem com sua configuração default adequada à maioria dos casos de uso. Mas, você poderá modificar os parâmetros de configuração para atender as suas específicas necessidades.
Segue abaixo uma lista dos principais parâmetros configuráveis no Config\Lib\Router.

DefaultController: Caso o parâmetro "controller" não seja indicado no método "respond", o Router usará o controlador indicado aqui.

$router->setDefaultController('Namespace\Class\Controller');

DefaultAction: Indica o "action" do controlador, caso não seja indicado.

$router->setDefaultAction('index');

O controlador e a ação (action) padrões são chamados pelo Router, também, quando uma requisição não corresponda a nenhuma "respond" programada. Neste caso, você pode usar o "default" para mostrar uma página do tipo HTTP 404, ao seu visitante.

NamespacePrefix: Você pode indicar um namespace para prefixar as suas classes de controle. Isso evita a excessiva repetição, por exemplo, em sistemas que concentram em um namespace específico, as classes de controle (alguns MVCs). Basta, então, indicar usando o método:

$router->setNamespacePrefix('Namespace/Prefix');

Verifique outros parâmetros de configuração na classe Config\Lib\Router.

Parâmetros de Inicialização

O Router pode ser iniciado com alguns parâmetros que lhe trarão mais flexibilidade ao projeto e controle sobre o queé processado.

( new Lib\Router( autorun,  request, url) )->run();

** trecho do front controller (boot)

Autorun: booleano, default: true.
Indica se o Router deve, além de resolver as configurações da requisição web, montar e chamar a classe (ou função anônima) de controle ou apenas retornar o próprio Router para um pré-processamento, cascateamento, middleware, etc. 

Request: string, default: null.
Você pode injetar aqui um pseudo request e o Router ignorará o verdadeiro request de acesso. Muito útil para cascateamento de routers, testes e outros.

Url: string, default: null.
Normalmente o Router calcula o url do domínio do seu site automaticamente, baseado nos parâmetros do servidor e da requisição ($_SERVER). Porém, em alguns casos, é necessário forçar o valor dessa url. Basta, então, indicar a url através desse parâmetro de inicialização.

Segue um exemplo para o front controller:

$router = new Lib\Router( false, 
                          '/produtos/89755', 
                          'https://dominio.com' );						 
$router->run();

// capturando os dados processados
$controller = $router->getController();
$action     = $router->getAction();
$params     = $router->getParams();

Exemplos

Veja alguns exemplos que estão (também) listados na classe Config\Lib\Router

$route->respond('get', '/', 'Resource\Main::index')

      ->respond('get', 'login', 'Blog\Page::login')
      ->respond('get', 'blog', 'Devbr\Install\Page::index')

      ->respond('get', 'blog/e/(?(.*)?)', 'Blog\Page::edit')
      ->respond('get', 'blog/(?.*?)', 'Blog\Page::view')
		
//AJAX
      ->respond('post', 'blog/save', 'Blog\Ajax::save')
      ->respond('post', 'blog/checklink', 'Blog\Ajax::checkLink')

      ->respond('post', 'blog/delete/(?(\d+)?)', 'Blog\Ajax::delete')
      ->respond('post', 'blog/upload/(?(\d+)?)', 'Blog\Ajax::upload')

//REST
      ->respond('post',   'api/data', 'Rest/Ful::create)
      ->respond('get',    'api/data', 'Rest/Ful::read)
      ->respond('put',    'api/data', 'Rest/Ful::update)
      ->respond('patch',  'api/data', 'Rest/Ful::modify)
      ->respond('delete', 'api/data', 'Rest/Ful::delete)


					
Considere a url:
http://localhost/loja/903/Camisa Polo Marca/qualquer coisa ignorada/

Captura:
	['id'] => 903
	['produto'] => Camisa Polo Marca

E ignora tudo depois de 'produto'.

Veja a função "test" da classe em "/.php/Site/Front.php"
Segue a configuração da rota, abaixo:

      ->respond('get', '/loja/(?.*?)/(?[^/]*).*', 'Site/Front::test')

		
A mesma configuração, porém com parametros (índice) NUMÉRICOS:
http://localhost/loja2/903/Camisa Polo Marca/qualquer coisa ignorada/


      ->respond('get', '/loja2/(.*?)/([^/]*).*', 'Site/Front::test')


Usando uma função anônima diretamente na configuração do Router
http://localhost/fac/categoria/pergunta

      ->respond('get', '/fac/(.*?)/([^/]*).*',

            function ($type, $user) {
                echo '<h1>Função anônima</h1>
                &alt;p><b>Request URI:</b> '.$type.'<br>
                Parametros:</b><pre>'.print_r($user, true).'</pre></p>';
            }
        )


Usando uma função anônima para mostrar uma página HTML ESTÁTICA
http://localhost/about

      ->respond('get', '/about',

            function () {
                include _HTMLPATH.'Static/about.html';
        })

Mostrando uma página diretamente pela classe Html [ equal: Html->show('about') ]
http://localhost/about

      ->respond('get', '/about', 'Html', 'show', 'about');