Prechádzať zdrojové kódy

ZF-7045: Refactor building of the count query into its own method in the DbSelect adapter

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@16146 44c647ce-9c0f-0410-b52a-842ac1e357ba
norm2782 16 rokov pred
rodič
commit
301e73c938

+ 71 - 46
library/Zend/Paginator/Adapter/DbSelect.php

@@ -50,6 +50,13 @@ class Zend_Paginator_Adapter_DbSelect implements Zend_Paginator_Adapter_Interfac
     const ROW_COUNT_COLUMN = 'zend_paginator_row_count';
 
     /**
+     * The COUNT query
+     *
+     * @var Zend_Db_Select
+     */
+    protected $_countSelect = null;
+
+    /**
      * Database query
      *
      * @var Zend_Db_Select
@@ -150,71 +157,89 @@ class Zend_Paginator_Adapter_DbSelect implements Zend_Paginator_Adapter_Interfac
     public function count()
     {
         if ($this->_rowCount === null) {
-            $rowCount = clone $this->_select;
-            $db = $rowCount->getAdapter();
+            $this->setRowCount(
+                $this->getCountSelect()
+            );
+        }
 
-            $countColumn = $db->quoteIdentifier($db->foldCase(self::ROW_COUNT_COLUMN));
+        return $this->_rowCount;
+    }
 
-            if ($rowCount->getPart(Zend_Db_Select::UNION) != array()) {
-                $expression = new Zend_Db_Expr('COUNT(*) AS ' . $countColumn);
+    /**
+     * Get the COUNT select object for the provided query
+     *
+     * @return Zend_Db_Select
+     */
+    public function getCountSelect()
+    {
+        if ($this->_countSelect !== null) {
+            return $this->_countSelect;
+        }
 
-                $rowCount = $db->select()->from($rowCount, $expression);
-            } else {
-                /**
-                 * The DISTINCT and GROUP BY queries only work when selecting one column.
-                 * The question is whether any RDBMS supports DISTINCT for multiple columns, without workarounds.
-                 */
-                if (true === $rowCount->getPart(Zend_Db_Select::DISTINCT)) {
-                    $columnParts = $rowCount->getPart(Zend_Db_Select::COLUMNS);
+        $rowCount = clone $this->_select;
+        $db = $rowCount->getAdapter();
 
-                    $columns = array();
+        $countColumn = $db->quoteIdentifier($db->foldCase(self::ROW_COUNT_COLUMN));
 
-                    foreach ($columnParts as $part) {
-                        if ($part[1] == Zend_Db_Select::SQL_WILDCARD || $part[1] instanceof Zend_Db_Expr) {
-                            $columns[] = $part[1];
-                        } else {
-                            $column = $db->quoteIdentifier($part[1], true);
+        if ($rowCount->getPart(Zend_Db_Select::UNION) != array()) {
+            $expression = new Zend_Db_Expr('COUNT(*) AS ' . $countColumn);
 
-                            if (!empty($part[0])) {
-                                $column = $db->quoteIdentifier($part[0], true) . '.' . $column;
-                            }
+            $rowCount = $db->select()->from($rowCount, $expression);
+        } else {
+            /**
+             * The DISTINCT and GROUP BY queries only work when selecting one column.
+             * The question is whether any RDBMS supports DISTINCT for multiple columns, without workarounds.
+             */
+            if (true === $rowCount->getPart(Zend_Db_Select::DISTINCT)) {
+                $columnParts = $rowCount->getPart(Zend_Db_Select::COLUMNS);
 
-                            $columns[] = $column;
-                        }
-                    }
+                $columns = array();
 
-                    if (count($columns) == 1 && $columns[0] == Zend_Db_Select::SQL_WILDCARD) {
-                        $groupPart = null;
+                foreach ($columnParts as $part) {
+                    if ($part[1] == Zend_Db_Select::SQL_WILDCARD || $part[1] instanceof Zend_Db_Expr) {
+                        $columns[] = $part[1];
                     } else {
-                        $groupPart = implode(',', $columns);
-                    }
-                } else {
-                    $groupParts = $rowCount->getPart(Zend_Db_Select::GROUP);
+                        $column = $db->quoteIdentifier($part[1], true);
 
-                    foreach ($groupParts as &$part) {
-                        if (!($part == Zend_Db_Select::SQL_WILDCARD || $part instanceof Zend_Db_Expr)) {
-                            $part = $db->quoteIdentifier($part, true);
+                        if (!empty($part[0])) {
+                            $column = $db->quoteIdentifier($part[0], true) . '.' . $column;
                         }
+
+                        $columns[] = $column;
                     }
+                }
 
-                    $groupPart = implode(',', $groupParts);
+                if (count($columns) == 1 && $columns[0] == Zend_Db_Select::SQL_WILDCARD) {
+                    $groupPart = null;
+                } else {
+                    $groupPart = implode(',', $columns);
                 }
+            } else {
+                $groupParts = $rowCount->getPart(Zend_Db_Select::GROUP);
 
-                $countPart  = empty($groupPart) ? 'COUNT(*)' : 'COUNT(DISTINCT ' . $groupPart . ')';
-                $expression = new Zend_Db_Expr($countPart . ' AS ' . $countColumn);
+                foreach ($groupParts as &$part) {
+                    if (!($part == Zend_Db_Select::SQL_WILDCARD || $part instanceof Zend_Db_Expr)) {
+                        $part = $db->quoteIdentifier($part, true);
+                    }
+                }
 
-                $rowCount->__toString(); // Workaround for ZF-3719 and related
-                $rowCount->reset(Zend_Db_Select::COLUMNS)
-                         ->reset(Zend_Db_Select::ORDER)
-                         ->reset(Zend_Db_Select::LIMIT_OFFSET)
-                         ->reset(Zend_Db_Select::GROUP)
-                         ->reset(Zend_Db_Select::DISTINCT)
-                         ->columns($expression);
+                $groupPart = implode(',', $groupParts);
             }
 
-            $this->setRowCount($rowCount);
+            $countPart  = empty($groupPart) ? 'COUNT(*)' : 'COUNT(DISTINCT ' . $groupPart . ')';
+            $expression = new Zend_Db_Expr($countPart . ' AS ' . $countColumn);
+
+            $rowCount->__toString(); // Workaround for ZF-3719 and related
+            $rowCount->reset(Zend_Db_Select::COLUMNS)
+                     ->reset(Zend_Db_Select::ORDER)
+                     ->reset(Zend_Db_Select::LIMIT_OFFSET)
+                     ->reset(Zend_Db_Select::GROUP)
+                     ->reset(Zend_Db_Select::DISTINCT)
+                     ->columns($expression);
         }
 
-        return $this->_rowCount;
+        $this->_countSelect = $rowCount;
+
+        return $rowCount;
     }
 }

+ 20 - 1
tests/Zend/Paginator/Adapter/DbSelectTest.php

@@ -341,6 +341,9 @@ class Zend_Paginator_Adapter_DbSelectTest extends PHPUnit_Framework_TestCase
         }
     }
 
+    /**
+     * @group ZF-5956
+     */
     public function testUnionSelect()
     {
         $union = $this->_db->select()->union(array(
@@ -348,11 +351,27 @@ class Zend_Paginator_Adapter_DbSelectTest extends PHPUnit_Framework_TestCase
             $this->_db->select()->from('test')->where('number > 250')
         ));
 
-        //$this->_db->select()->from($union, 'count(*)')
         $adapter = new Zend_Paginator_Adapter_DbSelect($union);
         $expected = 500;
         $actual = $adapter->count();
 
         $this->assertEquals($expected, $actual);
     }
+
+    /**
+     * @group ZF-7045
+     */
+    public function testGetCountSelect()
+    {
+        $union = $this->_db->select()->union(array(
+            $this->_db->select()->from('test')->where('number <= 250'),
+            $this->_db->select()->from('test')->where('number > 250')
+        ));
+
+        $adapter = new Zend_Paginator_Adapter_DbSelect($union);
+
+        $expected = 'SELECT COUNT(*) AS "zend_paginator_row_count" FROM (SELECT "test".* FROM "test" WHERE (number <= 250) UNION SELECT "test".* FROM "test" WHERE (number > 250)) AS "t"';
+
+        $this->assertEquals($expected, $adapter->getCountSelect()->__toString());
+    }
 }