Yii2: Wrong DataProvider->totalCount

Created on 1 Feb 2019  路  11Comments  路  Source: yiisoft/yii2

Wrong DataProvider->totalCount

What steps will reproduce the problem?

$query = MyModel::find();
$dataProvider = new ActiveDataProvider(['query' => $query);
$dataProvider->pagination->pageSize = 30;
//    Now $dataProvider->totalCount is set because of BaseDataProvider::getPagination()
$query->andFilterWhere(['number' => $this->number]);
//    From now on totalCount is NOT updated to consider this condition and any other conditions added before feeding it to a GridView and rendering.

What is the expected result?

totalCount should be set only when DataProvider gets to be used to fetch and render data.
Up to version 12.0.15 DataProvider pagination could be invoked and set before setting all its query conditions and afterwards totalCount was calculated correctly as expected.

What do you get instead?

DataProvider totalCount is wrong - total number of rows in the table!! - doesn't care about query conditions added after invoking $dataProvider->pagination.

Additional info

Related issue: https://github.com/yiisoft/yii2/issues/16891

| Q | A
| ---------------- | ---
| Yii version | 2.0.16
| PHP version | 7.*
| Operating system |Windows/Linux

important bug

Most helpful comment

Looks like we need to revert https://github.com/yiisoft/yii2/commit/e1623868f9e95769074312f8582c1709cfcb52a8#diff-3a9563dfdfd2448d1b7edfad3ec14522

All 11 comments

What is the AR storage you are using?

Is here any reason you don't use config to set pageSize value?

I think we should block any changes in query or pagination after ActiveDataProvider was initialized. Otherwise we have to recalculate it parameters every time. Or introduce an events system, which to be able to catch such changes and adjust only needed parameters.

What is the AR storage you are using?

MySQL

Is here any reason you don't use config to set pageSize value?

Supposing you refer to app config, the reason is pageSize is not fixed but different for different DataProviders.

I think we should block any changes in query or pagination after ActiveDataProvider was initialized. Otherwise we have to recalculate it parameters every time. Or introduce an events system, which to be able to catch such changes and adjust only needed parameters.

...or delay calculating and setting totalCount until it is really needed. Why not?

Supposing you refer to app config, the reason is pageSize is not fixed but different for different DataProviders.

No proplem:

$dataProvider = new ActiveDataProvider([
     'query' => $query,
     'pagination' => [
            'pageSize' => $YOUR_DYNAMIC_VALUE_HERE,
     ],
);

...or delay calculating and setting totalCount until it is really needed. Why not?

Just let the framework take care about this. It makes sense but in current case you can get exactly what you want by making up right config before ActiveDataProvider initialization.

Discussed the case in private messages with @GHopperMSK. He has a good solution for it.

@GHopperMSK 's solution works, of course :-), and I'm refactoring this way.
It's refreshing to find myself still learning basing stuff after 3 yers of using Yii2. Thanks!
But if you find a (easy) way to have totalCount reflect query at final stage (get data and render) it would be great.

Unfortunately, my solution isn't good at all. Here are a few cases:

  1. You can't anymore set totalCount by usual way:
$provider = new ActiveDataProvider([
    'query' => Order::find()->orderBy('id'),
    'totalCount' => 10, // it makes no sense anymore
    'pagination' => [
        'pageSize' => 1,
        // now 'totalCount' must be declared here
    ],
]);
  1. Strange behavior in some cases:
$provider = new ActiveDataProvider([
    'db' => $this->getConnection(),
    'query' => $query->from('order')->orderBy('id'),
]);
$perPage = $provider->getPagination()->getPageCount(); // null
// Pagination: getPageCount() => getPageSize() => setPageSize() => totalCount = null;
  1. Absurd cases:

Next code works fine:

$provider = new ActiveDataProvider([
    'query' => Order::find()->orderBy('id'),
    'pagination' => [
        'pageSize' => 1,
        'totalCount' => 100,
    ],
]);

But if we just swap two lines, it will break:

$provider = new ActiveDataProvider([
    'query' => Order::find()->orderBy('id'),
    'pagination' => [
        'totalCount' => 100,
        'pageSize' => 1,
    ],
]);
// the same reason as in 2

Looks like we need to revert https://github.com/yiisoft/yii2/commit/e1623868f9e95769074312f8582c1709cfcb52a8#diff-3a9563dfdfd2448d1b7edfad3ec14522

This is limiting us to move to 2.0.16 :( How can I help to fix this one?

Was this page helpful?
0 / 5 - 0 ratings