Generación de URL
- Introducción
- Los Fundamentos
- URLs para Rutas Nombradas
- URLs para Acciones de Controlador
- Valores Predeterminados
Introducción
Laravel ofrece varios helpers para ayudarte a generar URL para tu aplicación. Estos helpers son especialmente ú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 URL
El helper url
se puede utilizar para generar URL arbitrarias para tu aplicación. La URL generada utilizará 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 arreglos de valores como parámetros de consulta. Estos valores estarán correctamente indexados y codificados 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 ninguna ruta al helper url
, se devuelve una instancia de Illuminate\Routing\UrlGenerator
, lo que te permite acceder a información sobre la URL actual:
// Get the current URL without the query string...echo url()->current(); // Get the current URL including the query string...echo url()->full(); // Get the full URL for the previous request...echo url()->previous();
Cada uno de estos métodos también puede accederse a través de la URL
facade:
use Illuminate\Support\Facades\URL; echo URL::current();
URLs para Rutas Nombradas
El helper route
puede utilizarse para generar URL a rutas nombradas. Las rutas nombradas te permiten generar URL 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 se puede utilizar 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 añadirá 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 utilizando la clave de ruta (típicamente la clave primaria) de modelos de Eloquent. Por esta razón, puedes pasar modelos de Eloquent como valores de parámetro. 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 URL "firmadas" para rutas nombradas. Estas URL tienen un hash de "firma" añadido a la cadena de consulta, lo que permite que Laravel verifique que la URL no ha sido modificada desde que fue creada. Las URL firmadas son especialmente útiles para rutas que son accesibles públicamente pero que necesitan una capa de protección contra la manipulación de URL.
Por ejemplo, podrías usar URL firmadas para implementar un enlace público de "desuscribirse" que se envía por correo electrónico a tus clientes. Para crear una URL firmada a una ruta nombrada, utiliza 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 período de tiempo específico, 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 que está 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, es posible que necesites permitir que el frontend de tu aplicación añada 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 utilizando el método hasValidSignatureWhileIgnoring
. Recuerda que ignorar parámetros permite que cualquiera modifique esos parámetros en la solicitud:
if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) { abort(401);}
En lugar de validar las URL firmadas utilizando la instancia de la 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 URL 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 una "función anónima" de renderizado personalizada 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 del Controlador
La función action
genera una URL para la acción del controlador dada:
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, es posible que desees especificar valores predeterminados a nivel de solicitud para ciertos parámetros de URL. Por ejemplo, imagina que muchas de tus rutas definen un parámetro {locale}
:
Route::get('/{locale}/posts', function () { // ...})->name('post.index');
Es engorroso tener que pasar el locale
cada vez que llamas al helper route
. Así que puedes usar el método URL::defaults
para definir un valor por defecto para este parámetro que se aplicará siempre 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{ /** * 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); }}
Una vez que se ha establecido el valor predeterminado para el parámetro locale
, ya no es necesario pasar su valor al generar URL 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 las vinculaciones de modelo implícitas por parte de Laravel. Por lo tanto, debes priorizar tu middleware que establece los predeterminados de URL para que se ejecuten antes del middleware SubstituteBindings
de Laravel. Puedes lograr esto utilizando el método de middleware priority
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, ]);})