-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #20239: fix yii\data\ActiveDataProvider
to avoid unexpected pagination results with UNION queries
#20311
base: master
Are you sure you want to change the base?
Conversation
…ted pagination results with UNION queries
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #20311 +/- ##
============================================
+ Coverage 64.85% 64.86% +0.01%
- Complexity 11435 11437 +2
============================================
Files 431 431
Lines 37193 37203 +10
============================================
+ Hits 24120 24131 +11
+ Misses 13073 13072 -1 ☔ View full report in Codecov by Sentry. |
Let's exclude |
@rob006 would you please take a look? |
{ | ||
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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we return $this->query
if the condition isn't met right away?
if (!$wrapper instanceof Query || empty($wrapper->union)) {
return $this->query;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather return $wrapper;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to keep the original logic (not reusing the original query):
yii2/framework/data/ActiveDataProvider.php
Lines 98 to 104 in b0b7832
protected function prepareModels() | |
{ | |
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; | |
if (($pagination = $this->getPagination()) !== false) { |
yii2/framework/data/ActiveDataProvider.php
Lines 162 to 168 in b0b7832
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); |
Should I change it?
$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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There might be more properties that needs to be reset. For example ActiveQuery
has on
and joinWith
(and sql
?) properties, that may leak to wrapper. Developer may extend these classes and create own properties with the same problem. Query
needs some kind of reset()
method, that would be responsible for resting query state.
Or we cold use new Query()
, similar to ActiveQuery::queryScalar()
:
yii2/framework/db/ActiveQuery.php
Line 355 in b0b7832
$command = (new Query())->select([$selectExpression]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a new Query()
will break prepareModels()
itself if query
is an ActiveQuery
and the expected return value of ActiveQuery::all()
is array of objects rather then an array of arrays. I'll think about the solution a little more.
I don't really like the implementation, it looks like a workaround. The design of the query build doesn't allow for a more proper solution without breaking BC. Or am I missing something? |
Moved to next milestone for now. |
@Izumi-kun any idea about better solution? |
No any new solutions without BC. |
Related PR: #20246