- Introducción
- Conceptos básicos
- URLs para rutas nombradas
- URLs para acciones de controladores
- Valores predeterminados
#Introducción
Laravel proporciona varios helpers para ayudarle a generar URLs para su aplicación. Estos helpers son especialmente útiles al construir enlaces en sus plantillas y respuestas API, o al generar respuestas de redirección a otra parte de su aplicación.
#Conceptos básicos
#Generación de URLs
El helper url puede usarse para generar URLs arbitrarias para su 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
#Acceder a la URL actual
Si no se proporciona una ruta al helper url, se devuelve una instancia de Illuminate\Routing\UrlGenerator, lo que le 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 accederse a través del facade 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 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 modificar las llamadas a la función route. Por ejemplo, imagine que su aplicación contiene una ruta definida así:
Route::get('/post/{post}', function (Post $post) {
// ...
})->name('post.show');
Para generar una URL a esta ruta, puede usar el helper route así:
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 en el array que no corresponda a los parámetros definidos en 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 generará URLs usando la clave de ruta (normalmente la clave primaria) de los modelos Eloquent. Por esta razón, puede 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 le permite crear fácilmente URLs "firmadas" para rutas nombradas. Estas URLs tienen un hash de "firma" añadido 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 accesibles públicamente pero que necesitan una capa de protección contra la manipulación de URLs.
Por ejemplo, podría usar URLs firmadas para implementar un enlace público de "cancelar suscripción" que se envía por correo a sus clientes. Para crear una URL firmada para una ruta nombrada, use el método signedRoute del facade URL:
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
Puede 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 desea generar una URL firmada temporal que expire después de un tiempo especificado, puede usar el método temporarySignedRoute. Cuando Laravel valida una URL firmada temporal, se asegura de que la marca de tiempo de expiración codificada en la URL no haya pasado:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
#Validación de solicitudes a rutas firmadas
Para verificar que una solicitud entrante tiene una firma válida, debe llamar al método hasValidSignature en la instancia entrante de Illuminate\Http\Request:
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
A veces, puede necesitar permitir que el frontend de su aplicación añada datos a una URL firmada, como al realizar paginación del lado del cliente. Por lo tanto, puede especificar parámetros de consulta que deben ser ignorados al validar una URL firmada usando el método hasValidSignatureWhileIgnoring. Recuerde 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 URLs firmadas usando la instancia de solicitud entrante, puede asignar el middleware Illuminate\Routing\Middleware\ValidateSignature a la ruta. Si no está presente, puede asignar un alias a este middleware en el array $middlewareAliases de su kernel HTTP:
/**
* Los alias de middleware de la aplicación.
*
* Los alias pueden usarse para asignar middleware a rutas y grupos de forma conveniente.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
];
Una vez registrado el middleware en su kernel, puede adjuntarlo a una 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 sus URLs firmadas no incluyen el dominio en el hash de la URL, debe proporcionar el argumento relative al middleware:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed:relative');
#Responder 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, puede personalizar este comportamiento definiendo un closure "renderable" personalizado para la excepción InvalidSignatureException en su manejador de excepciones. Este closure debe devolver una respuesta HTTP:
use Illuminate\Routing\Exceptions\InvalidSignatureException;
/**
* Registrar los callbacks para el manejo de excepciones de la aplicación.
*/
public function register(): void
{
$this->renderable(function (InvalidSignatureException $e) {
return response()->view('error.link-expired', [], 403);
});
}
#URLs para acciones de controladores
La función action genera una URL para la acción de controlador dada:
use App\Http\Controllers\HomeController;
$url = action([HomeController::class, 'index']);
Si el método del controlador acepta parámetros de ruta, puede pasar un array asociativo de parámetros como segundo argumento de la función:
$url = action([UserController::class, 'profile'], ['id' => 1]);
#Valores predeterminados
Para algunas aplicaciones, puede que desee especificar valores predeterminados para ciertos parámetros de URL durante toda la solicitud. Por ejemplo, imagine que muchas de sus rutas definen un parámetro {locale}:
Route::get('/{locale}/posts', function () {
// ...
})->name('post.index');
Es tedioso pasar siempre el locale cada vez que llama al helper route. Por eso, puede usar el método URL::defaults para definir un valor predeterminado para este parámetro que siempre se aplicará durante la solicitud actual. Puede llamar a este método desde un middleware de ruta para tener 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 con el helper route.
#Valores predeterminados de URL y prioridad de middleware
Establecer valores predeterminados de URL puede interferir con el manejo de bindings implícitos de modelos en Laravel. Por lo tanto, debe priorizar sus middleware que establecen valores predeterminados de URL para que se ejecuten antes del middleware SubstituteBindings de Laravel. Puede lograr esto asegurándose de que su middleware aparezca antes de SubstituteBindings en la propiedad $middlewarePriority del kernel HTTP de su aplicación.
La propiedad $middlewarePriority está definida en la clase base Illuminate\Foundation\Http\Kernel. Puede copiar su definición desde esa clase y sobrescribirla en el kernel HTTP de su aplicación para modificarla:
/**
* La lista de middleware ordenada por prioridad.
*
* Esto fuerza que los middleware no globales siempre estén en el orden dado.
*
* @var array
*/
protected $middlewarePriority = [
// ...
\App\Http\Middleware\SetDefaultLocaleForUrls::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// ...
];