Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

Генерація URL

Вступ

Laravel надає кілька хелперів, які допомагають генерувати URL для вашого застосунку. Вони насамперед корисні, коли ви створюєте посилання у шаблонах і відповідях API або генеруєте відповіді-перенаправлення до іншої частини застосунку.

Основи

Генерація URL

Хелпер url дозволяє генерувати довільні URL для вашого застосунку. Згенерований URL автоматично використає схему (HTTP чи HTTPS) і хост із поточного запиту, який обробляє застосунок:

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

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

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

Щоб згенерувати URL із параметрами рядка запиту, скористайтеся методом 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

Передавання параметрів рядка запиту, які вже є у шляху, перезапише їхні наявні значення:

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

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

Як параметри запиту можна також передавати масиви значень. Ці значення отримають коректні ключі й будуть закодовані у згенерованому URL:

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

Доступ до поточного URL

Якщо хелперу url не передано шляху, повертається екземпляр Illuminate\Routing\UrlGenerator, що дає доступ до інформації про поточний URL:

// Get the current URL without the query string...
echo url()->current();

// Get the current URL including the query string...
echo url()->full();

До кожного з цих методів можна також звернутися через фасад URL:

use Illuminate\Support\Facades\URL;

echo URL::current();

Доступ до попереднього URL

Іноді корисно знати попередній URL, з якого прийшов користувач. Отримати його можна методами previous і previousPath хелпера url:

// Get the full URL for the previous request...
echo url()->previous();

// Get the path for the previous request...
echo url()->previousPath();

Або ж через сесію ви можете отримати попередній URL як екземпляр плинного URI:

use Illuminate\Http\Request;

Route::post('/users', function (Request $request) {
    $previousUri = $request->session()->previousUri();

    // ...
});

Через сесію також можна отримати ім'я маршруту попередньо відвіданого URL:

$previousRoute = $request->session()->previousRoute();

URL для іменованих маршрутів

Хелпер route дозволяє генерувати URL до іменованих маршрутів. Іменовані маршрути дають змогу генерувати URL, не прив'язуючись до фактичної адреси, визначеної в маршруті. Тому якщо URL маршруту зміниться, ваші виклики функції route змінювати не доведеться. Наприклад, уявіть, що ваш застосунок містить такий маршрут:

Route::get('/post/{post}', function (Post $post) {
    // ...
})->name('post.show');

Щоб згенерувати URL до цього маршруту, скористайтеся хелпером route так:

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

// http://example.com/post/1

Звісно, хелпер route можна використовувати й для маршрутів із кількома параметрами:

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

Будь-які додаткові елементи масиву, що не відповідають параметрам у визначенні маршруту, буде додано до рядка запиту URL:

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

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

Моделі Eloquent

Часто ви генеруватимете URL за ключем маршруту (зазвичай первинним ключем) моделей Eloquent. Тому ви можете передавати моделі Eloquent як значення параметрів - хелпер route автоматично візьме ключ маршруту моделі:

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

Підписані URL

Laravel дозволяє легко створювати «підписані» URL до іменованих маршрутів. До рядка запиту таких URL додається хеш-«підпис», що дозволяє Laravel перевірити, чи не змінювався URL після створення. Підписані URL особливо корисні для маршрутів, які є загальнодоступними, але потребують шару захисту від маніпуляцій з адресою.

Наприклад, підписані URL можна використати для публічного посилання «відписатися», яке надсилають клієнтам електронною поштою. Щоб створити підписаний URL до іменованого маршруту, скористайтеся методом signedRoute фасаду URL:

use Illuminate\Support\Facades\URL;

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

Ви можете виключити домен із хешу підписаного URL, передавши методу signedRoute аргумент absolute:

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

Якщо ви хочете згенерувати тимчасовий підписаний URL маршруту, що спливає через певний час, скористайтеся методом temporarySignedRoute. Перевіряючи тимчасовий підписаний URL, Laravel переконається, що закодована в ньому мітка часу спливання ще не минула:

use Illuminate\Support\Facades\URL;

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

Перевірка запитів до підписаних маршрутів

Щоб перевірити, чи має вхідний запит дійсний підпис, викличте метод hasValidSignature на екземплярі Illuminate\Http\Request:

use Illuminate\Http\Request;

Route::get('/unsubscribe/{user}', function (Request $request) {
    if (! $request->hasValidSignature()) {
        abort(401);
    }

    // ...
})->name('unsubscribe');

Іноді фронтенду вашого застосунку потрібно додавати дані до підписаного URL - наприклад, під час пагінації на боці клієнта. Тому ви можете вказати параметри рядка запиту, які слід ігнорувати під час перевірки підписаного URL, методом hasValidSignatureWhileIgnoring. Пам'ятайте: ігнорування параметрів дозволяє будь-кому змінювати їх у запиті:

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

Замість перевіряти підписані URL через екземпляр вхідного запиту, ви можете призначити маршруту middleware signed (Illuminate\Routing\Middleware\ValidateSignature). Якщо вхідний запит не має дійсного підпису, middleware автоматично поверне HTTP-відповідь 403:

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

Якщо ваші підписані URL не містять домену в хеші, передайте middleware аргумент relative:

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

Реакція на недійсні підписані маршрути

Коли хтось відвідує підписаний URL, термін дії якого сплив, він отримає загальну сторінку помилки для HTTP-статусу 403. Однак ви можете налаштувати цю поведінку, визначивши власне замикання «render» для винятку InvalidSignatureException у файлі bootstrap/app.php вашого застосунку:

use Illuminate\Routing\Exceptions\InvalidSignatureException;

->withExceptions(function (Exceptions $exceptions): void {
    $exceptions->render(function (InvalidSignatureException $e) {
        return response()->view('errors.link-expired', status: 403);
    });
})

URL для дій контролерів

Функція action генерує URL для вказаної дії контролера:

use App\Http\Controllers\HomeController;

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

Якщо метод контролера приймає параметри маршруту, ви можете передати асоціативний масив параметрів другим аргументом функції:

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

Плинні об'єкти URI

Клас Uri Laravel надає зручний плинний інтерфейс для створення URI та роботи з ними через об'єкти. Цей клас обгортає функціональність пакета League URI й бездоганно інтегрується із системою маршрутизації Laravel.

Створити екземпляр Uri легко за допомогою статичних методів:

use App\Http\Controllers\UserController;
use App\Http\Controllers\InvokableController;
use Illuminate\Support\Uri;

// Generate a URI instance from the given string...
$uri = Uri::of('https://example.com/path');

// Generate URI instances to paths, named routes, or controller actions...
$uri = Uri::to('/dashboard');
$uri = Uri::route('users.show', ['user' => 1]);
$uri = Uri::signedRoute('users.show', ['user' => 1]);
$uri = Uri::temporarySignedRoute('user.index', now()->plus(minutes: 5));
$uri = Uri::action([UserController::class, 'index']);
$uri = Uri::action(InvokableController::class);

// Generate a URI instance from the current request URL...
$uri = $request->uri();

// Generate a URI instance from the previous request URL...
$uri = $request->session()->previousUri();

Маючи екземпляр URI, ви можете плинно його змінювати:

$uri = Uri::of('https://example.com')
    ->withScheme('http')
    ->withHost('test.com')
    ->withPort(8000)
    ->withPath('/users')
    ->withQuery(['page' => 2])
    ->withFragment('section-1');

Докладніше про роботу з плинними об'єктами URI дивіться в документації URI.

Значення за замовчуванням

У деяких застосунках вам може знадобитися задати значення за замовчуванням для певних параметрів URL у межах усього запиту. Наприклад, уявіть, що багато ваших маршрутів визначають параметр {locale}:

Route::get('/{locale}/posts', function () {
    // ...
})->name('post.index');

Марудно щоразу передавати locale, викликаючи хелпер route. Тож ви можете скористатися методом URL::defaults, щоб задати значення за замовчуванням для цього параметра, яке застосовуватиметься протягом поточного запиту. Цей метод варто викликати з middleware маршруту, щоб мати доступ до поточного запиту:

<?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);
    }
}

Щойно значення за замовчуванням для параметра locale задано, вам більше не потрібно передавати його, генеруючи URL хелпером route.

Значення URL за замовчуванням і пріоритет middleware

Задавання значень URL за замовчуванням може заважати обробці неявних прив'язок моделей у Laravel. Тому вам слід задати пріоритет своєму middleware, який встановлює ці значення, щоб він виконувався перед власним middleware SubstituteBindings від Laravel. Це можна зробити методом priority у файлі bootstrap/app.php вашого застосунку:

->withMiddleware(function (Middleware $middleware): void {
    $middleware->prependToPriorityList(
        before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
        prepend: \App\Http\Middleware\SetDefaultLocaleForUrls::class,
    );
})