1. Основы
  2. Генерация URL

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по 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

Если не указан путь вспомогательной функции url, будет возвращен экземпляр Illuminate\Routing\UrlGenerator, позволяя вам получить доступ к информации о текущем URL:

// Получение текущего URL без строки запроса...
echo url()->current();
 
// Получение текущего URL включая строку запроса...
echo url()->full();
 
// Получение полного URL предыдущего запроса...
echo url()->previous();

Каждый из этих методов также может быть доступен через фасад 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 с использованием экземпляра входящего запроса вы можете присвоить промежуточному ПО Illuminate\Routing\Middleware\ValidateSignature маршрут. Если его еще нет, вы можете присвоить этому промежуточному ПО псевдоним в массиве $middlewareAliases вашего ядра HTTP:

/**
* Псевдонимы промежуточного ПО приложения.
*
* Псевдонимы могут использоваться для удобного назначения промежуточных ПО маршрутам и группам.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
];

После регистрации промежуточного ПО в вашем ядре вы можете прикрепить его к маршруту. Если входящий запрос не содержит действительной подписи, промежуточное ПО автоматически вернет HTTP-ответ 403:

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

Если ваши подписанные URL не включают домен в хеш URL, вы должны предоставить аргумент relative промежуточному ПО:

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

Обработка Недопустимых Подписанных Маршрутов

Когда кто-то посещает подписанный URL, который истек, он получит общую страницу ошибки для кода состояния HTTP 403. Однако вы можете настроить это поведение, определив пользовательское замыкание "renderable" для исключения InvalidSignatureException в вашем обработчике исключений. Это замыкание должно возвращать HTTP-ответ:

use Illuminate\Routing\Exceptions\InvalidSignatureException;
 
/**
* Регистрация обработчиков исключений для приложения.
*/
public function register(): void
{
$this->renderable(function (InvalidSignatureException $e) {
return response()->view('error.link-expired', [], 403);
});
}

URL для Действий Контроллера

Функция action генерирует URL для указанного действия контроллера:

use App\Http\Controllers\HomeController;
 
$url = action([HomeController::class, 'index']);

Если метод контроллера принимает параметры маршрута, вы можете передать ассоциативный массив параметров маршрута вторым аргументом функции:

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

Значения По Умолчанию

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

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

Неудобно всегда передавать locale при вызове вспомогательной функции route. Поэтому вы можете использовать метод URL::defaults для определения значения по умолчанию для этого параметра, которое всегда будет применяться в текущем запросе. Вы можете вызвать этот метод из промежуточного ПО маршрута, чтобы иметь доступ к текущему запросу:

<?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 По Умолчанию и Приоритет Промежуточного ПО

Установка значений по умолчанию для URL может вмешиваться в обработку Laravel неявных привязок моделей. Поэтому вы должны приоритезировать свое промежуточное ПО, устанавливающее значения по умолчанию для URL, чтобы быть выполненным до собственного промежуточного ПО Laravel SubstituteBindings. Это можно сделать, убедившись, что ваше промежуточное ПО выполняется до промежуточного ПО Laravel SubstituteBindings в свойстве $middlewarePriority ядра HTTP вашего приложения.

Свойство $middlewarePriority определено в базовом классе Illuminate\Foundation\Http\Kernel. Вы можете скопировать его определение из этого класса и перезаписать его в ядре HTTP вашего приложения для модификации:

/**
* Список промежуточного ПО с сортировкой по приоритету.
*
* Это обеспечивает, что промежуточное ПО, не являющееся глобальным, всегда будет в заданном порядке.
*
* @var array
*/
protected $middlewarePriority = [
// ...
\App\Http\Middleware\SetDefaultLocaleForUrls::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// ...
];