Если вы обратите внимание на URL домашней страницы Joboard, то в адресной строке вы увидите: /job/1/show. Наверняка, вы привыкли видеть адреса в формате /job.php?id=1. Так как же Symfony определяет какое действие необходимо выполнить исходя из заданного адреса? Почему переменная $idнаходится там, где должно указываться действие, а не параметр? Попробуем разобраться.
Следующий код вы уже видели в шаблоне src/App/JoboardBundle/Resources/views/Job/index.html.twig.
{{ path(‘app_job_show’, { ‘id’: entity.id }) }}
При помощи функции path
Symfony генерирует необходимый нам путь для вывода статьи с идентификатором 1
. app_job_show
— имя маршрута заданное в настройках фреймворка, которые мы увидим чуть ниже.
Настройка маршрутизации
Обычно, настройка маршрутов Symfony2 задается в файле app/config/routing.yml. В нем указывается ссылка на настройки маршрутизации определённого бандла Symfony2. В нашем случае это — src/App/JoboardBundle/Resources/config/routing.yml:
# app/config/routing.yml
app_joboard:
resource: "@AppJoboardBundle/Resources/config/routing.yml"
prefix: /
Если вы обратите внимание на содержание файла routing.yml в бандле JoboardBundle, вы не сможете не заметить, что он в свою очередь импортирует другой файл настройки маршрутизации, а именно — настройки для определённого контроллера, а также определяет маршрут AppJoboardBundle_homepage
для адреса /hello/{name}
:
# src/App/JoboardBundle/Resources/config/routing.yml
AppJoboardBundle_job:
resource: "@AppJoboardBundle/Resources/config/routing/job.yml"
prefix: /job
app_joboard_homepage:
pattern: /hello/{name}
defaults: { _controller: AppJoboardBundle:Default:index }
# src/App/JoboardBundle/Resources/config/routing/job.yml
app_job:
pattern: /
defaults: { _controller: "AppJoboardBundle:Job:index" }
app_job_show:
pattern: /{id}/show
defaults: { _controller: "AppJoboardBundle:Job:show" }
app_job_new:
pattern: /new
defaults: { _controller: "AppJoboardBundle:Job:new" }
app_job_create:
pattern: /create
defaults: { _controller: "AppJoboardBundle:Job:create" }
requirements: { _method: post }
app_job_edit:
pattern: /{id}/edit
defaults: { _controller: "AppJoboardBundle:Job:edit" }
app_job_update:
pattern: /{id}/update
defaults: { _controller: "AppJoboardBundle:Job:update" }
requirements: { _method: post|put }
app_job_delete:
pattern: /{id}/delete
defaults: { _controller: "AppJoboardBundle:Job:delete" }
requirements: { _method: post|delete }
Давайте разберемся подробнее относительно маршрута app_job_show. Паттерн заданный маршрутом app_job_show
определяет адрес /{id}/show
, где знак {id}
является идентификатором вакансии. Для адреса /1/show
, id
получает значение 1
, который передаётся в качестве параметра контроллеру. Параметр _controller
— задает имя контроллера, соответствующего маршруту. В нашем случает это showAction
из JobController
в AppJoboardBundle.
Следует обратить особое внимание на параметры (например {id}), так как именно к ним у нас будет доступ из метода контроллера.
<?php
public function showAction($id)
{
// ...
}
Настройка маршрутизации в среде dev
В среде dev автоматически загружается файл app/config/routing_dev.yml, который среди прочих содержит в себе маршруты Web Debug Toolbar. Его загрузка объявлена в настройках dev окружения app/config/config_dev.yml.
Так по адресу http://joboard.local/app_dev.php расположена первая страница Symfony 2, которую вы видите после установки фреймворка. Давайте сделаем так, что в среде dev мы так же будем видеть те же страницы, что и в других средах. Откройте файл app/config/routing_dev.yml
и удалите первые три маршрута, которые относятся к бандлу Symfony demo bundle. Вот содержимое файла после редактирования:
# app/config/routing_dev.yml
_wdt:
resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
prefix: /_wdt
_profiler:
resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
prefix: /_profiler
_configurator:
resource: "@SensioDistributionBundle/Resources/config/routing/webconfigurator.xml"
prefix: /_configurator
_main:
resource: routing.yml
Не забудьте очистить кэш после этого.
php app/console cache:clear --env=prod
php app/console cache:clear --env=dev
Детальная настройка маршрутов
На данный момент перейдя по адресу / мы получим ошибку 404. Так получилось, потому что с этим адресом не связан ни один маршрут. У нас есть маршрут app_joboard_homepage, который соответствует адресу /hello/joboard и методу indexAction
из DefaultController. Направим этот маршрут на адрес /. Измените файл src/App/JoboardBundle/Resources/config/routing.yml в соответствии:
# src/App/JoboardBundle/Resources/config/routing.yml
# ...
app_joboard_homepage:
pattern: /
defaults: { _controller: AppJoboardBundle:Job:index }
Теперь очистите кэш (для prod и dev окружения и если возникает необходимость чистить кэш, то всегда делайте это для всех существующих сред окружения), перейдите по адресу http://joboard.local/app_dev.php/ и вы увидите свою домашнюю страницу. Давайте воспользуемся преимуществами маршрутизации и изменим адрес логотипа в файле шаблона. Найдите блок <div class="col-lg-4">
и поменяйте его на следующий код:
<!-- src/Resources/views/base.html.twig -->
<!-- ... -->
<div class="col-lg-4">
<a id="logo" href="{{ path('app_joboard_homepage') }}">
Joboard
</a>
</div>
<!-- ... -->
Теперь изменим сам адрес на /job/company-name/location-name/1/position-name
. Зачем мы изменили адрес? Такой адрес является более информативным, как для человека так и для поисковых систем (SEO friendly). Поправьте маршрут app_job_show
из файла src/App/JoboardBundle/Resources/config/routing/job.yml
# src/App/JoboardBundle/Resources/config/routing/job.yml
# ...
app_job_show:
pattern: /{company}/{location}/{id}/{position}/
defaults: { _controller: "AppJoboardBundle:Job:show" }
Нам необходимо передать все параметры заявленные в маршруте app_job_show. Замените маршрут {{ path('app_job_show', { 'id': entity.id }) }}
на следующий:
<!-- src/App/JoboardBundle/Resources/views/Job/index.html.twig -->
<!-- ... -->
<a href="{{ path('app_job_show', { 'id': entity.id, 'company': entity.company, 'location': entity.location, 'position': entity.position }) }}">
{{ entity.position }}
</a>
<!-- ... -->
И все-таки адреса пока ещё не приобрели нужного нам формата, на данный момент они выглядят так: http://joboard.local/app_dev.php/job/ООО Компания/Москва/1/Web Разработчик/
Нам нужно заменить все пробелы на символ —. Если мы этого не сделаем, то адрес будет выглядеть вот так: http://joboard.local/app_dev.php/job/ООО%20Компания/Москва/1/Web%20Разработчик/, т.е. браузер заменит пробелы на символы %20 и это будет выглядеть совершенно не читабельно.
Откройте файл src/App/JoboardBundle/Entity/Job.php
и добавьте следующие методы.
<?php
// src/App/JoboardBundle/Entity/Job.php
// ...
use App\JoboardBundle\Utils\Joboard as Joborad;
class Job
{
// ...
public function getCompanySlug()
{
return Joborad::slugify($this->getCompany());
}
public function getPositionSlug()
{
return Joborad::slugify($this->getPosition());
}
public function getLocationSlug()
{
return Joborad::slugify($this->getLocation());
}
}
Создайте файл src/App/JoboardBundle/Utils/Joboard.php и добавьте в него следующий метод
<?php
// src/App/JoboardBundle/Utils/Joboard.php
namespace App\JoboardBundle\Utils;
class Joboard
{
static public function slugify($text)
{
// Замена пробелов на тире
$text = preg_replace('/ +/', '-', $text);
// Приведение текста к нижнему регистру
$text = mb_strtolower(trim($text, '-'), 'utf-8');
return $text;
}
}
Мы определили три новых статичных метода: getCompanySlug()
, getPositionSlug()
, и getLocationSlug()
. Они возвращают соответствующие значение столбца после применения метода slugify(). Теперь мы можем заменить настоящие названия колонок на только что созданные.
<!-- src/App/JoboardBundle/Resources/views/Job/index.html.twig -->
<!-- ... -->
<a href="{{ path('app_job_show', { 'id': entity.id, 'company': entity.companyslug, 'location': entity.locationslug, 'position': entity.positionslug}) }}">
{{ entity.position }}
</a>
<!-- ... -->
Немного поясню, что у нас происходит в коде выше. entity
— представляет собой объект модели вакансии (Job.php). Этот объект создаётся в контроллёре (JobController метод showAction) и передаётся в шаблон вакансии. entity.id
означает, что вызывается метод getId()
класса Job.php, соответственно entity.companyslug вызывает метод companySlug и т.д. В результате имеем: http://joboard.local/app_dev.php/job/ооо-компания/москва/1/web-разработчик/
Требования маршрута
Маршрутизация содержит в себе систему проверки параметров. Каждый параметр можно проверить при помощи регулярных выражений заданных в параметре маршрута requirements.
# src/App/JoboardBundle/Resources/config/routing/job.yml
# ...
app_job_show:
pattern: /{company}/{location}/{id}/{position}
defaults: { _controller: "AppJoboardBundle:Job:show" }
requirements:
id: \d+
По этому правилу маршрут в качестве параметра id примет только целочисленное значение.
Отладка маршрутов
После добавления большого количества маршрутов полезно просмотреть всю информацию о них. Отличный способ — консольная команда router:debug
. Попробуйте выполнить её:
php app/console router:debug app_job_show
Напоследок
На сегодня достаточно. Если у вас остались вопросы, то ответы на них вы найдете прочитав главу Маршрутизация из документации или спрашивайте в комментариях.