如何在Doctrine 2中对原生查询进行分页?

时间:2013-01-22 16:05:11

标签: php doctrine-orm pagination dql

Doctrine 2有Doctrine \ ORM \ Tools \ Pagination \ Paginator类,可以用来对普通的DQL查询进行分页。

但是,如果我将原始查询传递给它,我会收到此错误:

Catchable fatal error: Argument 1 passed to Doctrine\ORM\Tools\Pagination\Paginator::cloneQuery() must be an instance of Doctrine\ORM\Query, instance of Doctrine\ORM\NativeQuery given

我已尝试在cloneQuery方法中从paginator类中删除类型提示,但这只会产生更多错误,因为paginator类的其他位需要在Query中找到不在NativeQuery中的方法。

有没有简单的方法来分页本机查询而无需构建新的paginator类或从数据库中将每一行都提取到数组中?

3 个答案:

答案 0 :(得分:8)

我使自己的paginator适配器类与Zend_Paginator兼容。

可能不会是最灵活的,因为它依赖于查询开头附近的“FROM”(请参阅​​count()方法),但这是一个相对快速和简单的修复。

/**
 * Paginate native doctrine 2 queries 
 */
class NativePaginator implements Zend_Paginator_Adapter_Interface
{
    /**
     * @var Doctrine\ORM\NativeQuery
     */
    protected $query;
    protected $count;

    /**
     * @param Doctrine\ORM\NativeQuery $query 
     */
    public function __construct($query)
    {
        $this->query = $query;
    }

    /**
     * Returns the total number of rows in the result set.
     *
     * @return integer
     */
    public function count()
    {
        if(!$this->count)
        {
            //change to a count query by changing the bit before the FROM
            $sql = explode(' FROM ', $this->query->getSql());
            $sql[0] = 'SELECT COUNT(*)';
            $sql = implode(' FROM ', $sql);

            $db = $this->query->getEntityManager()->getConnection();
            $this->count = (int) $db->fetchColumn($sql, $this->query->getParameters());
        }

        return $this->count;
    }

    /**
     * Returns an collection of items for a page.
     *
     * @param  integer $offset Page offset
     * @param  integer $itemCountPerPage Number of items per page
     * @return array
     */
    public function getItems($offset, $itemCountPerPage)
    {
        $cloneQuery = clone $this->query;
        $cloneQuery->setParameters($this->query->getParameters(), $this->query->getParameterTypes());

        foreach($this->query->getHints() as $name => $value)
        {
            $cloneQuery->setHint($name, $value);
        }

        //add on limit and offset
        $sql = $cloneQuery->getSQL();
        $sql .= " LIMIT $itemCountPerPage OFFSET $offset";
        $cloneQuery->setSQL($sql);

        return $cloneQuery->getResult();
    }
}

答案 1 :(得分:0)

如果你有一个dbal查询构建器(你已经构建了 $ yourDbalQueryBuilder = $ connection-> createQueryBuilder(); )然后你可以使用:

$ yourDbalQueryBuilder-> setFirstResult(0) - > setMaxResults(100000000) - >执行() - > rowCount时();

答案 2 :(得分:0)

public function countTotalRecords($query, string $primaryKey = '*'): int
    {
        if ($query instanceof QueryBuilder) {
            $paginator = new Paginator($query->getQuery());
            return count($paginator);
        } else if ($query instanceof NativeQuery) {
            $rsm = new ResultSetMappingBuilder($query->getEntityManager());
            $rsm->addScalarResult('count', 'count');

            $sqlCount = "select count(".$primaryKey.") as count from (" . $query->getSQL() . ") as item";

            $count = $query->getEntityManager()->createNativeQuery($sqlCount, $rsm);

            if ($query->getParameter('limit')) {
                $query->setParameter('limit', null);
            }

            $count->setParameters($query->getParameters());

            return (int)$count->getSingleScalarResult();
        }
        return 0;
    }