parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

PF: Преобразование экшнов

Sumo 25.08.2007 08:56 / 26.08.2007 11:54

В предыдущей заметке мы поговорили о том, как происходит выбор для экшнов в PF. Простая обработка не вызывает сложностей, но на практике возникает необходимость промежуточного преобразования url перед выбором обработчиков. Самый известный инструмент для этого Апачевский модуль mod_rewrite. Но работа с ним вызывает сложности у многих разработчиков. PF предоставляет внутренний rewrite-механизм, который сильно облегчает жизнь программистам.

Модули в PFе имеют метод @rewriteAction[aAction;aActionArgs], который производит преобразование экшнов перед их маршрутизацией. Вы можете перекрыть этот метод в любом месте и сделать необходимое преобразование, причем вы можете анализировать не тольк url, но и параметры запроса (как GET так и POST). При этом в метод преобразования экшн попадает уже усеченным, без начальной части, относящейся к родительским модулям. Метод rewriteAction вызывается автоматически из метода dispatch. Правда перекрывать этот метод нужно очень редко, поскольку его штатная реализация умеет делать достаточно сложные преобразования.

Пример из жизни. У меня в интерфейсе билинговой системы есть модуль, выводящий информацию об интернет-трафике за определенный период. URLы могут быть такими следующим образом:
/traffic/192.168.0.1/
/traffic/192.168.0.1/2007/
/traffic/192.168.0.1/2007/8/
/traffic/192.168.0.1/2007/8/22/
При всем многообразии вариантов вывод информации легко делается одним методом, да и штатный метод написания обработчиков нам не подойдет - в URLе постоянная часть только "/traffic/". В этом случае нам помогут rewrite patterns:
@CLASS
internetModule

@USE
pf/web/pfSiteModule.p

@BASE
pfSiteModule

@create[aOptions][lIPPattern]
  ^BASE:create[$aOptions]

  $lIPPattern[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}]
  ^addRewritePattern[traffic/:ip<$lIPPattern>;traffic]
  ^addRewritePattern[traffic/:ip<$lIPPattern>/:year<\d{4}>;traffic]
  ^addRewritePattern[traffic/:ip<$lIPPattern>/:year<\d{4}>/:month<\d{1,2}>;traffic]
  ^addRewritePattern[traffic/:ip<$lIPPattern>/:year<\d{4}>/:month<\d{1,2}>/:day<\d{1,2}>;traffic]

...

@onINDEX[aActionArgs]
  По-умолчанию...

@onTraffic[aActionArgs]
  В переменную $aActionArgs попадет такой хэш:
  $aActionArgs[
    $.ip[192.168.0.1]
    $.year[2007]
    $.month[8]
    $.day[22]
  ]

  Это в случае с самым длинным URLом. В остальных случаях полей бедет поменьше.
Есть еще и побочный эффект: если наши экшны не совпадет ни с одним из шаблонов, то onTraffic не будет вызван, а управление перейдет к onINDEX.

Язык шаблонов для параметра aPattern метода @addRewritePattern[aPattern;aNewAction;aOptions] выглядит следуюшим образом:
  path1/(path2|path3)/:arg1/:arg2<regex>/:{arg3}-arg4
         :arg1, :arg2 - имя переменной в выходном хеше
         <regex> - регулярное выражение, которое уточняет формат в котором должна 
                   прийти переменная.
         (path|path3) - выражение, которое интерпретируется как регулярное выражение, 
                        при этом левая скобка будет заменена на "(?:". 
                        Не рекомендуется использовать! 
                        Возможно будет исключено в следующих версиях, поскольку затрудняет
                        обратное преобразование урлов.
         :{arg4} - аналогично штатному синтаксису Парсера, отделяет имя переменной от
                   ненужных символов.
Возможны и статические преобразования. Если при добавлении шаблона указать опцию $aOptions.isStatic(1), то шаблон будет считаться регулярным выражением, которое должно совпать с экшном. При этом из экшна не будут "выкусываться" никакие переменные, редирект пройдет на $aNewAction, а вкачестве аргументов для обработчика будут использованы $aOptions.args.
# Мы изменили имя функции добавления сообщения 
# в блог с "add" на "new", но хотим, чтобы у киентов работали
# старые закладки.
  ^addRewritePattern[add;new;$.isStatic(1)]
Библиотека PF