Skip to content

Commit

Permalink
Fix yiisoft#20239: fix yii\data\ActiveDataProvider to avoid unexpec…
Browse files Browse the repository at this point in the history
…ted pagination results with UNION queries
  • Loading branch information
Izumi-kun committed Jan 15, 2025
1 parent b0b7832 commit 0e5219a
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 73 deletions.
130 changes: 65 additions & 65 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Yii Framework 2 Change Log
- Bug #20300: Clear stat cache in `FileCache::setValue()` (rob006)
- Enh #20306: Add new `yii\helpers\ArrayHelper::flatten()` method (xcopy)
- Bug #20308: Allow CompositeAuth auth methods to use their own user if defined (mtangoo)
- Bug #20239: Fix `yii\data\ActiveDataProvider` to avoid unexpected pagination results with UNION queries (Izumi-kun)

2.0.51 July 18, 2024
--------------------
Expand Down
39 changes: 31 additions & 8 deletions framework/data/ActiveDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use yii\base\Model;
use yii\db\ActiveQueryInterface;
use yii\db\Connection;
use yii\db\Query;
use yii\db\QueryInterface;
use yii\di\Instance;

Expand Down Expand Up @@ -93,14 +94,40 @@ public function init()
}

/**
* {@inheritdoc}
* Creates a wrapper of [[query]] that allows adding limit and order.
* @return QueryInterface
* @throws InvalidConfigException
*/
protected function prepareModels()
protected function createQueryWrapper(): 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.');
}
$query = clone $this->query;
$wrapper = clone $this->query;
if ($wrapper instanceof Query && !empty($wrapper->union)) {
$wrapper->where = [];
$wrapper->limit = null;
$wrapper->offset = null;
$wrapper->orderBy = [];
$wrapper->selectOption = null;
$wrapper->distinct = false;
$wrapper->groupBy = [];
$wrapper->join = [];
$wrapper->having = [];
$wrapper->union = [];
$wrapper->params = [];
$wrapper->withQueries = [];
$wrapper->select('*')->from(['q' => $this->query]);
}
return $wrapper;
}

/**
* {@inheritdoc}
*/
protected function prepareModels()
{
$query = $this->createQueryWrapper();
if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount();
if ($pagination->totalCount === 0) {
Expand Down Expand Up @@ -161,11 +188,7 @@ protected function prepareKeys($models)
*/
protected function prepareTotalCount()
{
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.');
}
$query = clone $this->query;
return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db);
return (int) $this->createQueryWrapper()->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db);
}

/**
Expand Down
Loading

0 comments on commit 0e5219a

Please sign in to comment.