Недавно вышла Symfony 2 Preview Release. Я хочу рассказать какие изменения претерпела система роутинга во второй ветке фреймворка.
Итак начнем.
В статье я не описываю как работает роутинг в symfony. Об этом можно почитать тут или посмотреть код! Дальше я опишу, что изменилось во второй ветке фреймворка.
Ниже я привожу участки кода иллюстрирующие новенькое ). Роутинг я тестил отдельно от фреймворка, так что данные в правилах отличаются, но суть остается прежней. А именно отличается массив $defaults. Вместо параметров _bundle, _controller, _action, я сделал module, action.
Вывод:
Во второй ветке Symfony система роутинга переписана полностью. Раньше я считал ее громоздкой. Теперь же беру свои слова обратно. Очень приятно, что разработчики оптимизировали генерируемые файлы и сделали возможность дампить правила в apache. То что систему роутинга можно использовать одтельно от фреймворка безусловно плюс! Как по мне такие компоненты улучшают жизнь разработчика!
Итак начнем.
В статье я не описываю как работает роутинг в symfony. Об этом можно почитать тут или посмотреть код! Дальше я опишу, что изменилось во второй ветке фреймворка.
Что новенького?
- Система роутинга вынесена в компоненты, теперь ее можно использовать отдельно от фреймворка.
- Само собой переработан код, повышена производительность. На каждое правило роутинга теперь не создается объект (если конечно используется кэширование!).
- При сопоставлении роута и url'a. Сначала используется функция strpos (когда это возможно), а потом только preg_match.
- Генерацией url'ов и их сопоставлением занимаются разные объекты (ProjectUrlGenerator, ProjectUrlMatcher).
- Любой класс системы роутинга теперь можно заменить, путем передачи соответствующих параметров в конструктор класса Symfony\Components\Routing\Router.
- Помимо дампа правил в php, есть дампер для Apache. Думаю можно будет написать и дампер файлов для nginx при желании.
Чего нет?
- Убрали (а может еще не сделали) возможность использования звезд в паттернах. Правило "/:module/:action/*" работать как прежде не будет.
Ниже я привожу участки кода иллюстрирующие новенькое ). Роутинг я тестил отдельно от фреймворка, так что данные в правилах отличаются, но суть остается прежней. А именно отличается массив $defaults. Вместо параметров _bundle, _controller, _action, я сделал module, action.
Пример дампа правил в Symfony 1.2:
<?php
// auto-generated by sfRoutingConfigHandler
// date: 2010/03/14 00:46:57
return array(
'addTopic' => new sfRoute('blogs/add-topic/', array (
'module' => 'blogsEdit',
'action' => 'addTopic',
), array (), array ()),
'editTopic' => new sfRoute('blogs/edit-topic/:id/', array (
'module' => 'blogsEdit',
'action' => 'editTopic',
), array (), array ()),
'themeBlog' => new sfRoute('blogs/:name/', array (
'module' => 'blogs',
'action' => 'blog',
), array (), array ())
// .. и т.д.
);
* This source code was highlighted with Source Code Highlighter.
Пример дампа правил в Symfony 1.4:
<?php
// auto-generated by sfRoutingConfigHandler
// date: 2010/03/14 00:46:57
$this->routes['route-1'] = unserialize('Сериализованный объект');
$this->routes['route-2'] = unserialize('Сериализованный объект');
$this->routes['route-6'] = unserialize('Сериализованный объект');
$this->routes['route-7'] = unserialize('Сериализованный объект');
$this->routes['route-8'] = unserialize('Сериализованный объект');
$this->routes['route-9'] = unserialize('Сериализованный объект');
$this->routes['route-10'] = unserialize('Сериализованный объект');
$this->routes['route-11'] = unserialize('Сериализованный объект');
$this->routes['route-12'] = unserialize('Сериализованный объект');
$this->routes['homepage'] = unserialize('Сериализованный объект');
$this->routes['default_index'] = unserialize('Сериализованный объект');
$this->routes['default'] = unserialize('Сериализованный объект');
* This source code was highlighted with Source Code Highlighter.
Пример правил роутинга в Symfony 2:
# blog
addTopic:
pattern: blogs/add-topic/
defaults: { module: blogsEdit, action: addTopic }
editTopic:
pattern: blogs/edit-topic/:id/
defaults: { module: blogsEdit, action: editTopic }
themeBlog:
pattern: blogs/:name/
defaults: { module: blogs, action: blog }
* This source code was highlighted with Source Code Highlighter.
Пример класса ProjectUrlMatcher в Symfony 2:
<?php
/**
* ProjectUrlMatcher
*
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class ProjectUrlMatcher extends Symfony\\Components\\Routing\\Matcher\\UrlMatcher
{
/**
* Constructor.
*/
public function __construct(array $context = array(), array $defaults = array())
{
$this->context = $context;
$this->defaults = $defaults;
}
public function match($url)
{
$url = $this->normalizeUrl($url);
if (0 === strpos($url, '/blogs/add-topic') && preg_match('#^/blogs/add\-topic$#x', $url, $matches))
return array_merge($this->mergeDefaults($matches, array ( 'module' => 'blogsEdit', 'action' => 'addTopic',)), array('_route' => 'addTopic'));
if (0 === strpos($url, '/blogs/edit-topic') && preg_match('#^/blogs/edit\-topic/(?P<id>[^/\.]+?)$#x', $url, $matches))
return array_merge($this->mergeDefaults($matches, array ( 'module' => 'blogsEdit', 'action' => 'editTopic',)), array('_route' => 'editTopic'));
if (0 === strpos($url, '/blogs') && preg_match('#^/blogs/(?P<name>[^/\.]+?)$#x', $url, $matches))
return array_merge($this->mergeDefaults($matches, array ( 'module' => 'blogs', 'action' => 'blog',)), array('_route' => 'themeBlog'));
// и т.д.
return false;
}
}
* This source code was highlighted with Source Code Highlighter.
Пример класса ProjectUrlGenerator Symfony 2:
<?php
/**
* ProjectUrlGenerator
*
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class ProjectUrlGenerator extends Symfony\\Components\\Routing\\Generator\\UrlGenerator
{
/**
* Constructor.
*/
public function __construct(array $context = array(), array $defaults = array())
{
$this->context = $context;
$this->defaults = $defaults;
}
public function generate($name, array $parameters, $absolute = false)
{
if (!method_exists($this, $method = 'get'.$name.'RouteInfo'))
{
throw new InvalidArgumentException(sprintf('Route "%s" does not exist.', $name));
}
list($variables, $defaults, $tokens) = $this->$method();
return $this->doGenerate($variables, $defaults, $tokens, $parameters, $name, $absolute);
}
protected function getaddTopicRouteInfo()
{
return array(array (), array_merge($this->defaults, array ( 'module' => 'blogsEdit', 'action' => 'addTopic',)), array ( 0 => array ( 0 => 'text', 1 => '/', 2 => '', 3 => NULL, ), 1 => array ( 0 => 'text', 1 => '/', 2 => 'add-topic', 3 => NULL, ), 2 => array ( 0 => 'text', 1 => '/', 2 => 'blogs', 3 => NULL, ),));
}
protected function geteditTopicRouteInfo()
{
return array(array ( 'id' => ':id',), array_merge($this->defaults, array ( 'module' => 'blogsEdit', 'action' => 'editTopic',)), array ( 0 => array ( 0 => 'text', 1 => '/', 2 => '', 3 => NULL, ), 1 => array ( 0 => 'variable', 1 => '/', 2 => ':id', 3 => 'id', ), 2 => array ( 0 => 'text', 1 => '/', 2 => 'edit-topic', 3 => NULL, ), 3 => array ( 0 => 'text', 1 => '/', 2 => 'blogs', 3 => NULL, ),));
}
protected function getthemeBlogRouteInfo()
{
return array(array ( 'name' => ':name',), array_merge($this->defaults, array ( 'module' => 'blogs', 'action' => 'blog',)), array ( 0 => array ( 0 => 'text', 1 => '/', 2 => '', 3 => NULL, ), 1 => array ( 0 => 'variable', 1 => '/', 2 => ':name', 3 => 'name', ), 2 => array ( 0 => 'text', 1 => '/', 2 => 'blogs', 3 => NULL, ),));
}
}
* This source code was highlighted with Source Code Highlighter.
Пример дампа правил для Apache в Symfony 2:
RewriteCond %{PATH_INFO} ^/blogs/add\-topic/$
RewriteRule .* index.php [QSA,L,E=_ROUTING__route:addTopic,E=_ROUTING_module:blogsEdit,E=_ROUTING_action:addTopic]
RewriteCond %{PATH_INFO} ^/blogs/edit\-topic/([^/\.]+?)/$
RewriteRule .* index.php [QSA,L,E=_ROUTING__route:editTopic,E=_ROUTING_id:%1,E=_ROUTING_module:blogsEdit,E=_ROUTING_action:editTopic]
RewriteCond %{PATH_INFO} ^/blogs/([^/\.]+?)/([^/\.]+?)/$
RewriteRule .* index.php [QSA,L,E=_ROUTING__route:topicInThemeBlog,E=_ROUTING_name:%1,E=_ROUTING_id:%2,E=_ROUTING_module:blogs,E=_ROUTING_action:topic]
* This source code was highlighted with Source Code Highlighter.
Вывод:
Во второй ветке Symfony система роутинга переписана полностью. Раньше я считал ее громоздкой. Теперь же беру свои слова обратно. Очень приятно, что разработчики оптимизировали генерируемые файлы и сделали возможность дампить правила в apache. То что систему роутинга можно использовать одтельно от фреймворка безусловно плюс! Как по мне такие компоненты улучшают жизнь разработчика!