mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 18:47:33 +08:00 
			
		
		
		
	Fix #20175: Fix bad result for pagination when used with GridView
This commit is contained in:
		| @ -8,7 +8,6 @@ | |||||||
| namespace yii\build\controllers; | namespace yii\build\controllers; | ||||||
|  |  | ||||||
| use DirectoryIterator; | use DirectoryIterator; | ||||||
| use Yii; |  | ||||||
| use yii\console\Controller; | use yii\console\Controller; | ||||||
| use yii\helpers\Html; | use yii\helpers\Html; | ||||||
|  |  | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ Yii Framework 2 Change Log | |||||||
| 2.0.51 under development | 2.0.51 under development | ||||||
| ------------------------ | ------------------------ | ||||||
|  |  | ||||||
| - no changes in this release. | - Bug #20175: Fix bad result for pagination when used with GridView (@lav45) | ||||||
|  |  | ||||||
|  |  | ||||||
| 2.0.50 May 30, 2024 | 2.0.50 May 30, 2024 | ||||||
|  | |||||||
| @ -7,8 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\base; | namespace yii\base; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ErrorException represents a PHP error. |  * ErrorException represents a PHP error. | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\base; | namespace yii\base; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\helpers\StringHelper; | use yii\helpers\StringHelper; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -110,7 +110,6 @@ class ActiveDataProvider extends BaseDataProvider | |||||||
|         if (($sort = $this->getSort()) !== false) { |         if (($sort = $this->getSort()) !== false) { | ||||||
|             $query->addOrderBy($sort->getOrders()); |             $query->addOrderBy($sort->getOrders()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $query->all($this->db); |         return $query->all($this->db); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -128,7 +127,6 @@ class ActiveDataProvider extends BaseDataProvider | |||||||
|                     $keys[] = call_user_func($this->key, $model); |                     $keys[] = call_user_func($this->key, $model); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return $keys; |             return $keys; | ||||||
|         } elseif ($this->query instanceof ActiveQueryInterface) { |         } elseif ($this->query instanceof ActiveQueryInterface) { | ||||||
|             /* @var $class \yii\db\ActiveRecordInterface */ |             /* @var $class \yii\db\ActiveRecordInterface */ | ||||||
| @ -148,13 +146,13 @@ class ActiveDataProvider extends BaseDataProvider | |||||||
|                     $keys[] = $kk; |                     $keys[] = $kk; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return $keys; |             return $keys; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return array_keys($models); |         return array_keys($models); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private $_totalCount = []; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * {@inheritdoc} |      * {@inheritdoc} | ||||||
|      */ |      */ | ||||||
| @ -163,8 +161,13 @@ class ActiveDataProvider extends BaseDataProvider | |||||||
|         if (!$this->query instanceof QueryInterface) { |         if (!$this->query instanceof QueryInterface) { | ||||||
|             throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); |             throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); | ||||||
|         } |         } | ||||||
|         $query = clone $this->query; |         $query = (clone $this->query)->limit(-1)->offset(-1)->orderBy([]); | ||||||
|         return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db); |         $key = md5((string)$query); | ||||||
|  |  | ||||||
|  |         if (!array_key_exists($key, $this->_totalCount)) { | ||||||
|  |             $this->_totalCount[$key] = (int)$query->count('*', $this->db); | ||||||
|  |         } | ||||||
|  |         return $this->_totalCount[$key]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -196,7 +199,6 @@ class ActiveDataProvider extends BaseDataProvider | |||||||
|         if (is_object($this->query)) { |         if (is_object($this->query)) { | ||||||
|             $this->query = clone $this->query; |             $this->query = clone $this->query; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         parent::__clone(); |         parent::__clone(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -167,10 +167,10 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa | |||||||
|         if ($this->_pagination === false) { |         if ($this->_pagination === false) { | ||||||
|             return $this->getCount(); |             return $this->getCount(); | ||||||
|         } |         } | ||||||
|         if ($this->_totalCount === null) { |         if ($this->_totalCount !== null) { | ||||||
|             $this->_totalCount = $this->prepareTotalCount(); |             return (int)$this->_totalCount; | ||||||
|         } |         } | ||||||
|         return $this->_totalCount; |         return $this->prepareTotalCount(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -219,7 +219,9 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa | |||||||
|             $value = Yii::createObject(array_merge($config, $value)); |             $value = Yii::createObject(array_merge($config, $value)); | ||||||
|         } |         } | ||||||
|         if ($value instanceof Pagination) { |         if ($value instanceof Pagination) { | ||||||
|             $value->totalCount = $this->getTotalCount(); |             $value->setTotalCount(function () { | ||||||
|  |                 return $this->getTotalCount(); | ||||||
|  |             }); | ||||||
|             $this->_pagination = $value; |             $this->_pagination = $value; | ||||||
|         } elseif ($value === false) { |         } elseif ($value === false) { | ||||||
|             $this->_pagination = false; |             $this->_pagination = false; | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
|  |  | ||||||
| namespace yii\data; | namespace yii\data; | ||||||
|  |  | ||||||
|  | use Closure; | ||||||
| use Yii; | use Yii; | ||||||
| use yii\base\BaseObject; | use yii\base\BaseObject; | ||||||
| use yii\web\Link; | use yii\web\Link; | ||||||
| @ -69,6 +70,7 @@ use yii\web\Request; | |||||||
|  * @property-read int $pageCount Number of pages. |  * @property-read int $pageCount Number of pages. | ||||||
|  * @property int $pageSize The number of items per page. If it is less than 1, it means the page size is |  * @property int $pageSize The number of items per page. If it is less than 1, it means the page size is | ||||||
|  * infinite, and thus a single page contains all items. |  * infinite, and thus a single page contains all items. | ||||||
|  |  * @property int $totalCount total number of items. | ||||||
|  * |  * | ||||||
|  * @author Qiang Xue <qiang.xue@gmail.com> |  * @author Qiang Xue <qiang.xue@gmail.com> | ||||||
|  * @since 2.0 |  * @since 2.0 | ||||||
| @ -123,10 +125,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|      * number validation. By doing so, [[page]] will return the value indexed by [[pageParam]] in [[params]]. |      * number validation. By doing so, [[page]] will return the value indexed by [[pageParam]] in [[params]]. | ||||||
|      */ |      */ | ||||||
|     public $validatePage = true; |     public $validatePage = true; | ||||||
|     /** |  | ||||||
|      * @var int total number of items. |  | ||||||
|      */ |  | ||||||
|     public $totalCount = 0; |  | ||||||
|     /** |     /** | ||||||
|      * @var int the default page size. This property will be returned by [[pageSize]] when page size |      * @var int the default page size. This property will be returned by [[pageSize]] when page size | ||||||
|      * cannot be determined by [[pageSizeParam]] from [[params]]. |      * cannot be determined by [[pageSizeParam]] from [[params]]. | ||||||
| @ -143,6 +141,10 @@ class Pagination extends BaseObject implements Linkable | |||||||
|      * If it is less than 1, it means the page size is infinite, and thus a single page contains all items. |      * If it is less than 1, it means the page size is infinite, and thus a single page contains all items. | ||||||
|      */ |      */ | ||||||
|     private $_pageSize; |     private $_pageSize; | ||||||
|  |     /** | ||||||
|  |      * @var Closure|int total number of items or closure returning it. | ||||||
|  |      */ | ||||||
|  |     private $_totalCount = 0; | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -151,13 +153,11 @@ class Pagination extends BaseObject implements Linkable | |||||||
|     public function getPageCount() |     public function getPageCount() | ||||||
|     { |     { | ||||||
|         $pageSize = $this->getPageSize(); |         $pageSize = $this->getPageSize(); | ||||||
|  |         $totalCount = $this->getTotalCount(); | ||||||
|         if ($pageSize < 1) { |         if ($pageSize < 1) { | ||||||
|             return $this->totalCount > 0 ? 1 : 0; |             return $totalCount > 0 ? 1 : 0; | ||||||
|         } |         } | ||||||
|  |         return (int) ((max($totalCount, 0) + $pageSize - 1) / $pageSize); | ||||||
|         $totalCount = $this->totalCount < 0 ? 0 : (int) $this->totalCount; |  | ||||||
|  |  | ||||||
|         return (int) (($totalCount + $pageSize - 1) / $pageSize); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private $_page; |     private $_page; | ||||||
| @ -173,7 +173,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|             $page = (int) $this->getQueryParam($this->pageParam, 1) - 1; |             $page = (int) $this->getQueryParam($this->pageParam, 1) - 1; | ||||||
|             $this->setPage($page, true); |             $this->setPage($page, true); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $this->_page; |         return $this->_page; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -221,7 +220,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|                 $this->setPageSize($pageSize, true); |                 $this->setPageSize($pageSize, true); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $this->_pageSize; |         return $this->_pageSize; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -264,7 +262,7 @@ class Pagination extends BaseObject implements Linkable | |||||||
|             $request = Yii::$app->getRequest(); |             $request = Yii::$app->getRequest(); | ||||||
|             $params = $request instanceof Request ? $request->getQueryParams() : []; |             $params = $request instanceof Request ? $request->getQueryParams() : []; | ||||||
|         } |         } | ||||||
|         if ($page > 0 || $page == 0 && $this->forcePageParam) { |         if ($page > 0 || ($page === 0 && $this->forcePageParam)) { | ||||||
|             $params[$this->pageParam] = $page + 1; |             $params[$this->pageParam] = $page + 1; | ||||||
|         } else { |         } else { | ||||||
|             unset($params[$this->pageParam]); |             unset($params[$this->pageParam]); | ||||||
| @ -282,7 +280,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|         if ($absolute) { |         if ($absolute) { | ||||||
|             return $urlManager->createAbsoluteUrl($params); |             return $urlManager->createAbsoluteUrl($params); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $urlManager->createUrl($params); |         return $urlManager->createUrl($params); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -293,7 +290,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|     public function getOffset() |     public function getOffset() | ||||||
|     { |     { | ||||||
|         $pageSize = $this->getPageSize(); |         $pageSize = $this->getPageSize(); | ||||||
|  |  | ||||||
|         return $pageSize < 1 ? 0 : $this->getPage() * $pageSize; |         return $pageSize < 1 ? 0 : $this->getPage() * $pageSize; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -305,7 +301,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|     public function getLimit() |     public function getLimit() | ||||||
|     { |     { | ||||||
|         $pageSize = $this->getPageSize(); |         $pageSize = $this->getPageSize(); | ||||||
|  |  | ||||||
|         return $pageSize < 1 ? -1 : $pageSize; |         return $pageSize < 1 ? -1 : $pageSize; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -331,7 +326,6 @@ class Pagination extends BaseObject implements Linkable | |||||||
|                 $links[self::LINK_NEXT] = $this->createUrl($currentPage + 1, null, $absolute); |                 $links[self::LINK_NEXT] = $this->createUrl($currentPage + 1, null, $absolute); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $links; |         return $links; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -348,7 +342,25 @@ class Pagination extends BaseObject implements Linkable | |||||||
|             $request = Yii::$app->getRequest(); |             $request = Yii::$app->getRequest(); | ||||||
|             $params = $request instanceof Request ? $request->getQueryParams() : []; |             $params = $request instanceof Request ? $request->getQueryParams() : []; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return isset($params[$name]) && is_scalar($params[$name]) ? $params[$name] : $defaultValue; |         return isset($params[$name]) && is_scalar($params[$name]) ? $params[$name] : $defaultValue; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return int total number of items. | ||||||
|  |      */ | ||||||
|  |     public function getTotalCount() | ||||||
|  |     { | ||||||
|  |         if (is_numeric($this->_totalCount)) { | ||||||
|  |             return (int)$this->_totalCount; | ||||||
|  |         } | ||||||
|  |         return (int)call_user_func($this->_totalCount); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param Closure|int $count | ||||||
|  |      */ | ||||||
|  |     public function setTotalCount($count) | ||||||
|  |     { | ||||||
|  |         $this->_totalCount = $count; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\data; | namespace yii\data; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\InvalidConfigException; | use yii\base\InvalidConfigException; | ||||||
| use yii\db\Connection; | use yii\db\Connection; | ||||||
| use yii\db\Expression; | use yii\db\Expression; | ||||||
| @ -150,10 +149,8 @@ class SqlDataProvider extends BaseDataProvider | |||||||
|                     $keys[] = call_user_func($this->key, $model); |                     $keys[] = call_user_func($this->key, $model); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return $keys; |             return $keys; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return array_keys($models); |         return array_keys($models); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\db; | namespace yii\db; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\BaseObject; | use yii\base\BaseObject; | ||||||
| use yii\helpers\StringHelper; | use yii\helpers\StringHelper; | ||||||
|  |  | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\i18n; | namespace yii\i18n; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\InvalidConfigException; | use yii\base\InvalidConfigException; | ||||||
| use yii\caching\CacheInterface; | use yii\caching\CacheInterface; | ||||||
| use yii\db\Connection; | use yii\db\Connection; | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\log; | namespace yii\log; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\InvalidConfigException; | use yii\base\InvalidConfigException; | ||||||
| use yii\db\Connection; | use yii\db\Connection; | ||||||
| use yii\db\Exception; | use yii\db\Exception; | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\log; | namespace yii\log; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\Component; | use yii\base\Component; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\log; | namespace yii\log; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\helpers\VarDumper; | use yii\helpers\VarDumper; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\rbac; | namespace yii\rbac; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\BaseObject; | use yii\base\BaseObject; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\rest; | namespace yii\rest; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\InvalidConfigException; | use yii\base\InvalidConfigException; | ||||||
| use yii\db\ActiveRecordInterface; | use yii\db\ActiveRecordInterface; | ||||||
| use yii\web\NotFoundHttpException; | use yii\web\NotFoundHttpException; | ||||||
|  | |||||||
| @ -7,8 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\rest; | namespace yii\rest; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ViewAction implements the API endpoint for returning the detailed information about a model. |  * ViewAction implements the API endpoint for returning the detailed information about a model. | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\web; | namespace yii\web; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\caching\CacheInterface; | use yii\caching\CacheInterface; | ||||||
| use yii\di\Instance; | use yii\di\Instance; | ||||||
|  |  | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
|  |  | ||||||
| namespace yii\web; | namespace yii\web; | ||||||
|  |  | ||||||
| use Yii; |  | ||||||
| use yii\base\BaseObject; | use yii\base\BaseObject; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -197,4 +197,23 @@ abstract class ActiveDataProviderTest extends DatabaseTestCase | |||||||
|  |  | ||||||
|         $this->assertEquals(0, $pagination->getPageCount()); |         $this->assertEquals(0, $pagination->getPageCount()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testTotalCountAfterSearch() | ||||||
|  |     { | ||||||
|  |         $query = Order::find(); | ||||||
|  |         $provider = new ActiveDataProvider([ | ||||||
|  |             'query' => $query, | ||||||
|  |             'pagination' => [ | ||||||
|  |                 'pageSize' => 2, | ||||||
|  |             ], | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $pagination = $provider->getPagination(); | ||||||
|  |         $this->assertEquals(2, $pagination->getPageCount()); | ||||||
|  |         $this->assertEquals(3, $pagination->getTotalCount()); | ||||||
|  |  | ||||||
|  |         $query->andWhere(['customer_id' => 2]); | ||||||
|  |         $this->assertEquals(1, $pagination->getPageCount()); | ||||||
|  |         $this->assertEquals(2, $pagination->getTotalCount()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Alex
					Alex