28 июля 2011 г.

Zend + action helpers + application.ini

Action helpers иногда бывают очень полезны. В частности как замена плагинов фронт-контроллера с возможностью доступа к экземпляру конкретного контроллера действия. Примеры конфигурирования оных я и приведу.

14 июля 2011 г.

Zend_Db set timeout in app.ini

В интернете не нашёл примера для указания таймаута ресурса Db в app.ini.
resources.db.params.driver_options.2 = 6000  ;PDO::ATTR_TIMEOUT
А всё потому, что в ini файле не исполнить PDO::ATTR_TIMEOUT =(

Zend_Db_Select + UNION + COUNT

Часто бывает нужно вывести часть данных и показать сколько ещё осталось. Сделать это можно разными способами, в данном случае я использую 2 отдельных запроса.
Весело становится когда запрос на выборку данных у нас составляется UNION-ами, к которому простой COUNT(*) не применить толком =)

Нашёл лаконичное решение через пагинатор.

8 июля 2011 г.

Настройка VDS под dseye.ru

Решил переехать на более производительный тариф и заодно записать все типовые шаги в настройке (постоянно что нибудь да забуду).

Описание краткое, просто чтобы не забыть.

4 июля 2011 г.

Zend_Paginator + Cache (memcached)

Столкнулся с проблемой при попытке прикрутить нативное кеширование к пагинатору (DbTableSelect адаптер)

бутстрап (производим кеш и скармливаем пагинатору)

Copy Source | Copy HTML
  1. $backendOptions = array(
  2.             'servers' => array( array(
  3.                     'host' => '127.0.0.1',
  4.                     'port' => (APPLICATION_ENV == 'production') ? 12245 : 11211,
  5.                     'persistent' => true,
  6.                     'weight' => 1,
  7.                     'timeout' => 10,
  8.                     'retry_interval' => 15,
  9.                     'status' => true,
  10.                     'failure_callback' => null ) ) );
  11.  
  12.         $frontendOptions = array(
  13.             'lifetime' => 3600
  14.             'automatic_serialization' => true,
  15.             'caching' => (APPLICATION_ENV == 'production') ? true : true,
  16.             'cache_id_prefix' => 'dseyeUP_',
  17.             'ignore_user_abort' => true );
  18.  
  19.         $cache = Zend_Cache::factory(
  20.                         'Core',
  21.                         'Memcached',
  22.                         $frontendOptions,
  23.                         $backendOptions);
  24.         Zend_Registry::set('upCoreMem', $cache);
  25.  
  26.         Zend_Paginator::setCache($cache);
  27.  

контроллер

Copy Source | Copy HTML
  1. $count = $this->_worlds->getPlayersCount($this->idW);
  2. $this->view->paginator = $paginator = $this->_players->listWorldPlayers($this->idW, $page, $count);


По всем мануалам всё должно работать, но нет:
во первых ZFDebug показывает лишний коннект к БД перед запросом данных пагинатора
во вторых этот запрос не кешируется никогда

Долго гуглил и копал сорцы, но как то безуспешно =(

Нашёл пару багов, где у людей файловый кеш пагинатора не работал при включенном профилировании через фаербаг, но показалось что проблема не та.

Версия 1.11.0, но и на продакшене 1.11.3 тоже самое.

Сам кеш разумеется работает нормально, без проблем подцепился к метаданным DbTable, да и ручками много где используется =)

Как временно решение прикрутил ручками кеширование этого запроса по составному ключу из параметров.

Скрытая фишечка хeлпера FormRadio

Случайно наткнулся в сорцах ZF на возможность задавать атрибуты лейбла у радиобатонов.
Делается посредством конкатенации строки "label_" к имени атрибута.

Например:
Copy Source | Copy HTML
  1. $this->formRadio('filter_alliance_mod',
  2.                   isset($this->searchProp->filterAllianceMod) ? $this->searchProp->filterAllianceMod : 'only',
  3.                   array('label_class' => 'text-top'),
  4.                   array('only' => 'только', 'not' => 'исключая'),
  5.                   ' ');

Стандартный роутер ZF или "будь бдителен!"

В zf, как известно, существует стандартный роутер по имени "default". Но есть и возможность описывать свои "человекоподобные" урлы.

Итак:
Есть пачка роутеров с параметрами. Параметров много, в роутерах задаются дефолтные значения и регулярки для валидации. Казалось бы - в контроллере эти переменные проверять ненадо, ведь если человек дошёл до контроллера, значит все проверки роутера выполнились. И тут (ВНЕЗАПНО!) я вспоминаю про стандартный роутер, без всех этих проверок.
Само собой ничего критичного там нет, да и prepared state дают защиту от SQL inject, но возможность вывести сразу все данные на одной странице (пагинация с изменяемым количеством итемов на странице) тоже может доставить хлопот.

Собственно вопрос: можно ли как то запретить переходить по стандартному роутеру для действий, к которым прописан кастомный роутер?

Доку пролистал вдоль и поперёк. Что нарыл:
1.Можно убить стандартный роутер вообще (ну или заменить на заведомо левый). Но этот вариант заставляет писать роутеры для всех страниц
2.Можно в критичных действиях проверять ($this->getFrontController()->getRouter()->getCurrentRouteName() == 'default' ). Достаточно гибкое решение, но генерирует слишком много повторного кода.
3. Зашить предыдущую проверку в плагин фронт контроллера и сочинить конфиг (для определения критичных действий). Тут уже можно разгуляться, но всё равно это смотрится костылём.