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


