# Класс HttpSoft\Router\Route

Класс, представляющий один маршрут.

Исходный код на GitHub.

use HttpSoft\Router\Route;

/**
 * @var mixed $handler
 */

$route = new Route('page', '/page/{token}', $handler, ['GET', 'POST']);

$route->getName(); // 'page'
$route->getPattern(); // '/page/{token}'
$route->getHandler(); // $handler
$route->getMethods(); // ['GET', 'POST']
$route->getTokens(); // []
$route->getDefaults(); // []
$route->getHost(); // null
$route->getMatchedParameters(); // []
$route->isAllowedMethod('GET'); // true
$route->isAllowedMethod('PUT'); // false

При добавлении параметра-плейсхолдера {token} в путь по умолчанию будет использоваться регулярное выражение [^/]+, которое соответствует любым символам, кроме слэша, указывающего на следующий сегмент пути.

Чтобы указать пользовательские регулярные выражения для плейсхолдеров, используйте метод tokens().

$route = (new Route('post.view', '/post/{slug}{format}', $handler))
    ->tokens(['slug' => '[\w\-]+', 'format' => '\.[a-zA-z]{3,}'])
;

$route->path(['slug' => 'post-slug', 'format' => '.html']); // '/post/post-slug.html'

Вы можете установить для токена значение по умолчанию, используя метод defaults().

$route = (new Route('post.view', '/post/{slug}{format}', $handler))
    ->tokens(['slug' => '[\w\-]+', 'format' => '\.[a-zA-z]{3,}'])
    ->defaults(['format' => '.html'])
;

$route->path(['slug' => 'post-slug']); // '/post/post-slug.html'

Используя метод host(), вы можете указать конкретный хост для маршрута.

$route = (new Route('page', '/page', $handler))
    ->host('example.com')
;

$route->getHost(); // 'example.com'

Токены маршрута, заключенные в [...], считаются необязательными.

$route = (new Route('post.list', '/posts{[page]}', $handler))
    ->tokens(['page' => '\d+'])
;

$route->path(['page' => 33]); // '/posts/33'
$route->path(); // '/posts'

Необязательные параметры ДОЛЖНЫ находиться только в самом конце маршрута.

Обратите внимание, что ведущий слэш не нужно помещать перед токеном необязательного параметра.

Также можно установить значение по умолчанию для токена необязательного параметра.

$route = (new Route('post.list', '/posts{[page]}', $handler))
    ->tokens(['page' => '\d+'])
    ->defaults(['page' => '1'])
;

$route->path(); // '/posts/1'
$route->path(['page' => null]); // '/posts'

Иногда бывает полезно иметь маршрут с несколькими необязательными параметрами подряд.

// `{[year/month/day]}` эквивалентно `{[/year/month/day]}`
$route = (new Route('post.archive', '/post/archive{[year/month/day]}', $handler))
    ->tokens(['year' => '\d{4}', 'month' => '\d{2}', 'day' => '\d{2}'])
;

// '/post/archive'
$route->path(['year' => null, 'month' => null, 'day' => null]);
// или 
$route->path();

// '/post/archive/2020/09/12'
$route->path(['year' => '2020', 'month' => '09', 'day' => '12']);
// '/post/archive/2020/09'
$route->path(['year' => '2020', 'month' => '09']);
// '/post/archive/2020'
$route->path(['year' => '2020']);

Данный класс умеет генерировать путь и URL из параметров маршрута, а также проверять совпадение с HTTP-запросом.

use HttpSoft\Message\Uri;
use HttpSoft\Router\Route;

/**
 * @var mixed $handler
 * @var Psr\Http\Message\ServerRequestInterface $request
 */

$route = (new Route('page', '/page/{require}{[optional]}', $handler))
    ->tokens(['require' => '\d+', 'optional' => '[\w-]+'])
    ->defaults(['require' => 1])
    ->host('example.com')
;

$route->match($request->withUri(new Uri('/page/slug'))); // false
$route->getMatchedParameters(); // []

$route->match($request->withUri(new Uri('/page/11'))); // true
$route->getMatchedParameters(); // ['require' => '11']

$route->match($request->withUri(new Uri('/page/25/slug'))); // true
$route->getMatchedParameters(); // ['require' => '11', 'optional' => 'slug']

$route->path(); // '/page/1'
$route->path(['require' => 11]); // '/page/11'
$route->path(['require' => 11, 'optional' => 'slug']); // '/page/11/slug'

$route->url(['require' => 11]); // '//example.com/page/11'
$route->url(['require' => '123'], true); // 'https://example.com/page/123'
$route->url(['require' => '123'], false); // 'http://example.com/page/123'

# Публичные методы

/**
 * @param string $name уникальное название маршрута.
 * @param string $pattern шаблон пути с параметрами.
 * @param mixed $handler action, controller, callable, closure и т.д.
 * @param array $methods разрешенные методы запроса для маршрута.
 */
public function __construct(string $name, string $pattern, $handler, array $methods = []);

# getName

Возвращает уникальное имя маршрута.

public function getName(): string;

# getPattern

Возвращает шаблон пути с параметрами.

public function getPattern(): string;

# getHandler

Возвращает обработчик маршрута.

/**
 * @return mixed
 */
public function getHandler();

# getMethods

Возвращает разрешенные методы запроса для маршрута.

/**
 * @return string[]
 */
public function getMethods(): array;

# getTokens

Возвращает токены параметров (имена параметров => регулярные выражения).

/**
 * @return array<string, string|null>
 */
public function getTokens(): array;

# getDefaults

Возвращает значения параметров по умолчанию (имена параметров => значения по умолчанию).

/**
 * @return array<string, string>
 */
public function getDefaults(): array;

# getHost

Возвращает хост маршрута или null, если хост не был установлен.

public function getHost(): ?string;

# getMatchedParameters

Возвращает совпавшие параметры имена параметров => значения параметров.

/**
 * @return array<string, string>
 */
public function getMatchedParameters(): array;

Совпадающие параметры могут появиться только после успешного выполнения метода match().

# isAllowedMethod

Проверяет, разрешен ли метод запроса для текущего маршрута.

public function isAllowedMethod(string $method): bool;

Передаваемый метод является регистронезависимым.

# tokens

Добавляет токены параметров и возвращает себя.

/**
 * @param array<string, mixed> $tokens `имена параметров` => `регулярные выражения`
 */
public function tokens(array $tokens): self;

Если токен параметра не является скалярным типом или null, будет брошено исключение HttpSoft\Router\Exception\InvalidRouteParameterException.

/**
 * @var mixed $handler
 */

$route = new Route('page', '/page/{id}', $handler);
$route->getTokens(); // []

$route->tokens(['id' => '\d+']);
$route->getTokens(); // ['id' => '\d+']

$route->tokens(['id' => fn() => null]); // throws InvalidRouteParameterException

# defaults

Добавляет значения параметров по умолчанию и возвращает себя.

/**
 * @param array<string, mixed> $defaults `имена параметров` => `значения по умолчанию`
 */
public function defaults(array $defaults): self;

Если значение параметра по умолчанию не является скалярным типом, будет брошено исключение HttpSoft\Router\Exception\InvalidRouteParameterException.

/**
 * @var mixed $handler
 */

$route = new Route('page', '/page/{id}', $handler);
$route->getDefaults(); // []

$route->defaults(['id' => 1]);
$route->getDefaults(); // ['id' => 1]
$route->path(); // '/page/1'

$route->defaults(['id' => fn() => null]); // throws InvalidRouteParameterException

# host

Устанавливает хост маршрута и возвращает себя.

/**
 * @param string $host имя хоста или регулярное выражение.
 */
public function host(string $host): self;

Все начальные и конечные слэши будут удалены, а все точки в регулярном выражении будут автоматически экранированы.

/**
 * @var mixed $handler
 */

$route = new Route('page', '/page/{id}', $handler);
$route->getHost(); // null

// Только для example.com
$route->host('example.com');
$route->getHost(); // 'example.com'

// Только для subdomain.example.com
$route->host('///subdomain.example.com///');
$route->getHost(); // 'subdomain.example.com'

// Для любого поддомена
$route->host('(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?).example.com');

# match

Проверяет, соответствует ли URI запроса текущему маршруту.

public function match(Psr\Http\Message\ServerRequestInterface $request): bool;

Если есть совпадение и маршрут имеет совпадающие параметры, они будут сохранены и доступны с помощью метода getMatchedParameters().

use HttpSoft\Message\Uri;

/**
 * @var mixed $handler
 * @var Psr\Http\Message\ServerRequestInterface $request
 */

$route = (new Route('page', '/page/{id}', $handler))
    ->tokens(['id' => '\d+'])
;

$route->match($request->withUri(new Uri('/page/11'))); // true
$route->getMatchedParameters(); // ['id' => '11']

$route->match($request->withUri(new Uri('/page/slug'))); // false
$route->getMatchedParameters(); // []

# path

Генерирует путь URL-адреса из параметров маршрута.

/**
 * @param array $parameters `имя параметра` => `значение параметра`.
 */
public function path(array $parameters = []): string;

Если значение параметра не соответствует его регулярному выражению или обязательный параметр имеет значение null, будет брошено исключение HttpSoft\Router\Exception\InvalidRouteParameterException.

/**
 * @var mixed $handler
 */

$route = (new Route('post', '/post/{tag}{[id]}', $handler))
    ->tokens(['tag' => '[\w-]+', 'id' => '\d+'])
;

$route->path(['tag' => 'tag-slug', 'id' => '11']); // '/post/tag-slug/11'
$route->path(['tag' => 'tag-slug', 'id' => null]); // '/post/tag-slug'
$route->path(['tag' => 'tag-slug']); // '/post/tag-slug'

$route->path(); // throws InvalidRouteParameterException
$route->path(['tag' => null]); // throws InvalidRouteParameterException
$route->path(['id' => 11]); // throws InvalidRouteParameterException
$route->path(['tag' => 'tag-slug', 'id' => 'slug']); // throws InvalidRouteParameterException

# url

Генерирует URL-адрес из параметров маршрута.

/**
 * @param array $parameters `имя параметра` => `значение параметра`.
 * @param bool|null $secure Если `true`, то `https`. Если `false`, то `http`. Если `null`, то без протокола.
 */
public function url(array $parameters = [], bool $secure = null): string;

Если хост или значение параметра не соответствует его регулярному выражению, или обязательный параметр имеет значение null, будет брошено исключение HttpSoft\Router\Exception\InvalidRouteParameterException.

/**
 * @var mixed $handler
 */

$route = new Route('home', '/', $handler);
$route->url([], 'any-host.com'); // '//any-host.com'
$route->url([], 'any-host.com', true); // 'https://any-host.com'
$route->url([], 'any-host.com', false); // 'http://any-host.com'

$route = (new Route('post', '/post/{id}', $handler))
    ->tokens(['id' => '\d+'])
    ->host('(shop|blog).example.com')
;

$route->url(['id' => 11]); // '/post/11'
$route->url(['id' => 11], 'shop.example.com'); // '//shop.example.com/post/11'
$route->url(['id' => '1'], 'blog.example.com', true); // 'https://blog.example.com/post/1'
$route->url(['id' => '1'], 'shop.example.com', false); // 'http://shop.example.com/post/1'

$route->url(); // throws InvalidRouteParameterException
$route->url(['id' => null]);; // throws InvalidRouteParameterException
$route->url(['id' => 'slug']);; // throws InvalidRouteParameterException
$route->url(['id' => 11], 'forum.example.com');; // throws InvalidRouteParameterException

Если хост не был передан, этот метод будет эквивалентен методу path().