Компонент маршрутизации Symfony 2.7 — Routing

Установка

Вы можете установить компонент двумя различными способами:

  1. Через Composer (symfony/routing в Packagist);
  2. Используя официальный Git репозиторий (https://github.com/symfony/Routing).

Затем включите vendor/autoload.php, чтобы задействовать механизм автозагрузки, поставляемый Composer’ом. Иначе, ваше приложение не сможет найти классы этого компонента Symfony.

 

Использование

Для того, чтобы настроить базовую систему маршрутизации необходимы три вещи:

  1. RouteCollection, содержащий определения маршрута (экземпляры Route класса)
  2. RequestContext, содержащий информацию о запросе
  3. UrlMatcher, выполняющий отображение запроса к одиночному маршруту

Вот небольшой пример. Обратите внимание, здесь предполагается, что вы уже сконфигурировали свой автозагрузчик для загрузки компонента Routing:

use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$route = new Route('/foo', array('controller' => 'MyController'));
$routes = new RouteCollection();
$routes->add('route_name', $route);

$context = new RequestContext($_SERVER['REQUEST_URI']);

$matcher = new UrlMatcher($routes, $context);

$parameters = $matcher->match('/foo');
// array('controller' => 'MyController', '_route' => 'route_name')

Будьте осторожны при использовании $_SERVER[‘REQUEST_URI’], поскольку он может включать любые параметры URL запроса, которые могут вызвать проблемы с определением маршрута. Самый простой способ решить эту проблему состоит в том, чтобы использовать компонент HttpFoundation, как объяснено ниже.

Вы можете добавить к RouteCollection столько маршрутов, сколько вы хотите.

Метод RouteCollection::add() принимает два параметра. Первым является название маршрута. Вторым является объект Route, ожидающий URL путь и некоторый массив пользовательских переменных в его конструкторе. Этот массив пользовательских переменных может быть всем, чем угодно, что требуется вашему приложению. Пользовательские переменные возвращаются, когда определён соответствующий маршрут.

Если подходящий маршрут не может быть найден, будет брошено ResourceNotFoundException.

В дополнение к вашему массиву пользовательских переменных добавляется _route ключ, который содержит имя определённого маршрута.

 

Определение маршрутов

Определение полного маршрута может состоять из семи частей (или меньше):

  1. URL путь маршрута. Он сравнивается с URL, переданного в RequestContext, и может содержать подстановки заполнители (например {placeholders}), соответствующие динамическим частям в URL.
  2. Массив значений по умолчанию. Он содержит массив произвольных значений, которые будут возвращены, когда запрос будет соответствовать маршруту.
  3. Массив требований. Они определяют ограничения для значений заполнителей в виде регулярных выражений.
  4. Массив опций. Они содержат внутренние настройки для маршрута и обычно наименее необходимы.
  5. Хост. Он сравнивается с хостом запроса. Смотрите, Как сопоставить маршрут на основе хоста для подробностей.
  6. Массив схем. Они соответствуют определенной схеме HTTP (http, https). (Возможно имеется ввиду протокол — прим. перев).
  7. Массив методов. Они соответствуют определенным методам HTTP запроса (HEAD, GET, POST…).

Возьмём следующий маршрут, который сочетает в себе несколько из этих идей:

$route = new Route(
    '/archive/{month}', // путь
    array('controller' => 'showArchive'), // значения по умолчанию
    array('month' => '[0-9]{4}-[0-9]{2}', 'subdomain' => 'www|m'), // требования
    array(), // опции
    '{subdomain}.example.com', // хост
    array(), // схемы
    array() // методы
);

// ...

$parameters = $matcher->match('/archive/2012-01');
// array(
//     'controller' => 'showArchive',
//     'month' => '2012-01',
//     'subdomain' => 'www',
//     '_route' => ...
//  )

$parameters = $matcher->match('/archive/foo');
// бросит ResourceNotFoundException

В этом случае, маршрут является соответствующим /archive/2012-01, потому что знак подстановки {month} соответствует данному знаку подстановки регулярного выражения. Однако /archive/foo не соответствует маршруту, потому что «foo» проваливает знак подстановки месяца.

Если вы хотите, чтобы соответствовали все адреса, которые начинаются с определенного пути и в конце имели произвольный суффикс можно использовать следующее определение маршрута:

$route = new Route(
    '/start/{suffix}',
    array('suffix' => ''),
    array('suffix' => '.*')
);

 

 Использование префиксов

Вы можете добавить маршруты или другие экземпляры RouteCollection в другую коллекцию. Таким образом, вы можете создать дерево маршрутов. Дополнительно вы можете определить префикс и значения по умолчанию для параметров, требований, опций, схем и хоста всех маршрутов, используя методы, предоставляемые RouteCollection классом:

$rootCollection = new RouteCollection();

$subCollection = new RouteCollection();
$subCollection->add(...);
$subCollection->add(...);
$subCollection->addPrefix('/prefix');
$subCollection->addDefaults(array(...));
$subCollection->addRequirements(array(...));
$subCollection->addOptions(array(...));
$subCollection->setHost('admin.example.com');
$subCollection->setMethods(array('POST'));
$subCollection->setSchemes(array('https'));

$rootCollection->addCollection($subCollection);

 

Установка параметров запроса

RequestContext предоставляет информацию о текущем запросе. Вы можете определить все параметры HTTP запроса этим классом через его конструктор:

public function __construct(
    $baseUrl = '',
    $method = 'GET',
    $host = 'localhost',
    $scheme = 'http',
    $httpPort = 80,
    $httpsPort = 443,
    $path = '/',
    $queryString = ''
)


Обычно, вы можете передать значения от $_SERVER переменной для заполнения RequestContext. Но если вы используете компонент HttpFoundation, вы можете использовать его класс Request, чтобы скормить его RequestContext по ссылке:

use Symfony\Component\HttpFoundation\Request;

$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());

 

Генерация URL

В то время как UrlMatcher пытается найти маршрут, соответствующий данному запросу, вы можете также создать URL из определенного маршрута:

use Symfony\Component\Routing\Generator\UrlGenerator;

$routes = new RouteCollection();
$routes->add('show_post', new Route('/show/{slug}'));

$context = new RequestContext($_SERVER['REQUEST_URI']);

$generator = new UrlGenerator($routes, $context);

$url = $generator->generate('show_post', array(
    'slug' => 'my-blog-post',
));
// /show/my-blog-post

При определении схемы генерируется абсолютный URL, если схема текущего RequestContext не соответствует требованиям.

 

Загрузка маршрутов из файла

Вы уже видели, как вы можете легко добавить маршруты в коллекцию прямо в PHP. Но вы можете также загрузить маршруты из ряда различных файлов.

Компонент Routing поставляется со многими классами загрузчиков, каждые дают вам возможность загрузить коллекцию определений маршрутов из внешнего файла в некотором формате. Каждый загрузчик ожидает экземпляр FileLocator в качестве параметра конструктора. Вы можете использовать FileLocator для определения массива путей, по которым загрузчик будет искать требуемые файлы. Если файл найден, то загрузчик возвращает RouteCollection.

Если Вы используете YamlFileLoader, то определения маршрута похоже на это:

# routes.yml
route1:
    path:     /foo
    defaults: { _controller: 'MyController::fooAction' }

route2:
    path:     /foo/bar
    defaults: { _controller: 'MyController::foobarAction' }

Для загрузки этого файла вы можете использовать следующий код. Он предполагает, что ваш файл routes.yml находится в том же каталоге, где и приведённых ниже код:

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;

// просмотр внутри *текущей* директории
$locator = new FileLocator(array(__DIR__));
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');

Помимо YamlFileLoader существуют два других загрузчика, работающие также:

При использовании PhpFileLoader, вы должны предоставить имя файла PHP, возвращающего RouteCollection:

// RouteProvider.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(
    'route_name',
    new Route('/foo', array('controller' => 'ExampleController'))
);
// ...

return $collection;

 

Маршруты как замыкания

Существует также ClosureLoader, вызывающий замыкание и использующий результат в качестве RouteCollection:

use Symfony\Component\Routing\Loader\ClosureLoader;

$closure = function () {
    return new RouteCollection();
};

$loader = new ClosureLoader();
$collection = $loader->load($closure);

 

Маршруты как аннотации

Наконец, что не менее важно, существует AnnotationDirectoryLoader и AnnotationFileLoader для загрузки определений маршрута из аннотаций класса. Конкретные детали опущены здесь.

 

Единый Router

Класс Router является единым пакетом для быстрого использования компонента маршрутизации. Конструктор ожидает экземпляр загрузчика, путь к определению основного маршрута и некоторые другие настройки:

public function __construct(
    LoaderInterface $loader,
    $resource,
    array $options = array(),
    RequestContext $context = null,
    array $defaults = array()
);

С опицей cache_dir вы можете включить кэширование маршрута (если вы предоставляете путь), или отключить кэширование (если он установлен в null). Кэширование выполняется автоматически в фоновом режиме, если вы хотите использовать его. Основной пример Router класса будет выглядеть так:

$locator = new FileLocator(array(__DIR__));
$requestContext = new RequestContext($_SERVER['REQUEST_URI']);

$router = new Router(
    new YamlFileLoader($locator),
    'routes.yml',
    array('cache_dir' => __DIR__.'/cache'),
    $requestContext
);
$router->match('/foo/bar');

При использовании кэширования компонент маршрутизации скомпилирует новые классы, сохраняющиеся в cache_dir. Это означает, что ваш сценарий должен иметь полномочия записи для того расположения.

 


 

Примечание

Это перевод статьи «The Routing Component (The Symfony Components)».

Комментарии

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *