[symfony][propel][mysql] symfony 1.2 の sfPropelPager で MySQL 行カウント SQL_CALC_FOUND_ROWS を使う


http://ossipedia.ipa.go.jp/capacity/EV0603280115/

<?php
$c = new Criteria();
$c->addDescendingOrderByColumn(ArticlePeer::CREATED_AT);

$pager = new myPropelPager('Article', 10);
$pager->setCriteria($c);
$pager->setPage($page);
//$pager->init();         // COUNT
$pager->initFoundRows();  // SQL_CALC_FOUND_ROWS
<?php

class myPropelPager extends sfPropelPager
{
    protected $results;

    public function initFoundRows()
    {
        $hasMaxRecordLimit = ($this->getMaxRecordLimit() !== false);
        $maxRecordLimit = $this->getMaxRecordLimit();

        $c1 = $this->getCriteria();
        if ($c1 instanceof myCriteria) {
            $c = $c1;
        } else {
            $c = new myCriteria();
            $c->fromCriteria($c1);
        }

        $c->addSelectModifier(myCriteria::SQL_CALC_FOUND_ROWS)->
            setOffset(0)->
            setLimit(0);

        $offset = ($this->getPage() - 1) * $this->getMaxPerPage();
        $c->setOffset($offset);

        if ($hasMaxRecordLimit) {
            $maxRecordLimit = $maxRecordLimit - $offset;
            if ($maxRecordLimit > $this->getMaxPerPage()) {
                $c->setLimit($this->getMaxPerPage());
            } else {
                $c->setLimit($maxRecordLimit);
            }
        } else {
            $c->setLimit($this->getMaxPerPage());
        }

        $this->setCriteria($c);
        $this->results = parent::getResults();

        $con = Propel::getConnection(constant($this->getClassPeer() . '::DATABASE_NAME'), Propel::CONNECTION_READ);
        $stmt = $con->query('SELECT FOUND_ROWS()');
        $count = $stmt->fetchColumn();

        $this->setNbResults($hasMaxRecordLimit ? min($count, $maxRecordLimit) : $count);

        if (($this->getPage() == 0 || $this->getMaxPerPage() == 0)) {
            $this->setLastPage(0);
        } else {
            $this->setLastPage(ceil($this->getNbResults() / $this->getMaxPerPage()));
        }
    }

    public function getResults()
    {
        if ($this->results === null) {
            $this->results = parent::getResults();
        }

        return $this->results;
    }
}

class myCriteria extends Criteria
{
    const SQL_CALC_FOUND_ROWS = 'SQL_CALC_FOUND_ROWS';

    protected $_selectModifiers = array();

    public function addSelectModifier($modifier)
    {
        $this->_selectModifiers[] = $modifier;
    }

    public function getSelectModifiers()
    {
        return array_merge(parent::getSelectModifiers(), $this->_selectModifiers);
    }

    public function clear()
    {
        $this->_selectModifiers = array();
        parent::clear();
    }

    public function fromCriteria(Criteria $c)
    {
        array_map(array($this, 'addSelectColumn'), $c->getSelectColumns());
        array_map(array($this, 'addGroupByColumn'), $c->getGroupByColumns());
        array_map(array($this, 'add'), $c->getMap());

        foreach ($c->getAsColumns() as $name => $clause) {
            $this->addAsColumn($name, $clause);
        }

        foreach ($c->getJoins() as $join) {
            $this->addJoin($join->getLeftColumns(), $join->getRightColumns(), $join->getJoinType());
        }

        foreach ($c->getSelectModifiers() as $selectModifier) {
            switch ($selectModifier) {
                case Criteria::DISTINCT:
                    $this->setDistinct();
                    break;
                case Criteria::ALL:
                    $this->setAll();
                    break;
            }
        }

        foreach ($c->getOrderByColumns() as $column) {
            list($name, $order) = explode(' ', $column);
            switch ($order) {
                case Criteria::ASC:
                    $this->addAscendingOrderByColumn($name);
                    break;
                case Criteria::DESC:
                    $this->addDescendingOrderByColumn($name);
                    break;
            }
        }

        if ($having = $c->getHaving()) {
            $this->addHaving($having);
        }

        // TODO addAlias

        $this->setUseTransaction($c->isUseTransaction());
        $this->setDbName($c->getDbName());

        $this->
            setIgnoreCase($c->isIgnoreCase())->
            setSingleRecord($c->isSingleRecord())->
            setOffset($c->getOffset())->
            setLimit($c->getLimit());

        return $this;
    }
}