Url Generation

URL Generation

Introduction

Laravel proporciona varios helpers que te ayudan a generar URLs para tu aplicación. Estos helpers son especialmente útiles al construir enlaces en tus plantillas y respuestas de API, o al generar redirect responses a otra parte de tu aplicación.


The Basics

Generating 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 la aplicación esté manejando:

$post = App\Models\Post::find(1);

echo url("/posts/{$post->id}");

// http://example.com/posts/1

Para generar una URL con parámetros de query string, 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

Si proporcionas parámetros de query string que ya existen en la ruta, estos valores serán sobrescritos:

echo url()->query('/posts?sort=latest', ['sort' => 'oldest']);

// http://example.com/posts?sort=oldest

También puedes pasar arreglos de valores como parámetros de query. Estos valores estarán debidamente 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

Accessing the Current URL

Si no se proporciona una ruta al helper url, se devolverá una instancia de Illuminate\Routing\UrlGenerator, permitiéndote acceder a la URL actual:

// Obtener la URL actual sin el query string...
echo url()->current();

// Obtener la URL actual incluyendo el query string...
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 de la facade URL:

use Illuminate\Support\Facades\URL;

echo URL::current();

URLs for Named Routes

URLs for named Routes

El helper route puede usarse para generar URLs para named routes. Las named routes permiten generar URLs sin acoplarse a la URL real definida en la ruta. Por ejemplo, si tu aplicación tiene una ruta 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 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á al query string de la URL:

echo route('post.show', ['post' => 1, 'search' => 'rocket']);

// http://example.com/post/1?search=rocket

Eloquent Models

Con frecuencia, generarás URLs usando la clave de ruta (típicamente la clave primaria) de modelos Eloquent. Puedes pasar modelos Eloquent como valores de parámetro, y el helper route extraerá automáticamente la key de ruta del modelo:

echo route('post.show', ['post' => $post]);

Signed URLs

Laravel permite crear fácilmente URLs “firmadas” para named routes. Estas URLs tienen un “hash” de firma en el query string que permite a Laravel verificar que la URL no haya sido modificada. Son útiles para rutas públicas que necesitan protección contra la manipulación de URLs.

Por ejemplo, podrías usar URLs firmadas para implementar un enlace público de “desuscribirse” en un correo a tus usuarios. 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]);

Si deseas excluir el dominio del hash de la URL firmada, proporciona el argumento absolute a false en el método signedRoute:

return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);

Para generar una URL de ruta firmada temporal que expire después de un tiempo específico, usa temporarySignedRoute. Al validar una URL de ruta firmada temporal, Laravel se asegura que la marca de tiempo de expiración en la URL firmada no haya caducado:

use Illuminate\Support\Facades\URL;

return URL::temporarySignedRoute(
    'unsubscribe', now()->addMinutes(30), ['user' => 1]
);

Validating Signed Route Requests

Para verificar que una solicitud entrante tenga una firma válida, llama 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');

Si necesitas permitir que el frontend de tu aplicación agregue datos a una URL firmada, puedes especificar parámetros de solicitud que deben ignorarse al validar la URL usando hasValidSignatureWhileIgnoring:

if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
    abort(401);
}

En lugar de validar URLs firmadas en la instancia de request entrante, puedes asignar el middleware signeda la ruta, que automáticamente devolverá una respuesta 403 si la solicitud entrante no tiene una firma válida:

Route::post('/unsubscribe/{user}', function (Request $request) {
    // ...
})->name('unsubscribe')->middleware('signed');

Si tus URLs firmadas no incluyen el dominio en el hash, proporciona el argumento relative al middleware:

Route::post('/unsubscribe/{user}', function (Request $request) {
    // ...
})->name('unsubscribe')->middleware('signed:relative');

Responding to Invalid Signed Routes

Cuando alguien visita una URL firmada que ha expirado, recibirá una página de error genérica para el estado HTTP 403. Puedes personalizar esta respuesta definiendo un closure para la función “render” 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 for Controller Actions

La función action genera una URL para la acción del controlador especificada:

use App\Http\Controllers\HomeController;

$url = action([HomeController::class, 'index'])

Si el método del controlador acepta parámetros de ruta, puedes pasar un arreglo asociativo de parámetros de ruta como segundo argumento:

$url = action([UserController::class, 'profile'], ['id' => 1]);

Default Values

Para algunas aplicaciones, es útil especificar valores predeterminados para ciertos Url parameters. Por ejemplo, si 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 a route. Puedes usar el método URL::defaults para definir un valor predeterminado para este parámetro:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Symfony\Component\HttpFoundation\Response;

class SetDefaultLocaleForUrls
{
    public function handle(Request $request, Closure $next): Response
    {
        URL::defaults(['locale' => $request->user()->locale]);

        return $next($request);
    }
}

Una vez que el valor predeterminado para el parámetro locale se ha establecido, no es necesario pasarlo al generar URLs con el helper route.

URL Defaults and Middleware Priority

Establecer valores predeterminados para URLs puede interferir con el manejo implícito de model bindings. Por lo tanto, deberías priorizar el middleware (prioritize your middleware) que setea los valores por defecto en la Url para que se ejecute después del middleware SubstituteBindings de Laravel. Puedes lograr esto usando el método priority de los middlewares en bootstrap/app.php

->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,
    ]);
})