Генерація URL
- Вступ
- Основи
- URL-адреси для іменованих маршрутів
- URL-адреси для дій контролера
- Об'єкти Fluent URI
- Значення за замовчуванням
Вступ
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 для попереднього запиту...
echo url()->previous();
// Отримати шлях для попереднього запиту...
echo url()->previousPath();
Кожен з цих методів також може бути доступний через URL фасад:
use Illuminate\Support\Facades\URL;
echo URL::current();
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, надавши аргумент absolute методу signedRoute:
return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
Якщо ви хочете згенерувати тимчасовий підписаний URL маршруту, який закінчується після вказаного часу, ви можете використовувати метод temporarySignedRoute. Коли Laravel перевіряє тимчасовий підписаний URL маршруту, він переконується, що час закінчення, закодований у підписаному URL, не минув:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(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-адрес за допомогою вхідного екземпляра запиту, ви можете призначити signed (Illuminate\Routing\Middleware\ValidateSignature) middleware до маршруту. Якщо вхідний запит не має дійсного підпису, middleware автоматично поверне 403 HTTP-відповідь:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');
Якщо ваші підписані URL-адреси не включають домен у хеш URL-адреси, ви повинні надати аргумент relative до middleware:
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) {
$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]);
Об'єкти Fluent 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()->addMinutes(5));
$uri = Uri::action([UserController::class, 'index']);
$uri = Uri::action(InvokableController::class);
// Створити екземпляр URI з поточного URL запиту...
$uri = $request->uri();
Якщо у вас є екземпляр 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 Laravel SubstituteBindings. Ви можете досягти цього, використовуючи метод middleware priority у файлі bootstrap/app.php вашого застосунку:
->withMiddleware(function (Middleware $middleware) {
$middleware->prependToPriorityList(
before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
prepend: \App\Http\Middleware\SetDefaultLocaleForUrls::class,
);
})
