Guia de Desenvolvimento Laravel—Pt. 2 — Facades, Verbos Http e Roteamento
Como dito no primeiro artigo da série (aqui), nesse grupo de publicações iremos tratar de todos os tópicos citados no guia oficial da certificação, nesse artigo trataremos do padrão Facade (Fachada), de verbos Http, e de todo fluxo de roteamento do utilizado pelo Framework.
Para darmos inicio, vamos entender o porque de tratarmos das fachadas nesse artigo ao invés do primeiro, sendo que as fachadas estão ligadas diretamente aos tópicos relacionados a arquitetura.
1.3 — Facades
Como a tradução literal informa, em uma analogia distante, uma fachada de uma loja deve representar qual é o tipo do estabelecimento, para diversos fins, mas principalmente para que os transeuntes saibam que tipos de produtos são vendidos dentro daquela loja, se é uma loja de roupas, de comida, ou qualquer outra modalidade, mas não basta a loja ter uma fachada dando a entender uma coisa que não condiz com o que estabelecimento comercializa ou produz, então para que haja coesão a fachada deve ser condizente com a função do estabelecimento.
Agora trazendo essa analogia ao contexto do desenvolvimento, podemos entender que, quando criamos uma fachada para algo, ela deve representar corretamente o que ela faz, e dentro dela deve ser aplicada a logica correspondente.
Comumente utilizado visando o desacoplamento de partes do código e para facilitar o acesso a sub-sistemas de sistemas maiores e mais complexos, ou, no caso no Laravel, permite acessar os objetos do container providos pelos Services Providers, uma fachada, pode ou não ser estática, no caso do Laravel, nós teremos fachadas estáticas para as instancias, podemos verificar isso no passo de criação de uma instancia utilizada pela classe base do pacote Illuminate\Support\Facades, no arquivo com a classe abstrata Facade, através da análise da classe, é possível ver que o método magico __callStatic, presente no final da classe, é o responsável por literalmente, fazer a mágica acontecer, ele chama o método getFacadeRoot, que após solicitar a classe Literal estendida da classe abstrata Facade chama o método resolveFacadeInstance , nesse método notamos uma peculiaridade, pois na nossa fachada podemos definir uma instancia direta sem precisar dos acessos de localização instanciação através do container principal, mas caso utilize a declaração nominal, será validada se foi setada a instancia, e na sequencia ela é recuperada do container principal e devolvida, voltando ao método mágico no final da classe, e adicionar sua instancia ao atributo estático e de visibilidade protegida $resolvedIsntance.
Recapitulando, para o Laravel, as fachadas são formas de acessar partes do código com mais facilidade, como por exemplo, esse é o motivo de termos deixado o tópico referente as Facades para esse artigo, o roteamento do framework possui uma fachada de acesso integrada com alguns outros padrões, como Mixins por exemplo.
1.4 — Verbos Http
Apesar ser um tópico relativamente simples, é de extrema importância, principalmente se o produto desenvolvido possuir algum tipo de integração via APIs, os verbos Http vem do procolo Http, a versão atualmente em uso é a versão 1.1, definida pelo RFC2616 em 1999, e atualizado em 2014 pelo RFC7231, o RFC2616 é o protocolo proposto por grandes nomes da época como Compaq, Xerox e Microsoft, a organização W3C, e grandes nomes como Henrik Frystyk, um dos codesenvolvedores do CSS (ocorreu durante o desenvolvimento do browser Arena, um dos primeiros browsers desenvolvimentos para sistemas UNIX, o projeto foi descontinuado em 1996).
A definição de um protocolo para comunicação via web facilitou a criação de serviços de comunicação, e a padronização da forma como é feita a comunicação na web moderna, no caso do Framework Laravel, ele abstrai uma série de camadas do protocolo Http, mas não só do procolo em si, mas também outras abstrações previstas mais recentes, ou especificas para desenvolvimento com PHP como o PSR-7.
Mas esse tópico iremos tratar apenas no que equivale aos verbos Http, na RFC7321 possuímos declarados os seguintes métodos explicados de forma resumida abaixo, ressalvando que além dos métodos definidos nas normas citadas anteriormente, o Laravel ainda possui o acesso ao método PATCH, adicionado pela RFC5789:
OPTIONS:
Utilizado apenas para troca de informação, não deve possuir nenhuma ação ou iniciar algo, também não deve conter corpo.
GET:
Utilizado para busca de informação, geralmente a requisição mais otimizada em uma aplicação, e também o método padrão para ‘fazer uma requisição’, quando nenhuma informação adicional é fornecida.
HEAD:
O método é idêntico ao método GET, com a diferença de que o método HEAD nunca deve conter um corpo de resposta, geralmente utilizado para coleta de metadados ou teste de URLs.
POST:
Método utilizado para envio de dados ao servidor, comumente utilizado para criar registros, envio de mensagens, envio de dados de formulários, além do método GET, é o único método previsto pelas diretrizes do atributo form no HTML 5.
PUT:
O método PUT é utilizado para um registro já existente, sendo a origem substituída pelo corpo enviado, sempre devendo alterar utilizando todo o corpo enviado.
DELETE:
Utilizado para informar ao servidor que o alvo informado deve ser removido.
PATCH:
Semelhante ao método PUT, porém com propósito de permitir alteração parcial de um registro.
Veremos um pouco melhor sobre cada método e seu uso no tópico a seguir, assim também como voltaremos ao tópico 1.3, e veremos exemplos do uso e consume de fachadas(Facades).
2 — Routing
O Laravel possui um sistema de roteamento extremamente simples, e particionado, ou seja, suas rotas web são separadas de outras rotas, como APIs, comandos do console via Artisan e os canais, além de ser permitido que novas origens sejam adicionadas de acordo com o seu projeto.
O roteamento se da inicio pelo Service Provider de rotas, localizado junto com os demais, em App\Providers\RouteServiceProvider, através de instância de classe Route, inclui como grupo de prefixo api e web as rotas nos arquivos routes/api.php e routes/web.php, o prefixo api possui uma peculiaridade, pois como padrão ele vem com um grupo de middleware denominado também de api, porém esse grupo de middlewares está vazio por padrão.
Uma rota, deve ser declarada dentro de um arquivo de grupo de rotas válido, e deve utilizar da facade Route que devolve um instancia de Illuminate\Routing\Route, a chamada utiliza a seguinte sintaxe:
Route::método($url,$callback);Route::get(‘lojas’,’lojasController@getAll’);
O método a ser utilizado, não esta definido dentro da classe Illuminate\Routing\Route, essa classe é responsável pela lógica de implementação do controller responsável, enquanto visando uma abrangência maior, a classe Illuminate\Routing\Router é o responsável por definir nossas rotas em tempo de iniciação serviços, além de nossas rotas, possuímos alguns métodos de rotas padrões como ->auth, ->resetPassword e ->emailVerification, métodos para fornecer grupos de rotas auxiliares.
Veremos os detalhes do que nos parágrafos anteriores nos próximos tópicos deste artigo, assim até o final dos tópicos sobre Routing.
2.1 — Redirecionamento (Redirect)
Para iniciarmos nos tópicos sobre os detalhes do roteamento, vamos entender como funciona o redirecionamento dentro do framework, o redirecionamento é usado através da sintaxe:
Route::redirect($de,$para);
A chamada do método redirect, por padrão irá devolver um instancia de um controller previsto para redirecionamentos, o Illuminate\Routing\RedirectController, o redirectController é apenas responsável por chamar uma instancia do pacote auxiliar para redirecionamentos de requisições Http, Illuminate\Http\RedirectResponse, classe a qual estende de uma classe herdada do pacote Symfony, Symfony\Component\Http\RedirectResponse, classe que por sua vez estende da classe Symfony\Component\Http\Response, onde é aplicado o padrão de resposta previsto pela PSR-7.
A utilidade desse método é para informar ao client que a rota foi redirecionada, por padrão irá retornar a informação da rota redirecionada em seus headers.
Existem três sintaxes disponíveis:
Route::redirect($de,$para); // retorna um http code 302Route::redirect($de,$para,$statusCode); // retorna um http code customizadoRoute::permanentRedirect($de,$para); // retorna um http code 301
2.2 — Route Parameters
O roteamento padrão para os métodos http possuem alguns parâmetros disponíveis, sendo divididos em dois grupos, os parâmetros obrigatórios e os parâmetros opcionais, no grupo dos parâmetros obrigatórios temos o parâmetros referente a URL da rota, e um callback, veja no exemplo a seguir:
Route::get(‘loja/{loja}’,function($loja){// …});
É valido repararmos que a classe Illuminate\Routing\Router consegue identificar se esse calback for apontado para algum controller, veja a sintaxe a seguir:
Route::get(‘loja/{loja}’,’lojasController@loja’);
Agora caso nossos parâmetros sejam opcionais, a sintaxe permanece exatamente a mesma, porém passamos a ter a possibilidade definir um valor default para nosso parâmetro:
Route::get(‘loja/{loja}’,function($loja = null){if(is_null($loja)){}else{ // …});
Os dois casos de parâmetros citados acima, possui um método auxiliar para que o dado passado em seu parâmetro seja validado através de um regex
Route::get(‘loja/{loja}’,function($loja){ // …})->where(‘loja’,’[0–9]+’);
Essa forma de validar parâmetros pode ser definida de forma global, isso deve ser feito no método boot() do RouteServiceProvider:
public function boot(){Route::pattern(‘loja’,’[0–9]+’);parent::boot()}
Ao definir a validação dentro do Service Provider, todas as rodas subsequentes deverão passar pelo regex.
O parâmetro de rotas é um tópico leve, veremos outros detalhes interessantes no tópico relacionado a Models com typehint.
2.3 — Rotas nomeadas (Names Routes)
Em um projeto com muitas rotas, ou muitos grupos de rotas, pode ficar difícil, a declaração de novas e o consumo dessas rotas, imagine que você possui um site, com mais de 100 rotas declaradas em seu web.php, nesse caso a nomeação dessas rotas facilita com que seus arquivos .blade fiquem menos poluídos, ou outros redirecionamentos, facilita a limpeza dos consumidores das rotas.
Nomear uma rota é uma tarefa simples, veja no exemplo:
Route::get(‘lojas’,’lojasController@lojas’)->name(‘lojas’);
Veja o exemplo de consumo caso não haja parâmetros:
route(‘lojas’)
Caso haja parâmetros, é necessário uma leve mudança, passando os parâmetros através de array para o segundo parâmetro de route():
route(‘loja’,[‘loja’=>1])
Outra utilidade para a nomeação das rotas, seria na utilização de Middlewares ou em qualquer tempo da execução, pois é possível recuperar através de uma instância de Illuminate\Http\Request se a requisição em questão é correspondente com alguma rota:
request()->route()->named(‘lojas’);
A nomeação de rotas é outro tópico leve, que voltará a ser aboradados em tópicos mais profundos.
2.4-Grupos de Rotas (Route Groups)
Um Grupo de rotas para o Laravel, pode servir para agrupar diversas coisas, middlewares, namespaces para controllers, sub-dominios, prefixos, ou apenas para agrupar suas rotas.
Suponha que você possua uma API para um banco de dados que foi atualizada, sua api encontrasse na url http://minhaapi.com/, como queremos manter essa operando enquanto lançamos uma nova versão, podemos criar um grupo com prefixo v2, e colocarmos nossas novas rotas dentro desse grupo.
Veja abaixo a sintaxe para cada método:
Prefixo:
Utilizado para definir uma nome ao grupo.
Route::prefix(‘v2’)->group(function() {// rotas ..});
Middleware:
Utilizado para fazer com as requisições que estejam dentro desse grupo passem pelos middlewares informados.
Route::middleware([‘auth’])->group(function() {// rotas ..});
Namespace:
Utilizado para declarar um namespace onde os controllers declarados desse grupo possam ser localizados.
Route::namespace(‘lojas’)->group(function() {// rotas ..});
Sub Domínios:
Permite a manipulação de subdomínios a suas rotas dentro do grupo.
Route::domain(‘{version}.minhaapi.com’)->group(function() {// rotas ..});
Vale lembrar nomes declarados dentro que rotas com prefixo irão herdar o nome do prefixo em suas declarações.
Veja:
Route::prefix(‘v2’)->group(function() { Route::get(‘lojas’,’lojasController@lojas’)->name(‘lojas’);});
Essa rota terá o nome v2.lojas.
Existem outras sintaxes que podem ser utilizadas na criação de grupos, essa seria a sintaxe semântica, e os métodos podem ser usados de forma encadeada, permitindo adicionar mais de uma função ao mesmo tempo ao mesmo grupo:
Route::prefix(‘v2’)->namespace(‘v2’)->group(function() { Route::get(‘lojas’,’lojasController@lojas’)->name(‘lojas’);});
Também é possível iniciar um grupo via método estático, e definir todos os métodos com uma array:
Route::group([‘prefix’=>’v2',’namespace’=>’v2'])->group(function() { //rotas…});
Não há definição acerca do modo que deva vir a ser utilizado.
Apesar do agrupamento de rotas conter a implementação do middlewares, que é um tópico relativamente complexo, o agrupamento em si é simples e direto, então iremos ao próximo tópico.
2.5 — Route Model Binding
Esse tópico, talvez seja o mais interessante dentro do roteamento, pois é muito mal usado pelos desenvolvedores, e pode agilizar em muito o seu trabalho, o Route Model Binding, traduzido de forma literal é a ligação da sua rota com uma Model, isso pode ser feito de duas formas, de forma implícita, onde a classe será injetada em tempo de declaração de rota via typehint com a classe Model declarada, e na forma explicita, onde você irá adicionar o Model ao roteamento, após isso ele será adicionado a sua rota referenciado por um nome, veja a seguir de forma subsequente:
Route::get(‘loja/{loja}/contato’,function(App\Model\Loja $loja) { return $loja->contato;});
No RouteServiceProvider:
public function boot(){ parent::boot(); Route::model(‘loja’,App\Model\Lojas::class);}
Na rota:
Route::get(‘loja/{loja}/contato’,function(App\Model\Lojas $loja) { return $loja->contato;});
Caso nenhum registro seja encontrado, o padrão será uma responstá default com código Http 404.
Dentro da declaração explicita da rota, é possível customizar a forma de resolução do Model, a classe principal do Router permite que seja feito através do método bind:
public function boot(){ parent::boot(); Route::bind(‘lojas/{uf}’,function($uf) { return App\Model\Lojas::where(‘uf’,$uf)->first() ?? abort(404); )}}
O Route Model Binding prevê como padrão que você utilize as Models do framework para funcionarem, podem são possíveis criar bindings customizados, veremos nos tópicos que virão.
Por padrão, o Laravel devolverão um erro default 404 quando uma rota não é encontrada, mas em certos casos podemos querer uma página customizada, nesse caso podemos utilizar função fallback do roteamento:
Route::fallback(function(){});
Veremos mais sobre esse tópico nos tópicos referentes aos
Models, e la também veremos exemplos concretos de uso.
2.5 — Rate Limit
O rate limit, é um middleware padrão provido pelo Laravel para controlar a quantidade de requisições que podem ser feitas a determinada rota em determinado período de tempo.
O middleware responsável pela implementação do Rate Limit pode ser localizado em Illuminate\Routing\ThrottleRequests, que irá validar e armazenar em cache o tempo das requisições feitas.
O uso pode ser declarado da seguinte forma:
Route::middleware([‘auth:api’,’throttle:60,1’])->group(function() {// rotas ..});
O Rate Limit também pode ser adicionado dinâmica baseada no usuário autenticado, ou seja, se o usuário possui algum parâmetro que sirva de valor para o rate limit, esse pode ser definido na declaração:
Route::middleware([‘auth:api’,’throttle:rate_limit,1’])->group(function() {// rotas ..});
No exemplo, consideramos que a classe model do usuário autenticado possuí um campo com nome rate_limit contendo um valor válido para o middleware.
Esse artigo foi um pouco massante, pois os tópicos relacionados ao roteamento não da muita liberdade para exemplos práticos, porém no artigo seguinte referente aos middlewares e no posterior sobre controllers teremos exemplos de sobra, espero que a leitura tenha sido útil, e nos vemos daqui alguns dias.
See ya