Generacion de URL
Introducción
Laravel proporciona varios helpers para asistirte en la generación de URLs para tu aplicación. Estos helpers son principalmente útiles al construir enlaces en tus plantillas y respuestas de API, o al generar respuestas de redirección a otra parte de tu aplicación.
Lo Básico
Generando URLs
El helper url
puede usarse para generar URLs arbitrarias para tu aplicación. La URL generada usará automáticamente el esquema (HTTP o HTTPS) y el host de la solicitud actual que está siendo manejada por la aplicación:
$post = App\Models\Post::find(1);
echo url("/posts/{$post->id}");
// http://example.com/posts/1
Para generar una URL con parámetros de cadena de consulta, puedes usar el 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
Proporcionar parámetros de cadena de consulta que ya existen en la ruta sobrescribirá su valor existente:
echo url()->query('/posts?sort=latest', ['sort' => 'oldest']);
// http://example.com/posts?sort=oldest
También se pueden pasar arrays de valores como parámetros de consulta. Estos valores se codificarán y se les asignarán claves correctamente en la URL generada:
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
Accediendo a la URL Actual
Si no se proporciona una ruta al helper url
, se devuelve una instancia de Illuminate\Routing\UrlGenerator
, lo que te permite acceder a información sobre la URL actual:
// Obtener la URL actual sin la cadena de consulta...
echo url()->current();
// Obtener la URL actual incluyendo la cadena de consulta...
echo url()->full();
// Obtener la URL completa de la solicitud anterior...
echo url()->previous();
Cada uno de estos métodos también puede ser accedido a través de la fachada URL
:
use Illuminate\Support\Facades\URL;
echo URL::current();
URLs para Rutas Nombradas
El helper route
puede usarse para generar URLs a rutas nombradas. Las rutas nombradas te permiten generar URLs sin estar acoplado a la URL real definida en la ruta. Por lo tanto, si la URL de la ruta cambia, no es necesario hacer cambios en tus llamadas a la función route
. Por ejemplo, imagina que tu aplicación contiene una ruta definida como la siguiente:
Route::get('/post/{post}', function (Post $post) {
// ...
})->name('post.show');
Para generar una URL a esta ruta, puedes usar el helper route
de la siguiente manera:
echo route('post.show', ['post' => 1]);
// http://example.com/post/1
Por supuesto, el helper route
también puede usarse para generar URLs para rutas con múltiples parámetros:
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
Cualquier elemento adicional del array que no corresponda a los parámetros de definición de la ruta se agregará a la cadena de consulta de la URL:
echo route('post.show', ['post' => 1, 'search' => 'rocket']);
// http://example.com/post/1?search=rocket
Modelos Eloquent
A menudo estarás generando URLs usando la clave de ruta (típicamente la clave primaria) de los modelos Eloquent. Por esta razón, puedes pasar modelos Eloquent como valores de parámetros. El helper route
extraerá automáticamente la clave de ruta del modelo:
echo route('post.show', ['post' => $post]);
URLs Firmadas
Laravel te permite crear fácilmente URLs «firmadas» para rutas nombradas. Estas URLs tienen un hash de «firma» adjunto a la cadena de consulta que permite a Laravel verificar que la URL no ha sido modificada desde que fue creada. Las URLs firmadas son especialmente útiles para rutas que son públicamente accesibles pero necesitan una capa de protección contra la manipulación de URLs.
Por ejemplo, podrías usar URLs firmadas para implementar un enlace público de «desuscripción» que se envía por correo electrónico a tus clientes. Para crear una URL firmada a una ruta nombrada, usa el método signedRoute
de la fachada URL
:
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
Puedes excluir el dominio del hash de la URL firmada proporcionando el argumento absolute
al método signedRoute
:
return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
Si deseas generar una URL de ruta firmada temporal que expire después de un tiempo especificado, puedes usar el método temporarySignedRoute
. Cuando Laravel valida una URL de ruta firmada temporal, se asegurará de que la marca de tiempo de expiración codificada en la URL firmada no haya expirado:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
Validando Solicitudes de Rutas Firmadas
Para verificar que una solicitud entrante tiene una firma válida, debes llamar al método hasValidSignature
en la instancia de Illuminate\Http\Request
entrante:
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
A veces, puede que necesites permitir que el frontend de tu aplicación agregue datos a una URL firmada, como al realizar paginación del lado del cliente. Por lo tanto, puedes especificar parámetros de consulta de solicitud que deben ser ignorados al validar una URL firmada usando el método hasValidSignatureWhileIgnoring
. Recuerda, ignorar parámetros permite que cualquiera modifique esos parámetros en la solicitud:
if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
abort(401);
}
En lugar de validar URLs firmadas usando la instancia de solicitud entrante, puedes asignar el middleware signed
(Illuminate\Routing\Middleware\ValidateSignature
) a la ruta. Si la solicitud entrante no tiene una firma válida, el middleware devolverá automáticamente una respuesta HTTP 403:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');
Si tus URLs firmadas no incluyen el dominio en el hash de la URL, debes proporcionar el argumento relative
al middleware:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed:relative');
Respondiendo a Rutas Firmadas Inválidas
Cuando alguien visita una URL firmada que ha expirado, recibirá una página de error genérica para el código de estado HTTP 403. Sin embargo, puedes personalizar este comportamiento definiendo un closure de «render» personalizado para la excepción InvalidSignatureException
en el archivo bootstrap/app.php
de tu aplicación:
use Illuminate\Routing\Exceptions\InvalidSignatureException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (InvalidSignatureException $e) {
return response()->view('errors.link-expired', status: 403);
});
})
URLs para Acciones de Controladores
La función action
genera una URL para la acción del controlador dado:
use App\Http\Controllers\HomeController;
$url = action([HomeController::class, 'index']);
Si el método del controlador acepta parámetros de ruta, puedes pasar un array asociativo de parámetros de ruta como segundo argumento a la función:
$url = action([UserController::class, 'profile'], ['id' => 1]);
Valores Predeterminados
Para algunas aplicaciones, puede que desees especificar valores predeterminados para ciertos parámetros de URL en toda la solicitud. Por ejemplo, imagina que muchas de tus rutas definen un parámetro {locale}
:
Route::get('/{locale}/posts', function () {
// ...
})->name('post.index');
Es tedioso pasar siempre el locale
cada vez que llamas al helper route
. Entonces, puedes usar el método URL::defaults
para definir un valor predeterminado para este parámetro que siempre se aplicará durante la solicitud actual. Puede que desees llamar a este método desde un middleware de ruta para que tengas acceso a la solicitud actual:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Symfony\Component\HttpFoundation\Response;
class SetDefaultLocaleForUrls
{
/**
* Manejar una solicitud entrante.
*
* @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);
}
}
Una vez que se ha establecido el valor predeterminado para el parámetro locale
, ya no es necesario pasar su valor al generar URLs a través del helper route
.
Valores Predeterminados de URL y Prioridad de Middleware
Establecer valores predeterminados de URL puede interferir con el manejo de Laravel de las vinculaciones de modelos implícitas. Por lo tanto, debes priorizar tu middleware que establece valores predeterminados de URL para que se ejecute antes del middleware SubstituteBindings
de Laravel. Puedes lograr esto usando el método priority
de middleware en el archivo bootstrap/app.php
de tu aplicación:
->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,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
]);
})