Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Show file tree
Hide file tree
Showing 49 changed files with 1,099 additions and 1,852 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"homepage": "https://github.com/zendframework/zend-paginator",
"autoload": {
"psr-4": {
"Zend\\Paginator": "src/"
"Zend\\Paginator\\": "src/"
}
},
"require": {
Expand Down
2 changes: 0 additions & 2 deletions src/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
*
* @category Zend
* @package Paginator
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface AdapterInterface extends Countable
{
Expand Down
14 changes: 6 additions & 8 deletions src/Adapter/ArrayAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
/**
* @category Zend
* @package Paginator
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class ArrayAdapter implements AdapterInterface
{
Expand All @@ -23,14 +21,14 @@ class ArrayAdapter implements AdapterInterface
*
* @var array
*/
protected $_array = null;
protected $array = null;

/**
* Item count
*
* @var integer
*/
protected $_count = null;
protected $count = null;

/**
* Constructor.
Expand All @@ -39,8 +37,8 @@ class ArrayAdapter implements AdapterInterface
*/
public function __construct(array $array = array())
{
$this->_array = $array;
$this->_count = count($array);
$this->array = $array;
$this->count = count($array);
}

/**
Expand All @@ -52,7 +50,7 @@ public function __construct(array $array = array())
*/
public function getItems($offset, $itemCountPerPage)
{
return array_slice($this->_array, $offset, $itemCountPerPage);
return array_slice($this->array, $offset, $itemCountPerPage);
}

/**
Expand All @@ -62,6 +60,6 @@ public function getItems($offset, $itemCountPerPage)
*/
public function count()
{
return $this->_count;
return $this->count;
}
}
210 changes: 51 additions & 159 deletions src/Adapter/DbSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,97 +10,68 @@

namespace Zend\Paginator\Adapter;

use Zend\Db\Sql;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;
use Zend\Db\Sql\Select;
use Zend\Db\ResultSet\ResultSetInterface;
use Zend\Db\ResultSet\ResultSet;

/**
* @category Zend
* @package Zend_Paginator
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class DbSelect implements AdapterInterface
{

/**
* Name of the row count column
*
* @var string
* @var Sql
*/
const ROW_COUNT_COLUMN = 'zend_paginator_row_count';
protected $sql = null;

/**
* The COUNT query
* Database query
*
* @var \Zend\Db\Sql\Select
* @var Select
*/
protected $_countSelect = null;
protected $select = null;

/**
* Database query
*
* @var \Zend\Db\Sql\Select
* @var ResultSet
*/
protected $_select = null;
protected $resultSetPrototype = null;

/**
* Total item count
*
* @var integer
*/
protected $_rowCount = null;
protected $rowCount = null;

/**
* Constructor.
*
* @param \Zend\Db\Sql\Select $select The select query
*/
public function __construct(Sql\Select $select)
{
$this->_select = $select;
}

/**
* Sets the total row count, either directly or through a supplied
* query. Without setting this, {@link getPages()} selects the count
* as a subquery (SELECT COUNT ... FROM (SELECT ...)). While this
* yields an accurate count even with queries containing clauses like
* LIMIT, it can be slow in some circumstances. For example, in MySQL,
* subqueries are generally slow when using the InnoDB storage engine.
* Users are therefore encouraged to profile their queries to find
* the solution that best meets their needs.
*
* @param \Zend\Db\Sql\Select|integer $rowCount Total row count integer
* or query
* @param Select $select The select query
* @param Adapter|Sql $adapterOrSqlObject DB adapter or Sql object
* @param null|ResultSetInterface $resultSetPrototype
* @throws Exception\InvalidArgumentException
* @return DbSelect
*/
public function setRowCount($rowCount)
public function __construct(Select $select, $adapterOrSqlObject, ResultSetInterface $resultSetPrototype = null)
{
if ($rowCount instanceof Sql\Select) {
$columns = $rowCount->getPart(Sql\Select::COLUMNS);

$countColumnPart = $columns[0][1];

if ($countColumnPart instanceof Sql\ExpressionInterface) {
$countColumnPart = $countColumnPart->__toString();
}

$rowCountColumn = $this->_select->getAdapter()->foldCase(self::ROW_COUNT_COLUMN);
$this->select = $select;

// The select query can contain only one column, which should be the row count column
if (false === strpos($countColumnPart, $rowCountColumn)) {
throw new Exception\InvalidArgumentException('Row count column not found');
}

$result = $rowCount->query(Db\Db::FETCH_ASSOC)->fetch();
if ($adapterOrSqlObject instanceof Adapter) {
$adapterOrSqlObject = new Sql($adapterOrSqlObject);
}

$this->_rowCount = count($result) > 0 ? $result[$rowCountColumn] : 0;
} else if (is_integer($rowCount)) {
$this->_rowCount = $rowCount;
} else {
throw new Exception\InvalidArgumentException('Invalid row count');
if (!$adapterOrSqlObject instanceof Sql) {
throw new Exception\InvalidArgumentException(
'$adapterOrSqlObject must be an instance of Zend\Db\Adapter\Adapter or Zend\Db\Sql\Sql'
);
}

return $this;
$this->sql = $adapterOrSqlObject;
$this->resultSetPrototype = ($resultSetPrototype) ?: new ResultSet;
}

/**
Expand All @@ -112,9 +83,17 @@ public function setRowCount($rowCount)
*/
public function getItems($offset, $itemCountPerPage)
{
$this->_select->limit($itemCountPerPage, $offset);
$select = clone $this->select;
$select->offset($offset);
$select->limit($itemCountPerPage);

$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();

return $this->_select->query()->fetchAll();
$resultSet = clone $this->resultSetPrototype;
$resultSet->initialize($result);

return $resultSet;
}

/**
Expand All @@ -124,110 +103,23 @@ public function getItems($offset, $itemCountPerPage)
*/
public function count()
{
if ($this->_rowCount === null) {
$this->setRowCount(
$this->getCountSelect()
);
if ($this->rowCount !== null) {
return $this->rowCount;
}

return $this->_rowCount;
}
$select = clone $this->select;
$select->reset(Select::COLUMNS);
$select->reset(Select::LIMIT);
$select->reset(Select::OFFSET);

/**
* Get the COUNT select object for the provided query
*
* TODO: Have a look at queries that have both GROUP BY and DISTINCT specified.
* In that use-case I'm expecting problems when either GROUP BY or DISTINCT
* has one column.
*
* @return \Zend\Db\Sql\Select
*/
public function getCountSelect()
{
/**
* We only need to generate a COUNT query once. It will not change for
* this instance.
*/
if ($this->_countSelect !== null) {
return $this->_countSelect;
}
$select->columns(array('c' => new Expression('COUNT(1)')));

$rowCount = clone $this->_select;
$rowCount->__toString(); // Workaround for ZF-3719 and related

$db = $rowCount->getAdapter();

$countColumn = $db->quoteIdentifier($db->foldCase(self::ROW_COUNT_COLUMN));
$countPart = 'COUNT(1) AS ';
$groupPart = null;
$unionParts = $rowCount->getPart(Sql\Select::UNION);

/**
* If we're dealing with a UNION query, execute the UNION as a subquery
* to the COUNT query.
*/
if (!empty($unionParts)) {
$expression = new Sql\Expression($countPart . $countColumn);
$rowCount = $db
->select()
->bind($rowCount->getBind())
->from($rowCount, $expression);
} else {
$columnParts = $rowCount->getPart(Sql\Select::COLUMNS);
$groupParts = $rowCount->getPart(Sql\Select::GROUP);
$havingParts = $rowCount->getPart(Sql\Select::HAVING);
$isDistinct = $rowCount->getPart(Sql\Select::DISTINCT);

/**
* If there is more than one column AND it's a DISTINCT query, more
* than one group, or if the query has a HAVING clause, then take
* the original query and use it as a subquery os the COUNT query.
*/
if (($isDistinct && count($columnParts) > 1) || count($groupParts) > 1 || !empty($havingParts)) {
$rowCount = $db->select()->from($this->_select);
} else if ($isDistinct) {
$part = $columnParts[0];

if ($part[1] !== Sql\Select::SQL_WILDCARD && !($part[1] instanceof Sql\ExpressionInterface)) {
$column = $db->quoteIdentifier($part[1], true);

if (!empty($part[0])) {
$column = $db->quoteIdentifier($part[0], true) . '.' . $column;
}

$groupPart = $column;
}
} else if (!empty($groupParts) && $groupParts[0] !== Sql\Select::SQL_WILDCARD &&
!($groupParts[0] instanceof Sql\ExpressionInterface)
) {
$groupPart = $db->quoteIdentifier($groupParts[0], true);
}

/**
* If the original query had a GROUP BY or a DISTINCT part and only
* one column was specified, create a COUNT(DISTINCT ) query instead
* of a regular COUNT query.
*/
if (!empty($groupPart)) {
$countPart = 'COUNT(DISTINCT ' . $groupPart . ') AS ';
}

/**
* Create the COUNT part of the query
*/
$expression = new Sql\Expression($countPart . $countColumn);

$rowCount->reset(Sql\Select::COLUMNS)
->reset(Sql\Select::ORDER)
->reset(Sql\Select::LIMIT_OFFSET)
->reset(Sql\Select::GROUP)
->reset(Sql\Select::DISTINCT)
->reset(Sql\Select::HAVING)
->columns($expression);
}
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$row = $result->current();

$this->_countSelect = $rowCount;
$this->rowCount = $row['c'];

return $rowCount;
return $this->rowCount;
}
}
34 changes: 0 additions & 34 deletions src/Adapter/DbTableSelect.php

This file was deleted.

2 changes: 0 additions & 2 deletions src/Adapter/Exception/ExceptionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* @category Zend
* @package Zend_Paginator
* @subpackage Adapter
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface ExceptionInterface extends Exception
{}
4 changes: 1 addition & 3 deletions src/Adapter/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
* @category Zend
* @package Zend\Paginator\Adapter
* @subpackage Exception
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class InvalidArgumentException extends Exception\InvalidArgumentException implements
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{}
Loading

0 comments on commit 8a3b848

Please sign in to comment.