sfPropelPager — это встроенная в Propel функциональность, которая позволяет организовать Пейджинг (Propel Pager), т.е. разбивку на страницы. Работает великолепно, ознакомиться подробнее можно в статье How to paginate a list. Описанные ниже действия проводились на Propel 1.3.
Принцип работы простой, сначала делается запрос на определение количества записей, а далее получаем данные с учетом количества их на странице. Например, имеем Propel ORM объекты News и NewsI18n.
Пример php-кода:
$c = new Criteria(); $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT); $pager = new sfPropelPager('News', 10); $pager->setPage($this->getRequestParameter('page', 1)); $pager->setCriteria($c); $pager->init(); $this->pager = $pager;
Реальные SQL-запросы, что получились в итоге:
# Первый запрос: определяем кол-во объектов SELECT COUNT(*) FROM `news` # Выборка данных SELECT news.* FROM `news` ORDER BY news.PUBLISHED_AT DESC LIMIT 10;
Вопрос: как заставить sfPropelPager работать с таблицей news_i18n?
Оказывается есть замечательные методы в sfPropelPager: setPeerMethod и setPeerCountMethod, которые можно переназначить. И все вроде должно быть в порядке. Как бы не так. Вот что имеем:
$c = new Criteria(); $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT); $pager = new sfPropelPager('News', 10); $pager->setPage($this->getRequestParameter('page', 1)); $pager->setPeerMethod('doSelectWithI18n'); $pager->setCriteria($c); $pager->init(); $this->pager = $pager;
Журнал запросов:
# Первый запрос: определяем кол-во объектов SELECT COUNT(*) FROM `news` # Выборка данных SELECT news.*, news_i18n.*, FROM `news`, `news_i18n` WHERE news_i18n.CULTURE='en' AND news.ID=news_i18n.ID ORDER BY news.PUBLISHED_AT DESC LIMIT 10
После изучения принципов работы sfPropelPager выяснилось следующее:
1) Как в setPeerCountMethod указать правильный метод, которого кстати нет, чтобы выборка количества осуществлялась с учётом языка?
2) Как задать язык для формирования пейджинга? В оригинальном BaseNewsPeer.php метод doSelectWithI18n имеет следующий вид: public static function doSelectWithI18n(Criteria $c, $culture = null, PropelPDO $con = null). Тут есть $culture, а sfPropelPager никак не переназначает значение, значит, срабатывает следующий код:
if ($culture === null) { $culture = sfPropel::getDefaultCulture(); }
В итоге устанавливается язык по умолчанию.
В связи с эти был написан класс, который позволяет решить данную проблему. За основу была взята идея sfPropelPager with I18n и доработана до нормального состояния.
Мой класс, который можно скачать sfPropelPagerI18n. Файл надо положить в директорию lib.
<?php /** * This class is the Propel implementation of sfPropelPager. It interacts with the propel record set and * manages criteria. * * @package symfony * @subpackage propel * @author Igor Brovchenko */ class sfPropelPagerI18n extends sfPropelPager { /** * Constructor. * * @param string $class * @param int $maxPerPage * @param string $culture * @param string $joinField default value 'ID' * @return sfPropelPagerI18n */ public function __construct($class, $maxPerPage = 10, $culture = null, $joinField = 'ID') { if ($culture === null) { $culture = sfPropel::getDefaultCulture(); } $this->joinField = $joinField; $this->currentCulture = $culture; parent::__construct($class, $maxPerPage); $this->setPeerMethod('doSelectWithI18n'); } /** * Set Criteria for Pager. * * @param Criteria $c */ public function setCriteriaI18n($c) { $this->criteria = $c; $this->criteria->addJoin( constant($this->getClass() . 'Peer::' . $this->joinField), constant($this->getClass() . 'I18nPeer::' . $this->joinField), Criteria::INNER_JOIN ); $c->add(constant($this->getClass() . 'I18nPeer::CULTURE'), $this->currentCulture); } /** * Returns the result of Pager. * */ public function getResults() { $c = $this->getCriteria(); return call_user_func(array($this->getClassPeer(), $this->getPeerMethod()), $c, $this->currentCulture); } }
Пример использования sfPropelPagerI18n:
$c = new Criteria(); $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT); $c->add(NewsPeer::IS_PUBLISHED, true, Criteria::EQUAL); // Создаем новый Pager вместо старого sfPropelPager, и указываем язык $pager = new sfPropelPagerI18n('News', 1, 'ru'); $pager->setPage($this->getRequestParameter('page', 1)); // Критерий тоже новый $pager->setCriteriaI18n($c); $pager->init(); $this->pager = $pager;
Что же позволяет делать класс sfPropelPagerI18n:
1) Автоматически формируется запрос типа doCount с учётом i18n и всех дополнительных условий Criteria.
2) Указать свою culture или учитывается текущая.
3) Указать поле для связи таблицы, по умолчанию ‘ID’, но его можно переназначить.
Ссылки по теме:
• symfony API: sfPropelPager Class
• symfony API: sfPager Class
• http://www.symfony-project.org/forum/index.php/t/14991/
• http://groups.google.fr/group/symfony-users/browse_thread/thread/413beca4468e57e2
• http://groups.google.es/group/symfony-es/browse_thread/thread/e8f00368d629649a
Август 25th, 2008 at 22:21
Круто! Спасибо за i18n класс!
Август 25th, 2008 at 22:45
😉 Там много просветов на счет работы с мультиязычностью, что можем расширяем