Skip to content

Commit 15713e0

Browse files
authored
Fix: ColumnsSummary shows incorrect totals after inline edit (#1254)
1 parent c9835f1 commit 15713e0

2 files changed

Lines changed: 126 additions & 14 deletions

File tree

src/Datagrid.php

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -370,16 +370,35 @@ public function render(): void
370370
*/
371371
$rows = [];
372372

373-
$items = $this->redrawItem !== [] ? $this->dataModel->filterRow($this->redrawItem) : $this->dataModel->filterData(
374-
$this->getPaginator(),
375-
$this->createSorting($this->sort, $this->sortCallback),
376-
$this->assembleFilters()
377-
);
373+
$items = $this->redrawItem !== [] && !($this->columnsSummary instanceof ColumnsSummary)
374+
? $this->dataModel->filterRow($this->redrawItem)
375+
: $this->dataModel->filterData(
376+
$this->getPaginator(),
377+
$this->createSorting($this->sort, $this->sortCallback),
378+
$this->assembleFilters()
379+
);
378380

379381
$hasGroupActionOnRows = false;
380382

381383
foreach ($items as $item) {
382-
$rows[] = $row = new Row($this, $item, $this->getPrimaryKey());
384+
$row = new Row($this, $item, $this->getPrimaryKey());
385+
386+
/**
387+
* When iterating all items (for ColumnsSummary), skip rows that are not the redraw target.
388+
* The Row object is still created above so ColumnsSummary::add() is called for every row.
389+
*/
390+
if ($this->redrawItem !== []) {
391+
$redrawKey = array_key_first($this->redrawItem);
392+
393+
if ((string) $row->getValue($redrawKey) !== (string) $this->redrawItem[$redrawKey]) {
394+
continue;
395+
}
396+
397+
$this->getPresenterInstance()->payload->_datagrid_redrawItem_class = $row->getControlClass();
398+
$this->getPresenterInstance()->payload->_datagrid_redrawItem_id = $row->getId();
399+
}
400+
401+
$rows[] = $row;
383402

384403
if (!$hasGroupActionOnRows && $row->hasGroupAction()) {
385404
$hasGroupActionOnRows = true;
@@ -388,14 +407,6 @@ public function render(): void
388407
if ($this->rowCallback !== null) {
389408
($this->rowCallback)($item, $row->getControl());
390409
}
391-
392-
/**
393-
* Walkaround for item snippet - snippet is the <tr> element and its class has to be also updated
394-
*/
395-
if ($this->redrawItem !== []) {
396-
$this->getPresenterInstance()->payload->_datagrid_redrawItem_class = $row->getControlClass();
397-
$this->getPresenterInstance()->payload->_datagrid_redrawItem_id = $row->getId();
398-
}
399410
}
400411

401412
if ($hasGroupActionOnRows) {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Contributte\Datagrid\Tests\Cases;
4+
5+
require __DIR__ . '/../bootstrap.php';
6+
require __DIR__ . '/../Files/TestingDatagridFactory.php';
7+
8+
use Contributte\Datagrid\Datagrid;
9+
use Contributte\Datagrid\Row;
10+
use Contributte\Datagrid\Tests\Files\TestingDatagridFactory;
11+
use Tester\Assert;
12+
use Tester\TestCase;
13+
14+
final class ColumnsSummaryTest extends TestCase
15+
{
16+
17+
private Datagrid $grid;
18+
19+
private array $data = [
20+
['id' => 1, 'amount' => 100],
21+
['id' => 2, 'amount' => 200],
22+
['id' => 3, 'amount' => 300],
23+
];
24+
25+
public function setUp(): void
26+
{
27+
$factory = new TestingDatagridFactory();
28+
$this->grid = $factory->createTestingDatagrid();
29+
$this->grid->addColumnNumber('amount', 'Amount');
30+
$this->grid->setDataSource($this->data);
31+
}
32+
33+
public function testSummaryAccumulatesAllRows(): void
34+
{
35+
$summary = $this->grid->setColumnsSummary(['amount']);
36+
37+
foreach ($this->data as $item) {
38+
new Row($this->grid, $item, 'id');
39+
}
40+
41+
Assert::same('600', $summary->render('amount'));
42+
}
43+
44+
/**
45+
* Demonstrates the bug that existed before the fix:
46+
* when only the redrawn row was processed, ColumnsSummary showed the wrong (partial) total.
47+
*/
48+
public function testSummaryWithSingleRowShowsPartialTotal(): void
49+
{
50+
$summary = $this->grid->setColumnsSummary(['amount']);
51+
52+
// Only the redrawn row (id=2, amount=200) is processed — as the bug did
53+
new Row($this->grid, ['id' => 2, 'amount' => 200], 'id');
54+
55+
Assert::same('200', $summary->render('amount'));
56+
}
57+
58+
/**
59+
* Verifies that when redrawItem is set alongside columnsSummary,
60+
* Datagrid routes to filterData (all rows) — not filterRow (single row).
61+
*
62+
* The condition in Datagrid::render():
63+
* $redrawItem !== [] && !($columnsSummary instanceof ColumnsSummary)
64+
* must evaluate to FALSE so that filterData is used and all rows are iterated,
65+
* ensuring ColumnsSummary receives all values.
66+
*/
67+
public function testFilterDataUsedWhenColumnsSummaryAndRedrawItemSet(): void
68+
{
69+
$this->grid->setColumnsSummary(['amount']);
70+
71+
Assert::true($this->grid->hasColumnsSummary());
72+
73+
$reflectionRedrawItem = new \ReflectionProperty(Datagrid::class, 'redrawItem');
74+
$reflectionRedrawItem->setValue($this->grid, ['id' => 2]);
75+
76+
$redrawItem = $reflectionRedrawItem->getValue($this->grid);
77+
78+
Assert::false($redrawItem !== [] && !$this->grid->hasColumnsSummary());
79+
}
80+
81+
/**
82+
* Without columnsSummary, redrawItem causes filterRow to be used (expected behaviour).
83+
*/
84+
public function testFilterRowUsedWhenNoColumnsSummaryAndRedrawItemSet(): void
85+
{
86+
Assert::false($this->grid->hasColumnsSummary());
87+
88+
$reflRedrawItem = new \ReflectionProperty(Datagrid::class, 'redrawItem');
89+
$reflRedrawItem->setValue($this->grid, ['id' => 2]);
90+
91+
$redrawItem = $reflRedrawItem->getValue($this->grid);
92+
93+
$wouldUseFilterRow = $redrawItem !== [] && !$this->grid->hasColumnsSummary();
94+
95+
Assert::true($wouldUseFilterRow);
96+
}
97+
98+
}
99+
100+
101+
(new ColumnsSummaryTest())->run();

0 commit comments

Comments
 (0)