Глава 9 - Ссылки и система навигации
О работе "Глава 9 - Ссылки и система навигации"
Единая точка входа приложения (фронт-контроллер) и помощники в шаблонах позволяют полностью разделить способ отображения URL и работу,которую они выполняют. Назовём это навигацией. Навигация позволяет создавать более удобные и безопасные приложения. Эта глава расскажет вам обо всём, что нужно знать, что бы обрабатывать URL в ваших приложениях: Так же вы познакомитесь с некоторыми приемами настройки производительности навигации. Навигация - это механизм, который переписывает URL, что они были более удобными. Что бы понять, почему это важно, задумайтесь об URL. URL передают информацию от броузера к серверу, необходимую для вызова действия, желаемого пользователем. Например, традиционный URL содержит путь к файлу скрипта и параметры запроса, как в этом примере: Этот URL содержит информацию об архитектуре приложения и базы данных. Разработчики обычно прячут инфраструктуру приложения (например, они выбирают заглавия страниц вроде "Информация о пользователе", а не "QZ7.65"). Демонстрация внутренней структуры приложения в URL противоречит этому принципу и имеет отрицательные стороны: Технические данные, засветившиеся в URL, создают потенциальные дыры в безопасности. Что случится с предыдущим примером, если недоброжелательный пользователь изменит параметр Появление неразборчивых ссылок раздражает и делает менее выразительным впечатление от окружающего их контента. В наши дни URL появляются не только в адресной строке. Они появляются, когда пользователь проводит указателем мыши над ссылкой, а так же в результатах поиска. Когда пользователь ищет информацию, вы хотите дать ему понять, что же он нашел, а не сбивающий с толку URL, как на Рисунке 9-1. Рисунок 9-1 - URL появляются во многих местах, например, в результатах запроса к поисковым серверам Было бы намного хуже. если бы симфони не использовала принцип фронт-контроллера; это означало бы, что приложение состоит из большого количества скриптов, доступных из Интернет, находящихся в различных директориях, как, например, вот это: В этом случае, разработчикам пришлось бы приводить в соответствие внешний вид всех URL с файловой структурой, что при каждом изменении структуры превратило бы поддержку сайта в кошмар. Идея навигации в том, что бы рассматривать URL как часть интерфейса. Приложение может сформировать URL таким образом, что бы предоставить пользователю информацию, а пользователь может использовать URL для обращения к ресурсам приложения. Это возможно в приложениях симфони, поскольку URL, предоставляемая пользователю, не связана с инструкциями о том, как серверу следует обработать запрос. Напротив, она сотносится с запрашиваемой информацией, и может быть свободно отформатирована. Наример, симфони поймёт следующий URL и покажет ту же информацию, что и первый URL в этой главе: Преимущества таковы: Рисунок 9-2 - URL может содержать дополнительную информацию о странице, например, дату публикации URL может стать инструментом адресной строки сама по себе, позволяя обращаться к информации интуитивно понятным способом. Приложения, предоставляющие такую возможность, удобны для продвинутых пользователей. Вы можете изменять формат URL и имена действий и параметров независимо друг от друга и за одну операцию. Это значит, что сначала вы можете уделить внимание разработке, а затем отформатировать ваши URL, полностью избежав беспорядка в вашем приложении. Соответствие между URL, видимыми пользователем, и настоящим именем скрипта и параметрами запроса, достигается при помощи системы навигации, основанной на образцах, которые могут быть определены при настройке конфигурации приложения. NOTE
Изображения, каскадные таблицы стилей и файлы JavaScript находятся в подкаталогах каталога Симфони разделяет внешний URL и и его внутреннее представление URI. Соответствие между ними выполняется системой навигации. Что бы упростить обработку, симфони использует для внутренних URI синтаксис, подобный обычным URL. Пример 9-1 - Внешний URL и внутренний URI Система навигации использует специальный конфигурационный файл, называемый Пример 9-2 - Правило навигации Каждый запрос к приложению симфони сначала анализируется системой навигации (это просто организовать, благодаря единой точке входа в приложение - фронт-контроллеру). Система навигации ищет соответствие между URL запроса и образцами, определенными в правилах навигации. Если соответствие найдено, поименованные wildcard становятся параметрами запроса и объединяются с теми, которые определены в ключе Пример 9-3 - Система навигации интерпретирует URL входящих запросов TIP
Расширение Затем запрос передается действию Но этот механизм должен работать и в другую сторону. Что бы приложение могло показать внешние URL в форме ссылок, вы должны предоставить системе навигации достаточно данных, что бы можно было определить, какое правило к ним применить. Вам так же не следует записывать гиперссылки непосредственно при помощи тега Пример 9-4 - Система навигации формирует вывод URL в шаблонах Навигация - это двусторонний механизм, но он работает только в том случае, если вы используете помощник Прежде чем глубоко погрузиться в систему навигации, необходимо кое-что прояснить. Во внутренних URI примеров предыдущего раздела не было и намёка на фронт-контроллер ( В примерах сгенерированных URL вообще отсутствует имя скрипта. Это связано с тем, что URL, сгенерированные для продакшн-окружения, по умолчанию не содержат имени скрипта. Параметр Пример 9-5 - Как показывать в URL имя скрипта фронт-контроллера, Теперь генерируемые ссылки будут выглядеть следующим образом: Во всех окружениях, кроме первого (продакшн, production environment), параметр В продакшне Но как приложение узнает, какой фронт-контроллер следует вызывать? Здесь в игру вступает переписывание URL (URL rewriting). Веб-сервер может быть настроен таким образом, что бы вызывать требуемый скрипт, когда его имя не указано в URL. В веб-сервере Апач можно активировать расширение Пример 9-6 - Типовые настройки перезаписи URL в файле Веб-сервер исследует форму полученного ним URL. Если URL не содержит суффикс и кешированая версия страницы отсутствует (кеширование описано в Главе 12), то запрос обслуживается скриптом Однако, каталог Настройки mod_rewrite указывают только одно имя скрипта по умолчанию. Если вы включите no_script_name для всех ваших приложений и окружений, все URL будут восприниматься как запросы к приложению TIP
Существует способ получить несколько приложений, которые будут вызываться без указания имени скрипта. Создайте подкаталоги в каталоге Как уже говорилось ранее, вам следует использовать в шаблонах помощники ссылок вместо обычных тегов Вы уже знаете о методе-помошнике "link_to()". Он принимает два параметра: кликабельный элемент и внутренний URI, на который будет вести ссылка, и выводит совместимую с XHTML ссылку. Если вместо ссылки вы хотите вывести кнопку - используйте метод "button_to()". Так же существует метод-помошник для форм, который позволяет управлять атрибутом "action" формы. Подробнее о формах вы сможете прочитать в следующей главе. В листинге 9-7 приведены некоторые примеры использования описанных выше методов. Пример 9-7 - Link Helpers for Все эти методы могут работать как с внутренними URI, так и с статичными URL (начинающимися с "http://", система маршрутизации их игнорирует) и с якорями (anchors). Тут важно понимать, что внутренние URI строятся с учетом некоторых динамических параметров. Следующий листинг демонстрирует это: Пример 9-8 - URL, с которыми работают ссылочные методы-помошники Как показано в главе 7, методы-помошники позволяют использовать домолнительный аргумент опций, который может быть ассоциативным массивом, или строкой. Это так и для ссылочных помошников, как показано в листинге 9-9. Пример 9-9 - Ссылочные помошники позволяют использовать опции Вы так же можете использовать специфичные для symfony опции: "confirm" и "popup". Первая использует JS-диалоговое окно в момент клика по ссылке для подтверждения перехода (применимо для кнопок удаления в CMS, к примеру), а вторая - открывает документ, на который ведет ссылка в новом окне, как показано в листинге 9-10. Пример 9-10 - Все эти опции можно использовать совместно. Достаточно часто разработчик создает GET запрос в то время, как на самом деле подразумевается POST. Взгляните на этот пример: Этот запрос изменит данные, хранящиеся в приложении, добавив товар в корзину, которая хранится в сессии или базе данных. Такой URL может быть внесен в закладки, может быть закэширован, или проиндексирован поисковыми машинами. Только представьте все последствия такого для ваший базы данных! На самом деле этот запрос должен передаваться как POST. Хотя бы потому, что поисковые боты не делают POST запросов и не индексируют их. Symfony предоставляет нам возможность изменить поведение "link_to()" и "button_to()" так, чтобы они использовали POST. Для этого необходимо добавить опцию 'post=true', как показано в листинге 9-11. Пример 9-11 - Делаем POST из простой ссылки Когда происходит клик по ссылке, динамически создается форма с "action=post" и совершается переход по ней, а переход по исходной ссылке отменяется. Как видите, у этого тага есть аттрибут "href", и, если у пользователя отключен Javascript, или если по ссылке пройдет поисковый бот, он выполнит запрос GET по умолчанию. Чтобы избежать описанной выше ситуации вам необходимо ограничить ваш action таким образом, чтобы он отвечал только на POST запросы: У этого подхода есть одно ограничение - нельзя использовать ссылки с "post=true" внутри форм, так как такая ссылка при клике создает собственную форму, что приведет к некорректной работе исходной формы. Использовать ссылки с POST тогда, когда они действительно выполнают post считается хорошим тоном. В системе маршрутизации переменные, используемые в качестве аргументов для "link_to()" преобразовываются в шаблоны. Если сформированный внутренний URI не подпадает ни под одно правило, используется маршрут по умолчанию "module/action?key=value" => "module/action/key/value", как показано в листинге 9-12. Пример 9-12 - Правило маршрутизации по умолчанию Если вам нужно использовать синтакс GET и сохранить формат ?key=value для ваших параметров - вам необходимо использовать эти параметры вне передаваемого URL, в опции "query_string". Эту опцию поддерживают все ссылочные помощники. Пример 9-13 - Используем GET параметры в query_string Переменные, переданные в качестве GET параметров могут быть использованы в скриптах на стороне клиента и в переменных $_GET и $_REQUEST на стороне сервера. SIDEBAR
Методы помошники для статических ресурсов В седьмой главе вы познакомились с методами "image_tag()", "stylesheet_tag()", и "javascript_include_tag()", которые позволяют покдлючать к документу изображение, файл стиля или javasctipt файл. Пути в таких хэлперах не обрабатываются системой маршрутизации, так как они указывают на ресурсы, расположенные в публично доступной директории. Нет необходимости указывать расширение файла, Symfony автоматически использует ".png", ".js", ".css" для подключения изображения, js-файла или стиля. Более того, по умолчанию Symfony будет искать указанные файлы в директориях "web/images", "web/css", "web js". Однако, если вы хотите использовать нестандартное расширение файла, или файл из какой-то нестандартной директории, вы можете указать путь к файлу. И не беспокойтесь о атрибуте "alt" выших изображений, symfony определит его автоматически. Чтобы изменить размер изображения, используйте атрибут "size", он принимает ширину и высоту, разделенную символом Если вы хотите использовать стиль или js файл в секции Использование абсолютных путейПо умолчанию генерируемые ссылки используют относительные пути. Если по той или иной причине вам надо работать с абслютными, используйте опцию "absolete=true". Такой подход бывает полезен при работе с Email, API или RSS лентами. Пример 9-14 - Использование абсолютных путей [php] => '/routed/url/to/Finance_in_France' => 'http://www.example.com/routed/url/to/Finance_in_France' => <a href="/routed/url/to/Finance_in_France">finance</a> => <a href=" http://www.example.com/routed/url/to/Finance_in_France">finance</a> // The same goes for the asset helpers
Настройка маршрутизацииСистема маршрутизации выполняет следующие процедуры:
Преобразования выполняются по правилам, указанным в конфигурационном файле "routing.yml", который вы найдете в директории "config" приложения. В листинге 9-15 показан дефолтный файл конфигурации маршрутизации. Пример 9-15 - Файл конфигурации маршрутизации по-умолчанию, он находится в # default rules
homepage:
url: /
param: { module: default, action: index }
default_symfony:
url: /symfony/:action/*
param: { module: default }
default_index:
url: /:module
param: { action: index }
default:
url: /:module/:action/*
Правила и шаблоныПравила маршрутизации это бинарные отношения между внутренним URI и внешним URL. Они состоят из:
Шаблон может включать в себя групповые символы ( "*" к примеру) и проименованные групповые символы, которые начинаются с двоеточия. Совпадающие проименованные групповые символы преобразуются в параметры запроса. В качестве примера, в маршруте по умолчанию (:module/:action) при запросе "/foo/bar" параметр "action" примет значение "bar", а "module" => "foo", а в маршруте "default_symfony" в качестве модуля будет использоваться "symfony". Система шаблонов сверяет URL запроса со всеми правилами сверху вниз и останавливается при первом совпадении, по этому ваши более конкретизированные правила надо указывать выше более общих. Пример 9-16 - Правила проверяются сверху вниз. my_rule:
url: /foo/:bar
param: { module: mymodule, action: myaction }
# default rules
default:
url: /:module/:action/*
Пример 9-17 показывает, как сменить внешний формат URL для действия "article/read" Пример 9-17 - Меняем формат внешнего URL для "article/read" [php]
<?php echo url_for('my article', 'article/read?id=123) ?>
=> /article/read/id/123 // Default formatting
// To change it to /article/123, add a new rule at the beginning
// of your routing.yml
article_by_id:
url: /article/:id
param: { module: article, action: read }
В этом примере есть одна проблема: маршрут "article_by_id" перекрывает все маршруты, которые используют модуль "article". Фактически, при запросе "article/delete" symfony будет использовать действие "read" и id = delete. Чтобы обойти такое поведение, надо использовать шаблонное ограничение для правила, указывающее, что ":id" должно быть числом. Шаблонные ограниченияВ случае, если URL подпадает под несколько правил, вам придется переназначить правила путем добавления ограничений или требований к шаблону. Требование - это набор регулярных выражений, с которыми должны совпадать групповые символы (wildcards) URL чтобы оно подпадало под данное правило. К примеру, чтобы добавить ограничение к правилу "article_by_id", надо дописать следующую строчку: Пример 9-18 - Добавляем требование к правилу. article_by_id:
url: /article/:id
param: { module: article, action: read }
requirements: { id: \d+ }
Теперь при запросе "article/delete" действие "read" вызвано не будет, так как не выполняется требование.
Установка значений по умолчаниюВы можете указать переменным (wildcards) правила значения по умолчанию для того, чтобы правило сработало даже при отсутствии некоторых параметров, указывайте значения по умолчанию в массиве "params". К примеру, правило "article_by_id" не сработает, если не указан "id", но это можно обойти, форсировав значение "id", как показано в листинге 9-19: Пример 9-19 - Установка значения по умолчанию для wildcard. article_by_id:
url: /article/:id
param: { module: article, action: read,
id: 1
}
Параметрам по умолчанию не обязательно присутствовать в шаблоне. Таким образом вы можете управлять параметрами запроса: Пример 9-20 - Установка значения по умолчанию для параметра запроса: article_by_id:
url: /article/:id
param: { module: article, action: read, id: 1, display: true }
Ускорение системы маршрутизации средствами использования имени маршрутаМетоды-помошники для генерации ссылок поддерживают использование имени маршрута вместо пары модуль/действие, если перед ним стоит знак "@". Пример: Пример 9-21 - Использование имени маршрута [php] getId()) ?> // can also be written as getId()) ?> Вот все за и против этой технологии:
Но у этого подхода есть и свои минусы. Один из них - ссылки становятся более завуалированными, вам постоянно приходится ссылаться на routing.yml. Что лучше - решать вам. Во многом это зависит от конкретного проекта.
Добавляем расширение .htmlВзгляните на следующие адреса: http://myapp.example.com/article/Finance_in_France http://myapp.example.com/article/Finance_in_France.html Даже если за ними скрывается одна и та же страница, пользователи (и поисковые боты) будут воспринимать их по разному только из-за адреса. Второй требует хорошо организованной структуры старических веб-страниц, а это как раз то, что очень здорово индексируется поисковиками. Чтобы приписать ".html" ко всем внешним URL, которые генерируют ваши методы, установите переменную "suffix" в файле "settings.yml" конфиги приложения так, как это показано в примере 9-22. Пример 9-22 - Установка суффикса для всех адресов в prod:
.settings
suffix: .html
По умолчанию суффикс установлен в точку ("."), что означает, что система маршрутов не будет использовать суффиксы, если вы их не назначите дополнительно. Иногда бывает необходимость назначить суффикс только для одного правила - тогда вы можете добавить его прямо в строчку "url" в описании правила в "routing.yml", глобальный суффикс в таком случае будет проигнорирован. Пример 9-23 - Установка суффикса для одного адреса, in article_list:
url: /latest_articles
param: { module: article, action: list }
article_list_feed:
url: /latest_articles.rss
param: { module: article, action: list, type: feed }
Создаем правила без routing.ymlКак и большинство других конфигурационных файлов, routing.yml - не единственный метод создать правила системы маршрутов. Вы можете создавать правила в PHP - либо в config.php, либо в контроллере до вызова "dispatch()", так как он определяет, какой модуль и действие вызвать исходя из уже существующих маршрутов. Создание маршрутов в PHP позволяет вам создавать правила динамически с учетом конфигураций либо каких-то других факторов. Обработкой маршрутов занимается объект класса sfRouting (модель factory). Он доступен в любом месте кода посредствам вызова ** Новое в devel версии **
Пример 9-24 - Создаем маршрут в PHP. [php]
sfContext::getInstance()->getRouting()->prependRoute(
'article_by_id', // Route name
'/article/:id', // Route pattern
array('module' => 'article', 'action' => 'read'), // Default values
array('id' => '\d+'), // Requirements
);
Класс sfRouting имеет еще несколько методов, полезных при работе с маршрутами вручную:
Работа с маршрутами в действиях (actions)Если вам необходимо работать с текущим маршрутом в действии, к примеру, для создания ссылки "назад к странице XXX", вы должны работать с объектом класса sfRouting. Используйте адрес, возвращаемый методом Пример 9-25 - Используем sfRouting для получения информации о текущем маршруте [php]
// If you require a URL like
http://myapp.example.com/article/21
$routing = sfContext::getInstance()->getRouting();
// Use the following in article/read action
$uri = $routing->getCurrentInternalUri();
=> article/read?id=21
$uri = $routing->getCurrentInternalUri(true);
=> @article_by_id?id=21
$rule = $routing->getCurrentRouteName();
=> article_by_id
// If you just need the current module/action names,
// remember that they are actual request parameters
$module = $this->getRequestParameter('module');
$action = $this->getRequestParameter('action');
Если вам нужно получить внешний url из внутреннего так же, как это делает Пример 9-26 - Используем [php] $uri = 'article/read?id=21'; $url = $this->getController()->genUrl($uri); => /article/21 $url = $this->getController()->genUrl($uri, true); => http://myapp.example.com/article/21 ИтогМаршрутизация - двунаправленный механизм, который позволяет преобразовывать адреса таким образом, что они становятся более удобочитаемы. URL rewriting необходим для того, чтобы опускать имя контроллера ("index.php", к примеру) в ваших адресах. Если вы хотите, чтобы маршрутизация работала в обоих направлениях - вам необходимо использовать методы-помощники для вывода ссылок в ваших шаблонах. Файл Перевод Алексея Гоголева и Ната (natts) Гаджибалаева. Рейтинг работы балловГолосовать могут только зарегистрированные пользователиРегистрацияВернуться |



