Генерація URL · Laravel
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:
// Отримати поточний URL без рядка запиту...
echo url()->current();
// Отримати поточний URL разом із рядком запиту...
echo url()->full();
Кожен із цих методів також доступний через фасад URL:
use Illuminate\Support\Facades\URL;
echo URL::current();
Доступ до попереднього URL
Інколи корисно знати попередній URL, з якого прийшов користувач. Ви можете отримати його через методи previous і previousPath хелпера url:
// Отримати повний URL попереднього запиту...
echo url()->previous();
// Отримати шлях попереднього запиту...
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, визначеного в маршруті. Тому, якщо 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, звісно, також генерує URL для маршрутів із кількома параметрами:
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 можна реалізувати публічне посилання «відписатися», яке ви надсилаєте клієнтам електронною поштою. Щоб створити підписаний 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 не включають домен у хеш 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;
// Створити екземпляр URI з переданого рядка...
$uri = Uri::of('https://example.com/path');
// Створити екземпляри URI для шляхів, іменованих маршрутів або дій контролерів...
$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);
// Створити екземпляр URI з URL поточного запиту...
$uri = $request->uri();
// Створити екземпляр URI з 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
{
/**
* Обробити вхідний запит.
*
* @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, який встановлює значення URL за замовчуванням, щоб він виконувався до власного middleware SubstituteBindings Laravel. Це робиться методом middleware priority у файлі bootstrap/app.php вашого застосунку:
->withMiddleware(function (Middleware $middleware): void {
$middleware->prependToPriorityList(
before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
prepend: \App\Http\Middleware\SetDefaultLocaleForUrls::class,
);
})
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.