Geração de URL
Introdução
O Laravel disponibiliza vários helpers (auxiliares) para ajudá-lo a gerar URLs para a sua aplicação. Esses auxiliares são úteis principalmente quando você estiver criando links em templates e respostas da API, ou ao gerar respostas de redirecionamento para outra parte da sua aplicação.
O básico
Gerando URLs
O assistente url
permite gerar URLs arbitrárias para a sua aplicação. A URL gerada utilizará automaticamente o esquema (HTTP ou HTTPS) e o host do pedido atual da aplicação:
$post = App\Models\Post::find(1);
echo url("/posts/{$post->id}");
// http://example.com/posts/1
Para gerar uma URL com parâmetros de string de consulta, você pode usar o método query
:
echo url()->query('/posts', ['search' => 'Laravel']);
// https://example.com/posts?search=Laravel
echo url()->query('/posts?sort=latest', ['search' => 'Laravel']);
// http://example.com/posts?sort=latest&search=Laravel
Fornecer parâmetros de strings de consulta que já existem na url irá substituir seu valor atual:
echo url()->query('/posts?sort=latest', ['sort' => 'oldest']);
// http://example.com/posts?sort=oldest
Você também pode usar arrays de valores como parâmetros de consulta. Estes valores serão devidamente encaminhados e codificados na URL gerada:
echo $url = url()->query('/posts', ['columns' => ['title', 'body']]);
// http://example.com/posts?columns%5B0%5D=title&columns%5B1%5D=body
echo urldecode($url);
// http://example.com/posts?columns[0]=title&columns[1]=body
Acesso ao endereço atual da página
Se nenhum caminho for especificado para o auxiliar url
, uma instância Illuminate\Routing\UrlGenerator
é retornada, permitindo o acesso à informação da URL atual:
// Obtenha o URL atual sem a string de consulta...
echo url()->current();
// Obtenha o URL atual incluindo a string de consulta...
echo url()->full();
// Obtenha o URL completo da solicitação anterior...
echo url()->previous();
Cada um destes métodos também pode ser acessado através da URL
facade:
use Illuminate\Support\Facades\URL;
echo URL::current();
URLs para Rotas Com Nomes
O auxiliar route
pode ser usado para gerar URLs para rotas nomeadas. As rotas nomeadas permitem gerar URLs sem serem acopladas a URL real definida na rota. Portanto, se a URL da rota mudar, nenhuma alteração precisará ser feita em suas chamadas para a função route
. Por exemplo, imagine que seu aplicativo contém uma rota definida como a seguir:
Route::get('/post/{post}', function (Post $post) {
// ...
})->name('post.show');
Para gerar uma URL para esta rota, você pode usar o recurso auxiliar route
, da seguinte maneira:
echo route('post.show', ['post' => 1]);
// http://example.com/post/1
Claro que o route
poderá ser utilizado para gerar URLs com vários parâmetros em rotas:
Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) {
// ...
})->name('comment.show');
echo route('comment.show', ['post' => 1, 'comment' => 3]);
// http://example.com/post/1/comment/3
Quaisquer elementos adicionais da matriz que não correspondem aos parâmetros de definição da rota serão adicionados ao parâmetro query da URL.
echo route('post.show', ['post' => 1, 'search' => 'rocket']);
// http://example.com/post/1?search=rocket
Modelos Eloquent
Geralmente você estará gerando URLs utilizando a chave de rota (normalmente o chave primária) dos modelos Eloquent. Por este motivo, é possível passar modelos Eloquent como valores do parâmetro. O auxiliar route
irá extrair automaticamente a chave da rota do modelo:
echo route('post.show', ['post' => $post]);
URLs assinadas
O Laravel permite criar facilmente URLs "assinadas" para rotas nomeadas. Essas URLs têm um hash de assinatura anexado à string de consulta, que permite ao Laravel verificar se a URL não foi modificada desde que foi criada. As URLs assinadas são especialmente úteis para as rotas publicamente acessíveis mas que precisam de uma camada de proteção contra a manipulação da URL.
Por exemplo, você pode usar URLs assinadas para implementar um link público de "cancelamento" que é enviado por e-mail aos seus clientes. Para criar uma URL assinada com uma rota nomeada, use o método signedRoute
da facade URL
:
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
Você pode excluir o domínio do hash da URL assinada, fornecendo o argumento absolute
para a metodologia signedRoute
:
return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
Se desejar gerar uma URL de rota assinada temporária que expira após um determinado período de tempo, você poderá usar o método temporarySignedRoute
. Quando o Laravel valida uma URL de rota assinada temporária, ele garante que a marcação da data e hora não tenha decorrido:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
Validação de pedidos de rota assinados
Para verificar se uma requisição recebida possui uma assinatura válida, você deve chamar o método hasValidSignature
em uma instância da requisição Illuminate\Http\Request
:
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
Por vezes, você poderá ter de permitir que o frontend da aplicação adicione dados a uma URL assinada, por exemplo, ao efetuar uma paginação do lado do cliente. Para tal, você pode especificar parâmetros da consulta que devem ser ignorados quando se valida uma URL assinada através do método hasValidSignatureWhileIgnoring
. Lembre-se de que a opção de ignorar os parâmetros permite que qualquer pessoa modifique estes na requisição.
if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
abort(401);
}
Em vez de validar URLs assinados usando a instância de solicitação recebida, você pode atribuir o signed
(Illuminate\Routing\Middleware\ValidateSignature
) middleware à rota. Se a solicitação recebida não tiver uma assinatura válida, o middleware retornará automaticamente uma resposta HTTP 403
:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');
Se as suas URLs assinadas não incluírem o domínio na expressão hash da URL, você deve fornecer o argumento relative
ao middleware:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed:relative');
Resposta a rotas assinadas inválidas
Quando alguém visita uma URL assinada que expirou, este receberá uma página de erro genérica para o código de status HTTP "403". No entanto, você pode personalizar esse comportamento definindo uma closure de renderização personalizada para a exceção InvalidSignatureException
no arquivo bootstrap/app.php
da sua aplicação:
use Illuminate\Routing\Exceptions\InvalidSignatureException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (InvalidSignatureException $e) {
return response()->view('error.link-expired', [], 403);
});
})
URLs para ações do controlador
A função action
gera uma URL para a ação do controlador fornecida:
use App\Http\Controllers\HomeController;
$url = action([HomeController::class, 'index']);
Se o método do controlador aceitar parâmetros de rota, você poderá passar um array para associação de parâmetros de rota como segundo argumento à função.
$url = action([UserController::class, 'profile'], ['id' => 1]);
Valores Padrão
Para algumas aplicações, pode ser desejável especificar valores padrão para alguns parâmetros da solicitação de forma global. Por exemplo, digamos que muitos dos seus roteadores definem um parâmetro {locale}
:
Route::get('/{locale}/posts', function () {
// ...
})->name('post.index');
É oneroso sempre passar o locale
todas as vezes que você chama o helper route
. Por isso, você pode usar o método URL::defaults
para definir um valor padrão para este parâmetro que será sempre aplicado durante a solicitação atual. Você pode querer chamar esse método a partir de um middleware de rota para ter acesso à solicitação atual:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Symfony\Component\HttpFoundation\Response;
class SetDefaultLocaleForUrls
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
URL::defaults(['locale' => $request->user()->locale]);
return $next($request);
}
}
Uma vez que o valor padrão para o parâmetro locale
tenha sido definido, você não precisa mais passar seu valor ao gerar URLs por meio do auxiliar route
.
URLs padrões e prioridade do middleware
Definir valores padrão de URL pode interferir no tratamento de ligações implícitas de modelo pelo Laravel. Portanto, você deve priorizar seu middleware que define URLs padrão para serem executados antes do middleware SubstituteBindings
do próprio Laravel. Você pode fazer isso usando o método de middleware priority
no arquivo bootstrap/app.php
da sua aplicação:
->withMiddleware(function (Middleware $middleware) {
$middleware->priority([
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\App\Http\Middleware\SetDefaultLocaleForUrls::class, // [tl! add]
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
]);
})