Skip to content

Commit 1d391b6

Browse files
authored
Unify CRUD page titles and add datagrid drag-and-drop reordering (#4672)
2 parents a5fd64c + faca4bb commit 1d391b6

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

src/Component/Grid/Grid.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class Grid
6767

6868
protected ?string $orderingEntityClass = null;
6969

70+
protected ?string $dragAndDropOrderSourceColumnName = null;
71+
7072
protected PaginationResult $paginationResults;
7173

7274
/**
@@ -461,7 +463,7 @@ public function getGridParameters(array|string|null $removeParameters = []): arr
461463
}
462464
}
463465

464-
if ($this->getOrderSourceColumnName() !== null) {
466+
if (!$this->isDragAndDrop() && $this->getOrderSourceColumnName() !== null) {
465467
$gridParameters['order'] = $this->getOrderSourceColumnNameWithDirection();
466468
}
467469

@@ -512,8 +514,8 @@ protected function loadRows(): void
512514
$orderDirection = $this->orderDirection;
513515

514516
if ($this->isDragAndDrop()) {
515-
$orderSourceColumnName = null;
516-
$orderDirection = DataSourceInterface::ORDER_DESC;
517+
$orderSourceColumnName = $this->dragAndDropOrderSourceColumnName;
518+
$orderDirection = DataSourceInterface::ORDER_ASC;
517519
}
518520

519521
$this->paginationResults = $this->dataSource->getPaginatedRows(
@@ -567,9 +569,15 @@ public function getValueFromRowBySourceColumnName(array $row, string $sourceColu
567569
return $row[$sourceColumnName];
568570
}
569571

570-
public function enableDragAndDrop(string $entityClass): void
572+
/**
573+
* When drag-and-drop is enabled the listing is always ordered by $orderSourceColumnName ascending,
574+
* regardless of any ordering coming from the request, so the persisted positions are never mixed up.
575+
* Pass null when the ordering is already baked into the data source query builder (legacy grids).
576+
*/
577+
public function enableDragAndDrop(string $entityClass, ?string $orderSourceColumnName = null): void
571578
{
572579
$this->orderingEntityClass = $entityClass;
580+
$this->dragAndDropOrderSourceColumnName = $orderSourceColumnName;
573581
}
574582

575583
public function enableMultipleDragAndDrop(): void

tests/Unit/Component/Grid/GridTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,47 @@ public function testEnableDragAndDrop(): void
337337
$this->assertTrue($grid->isDragAndDrop());
338338
}
339339

340+
public function testDragAndDropIgnoresRequestOrderToPreventOrderByInjection(): void
341+
{
342+
$getParameters = [
343+
Grid::GET_PARAMETER => [
344+
'gridId' => [
345+
'order' => 'maliciousColumn',
346+
],
347+
],
348+
];
349+
350+
$request = new Request($getParameters);
351+
$requestStack = new RequestStack();
352+
$requestStack->push($request);
353+
354+
$twigStub = $this->createStub(Environment::class);
355+
$routerStub = $this->createStub(Router::class);
356+
$routeCsrfProtectorStub = $this->createStub(RouteCsrfProtector::class);
357+
$dataSourceMock = $this->getMockBuilder(DataSourceInterface::class)->getMock();
358+
$dataSourceMock->expects($this->once())->method('getPaginatedRows')
359+
->with(null, 1, 'position', DataSourceInterface::ORDER_ASC)
360+
->willReturn(new PaginationResult(1, 1, 0, []));
361+
$accessCheckerStub = $this->createStub(AccessCheckerInterface::class);
362+
$accessCheckerStub
363+
->method('canEdit')
364+
->willReturn(true);
365+
366+
$grid = new Grid(
367+
'gridId',
368+
SystemRole::ALL,
369+
$dataSourceMock,
370+
$requestStack,
371+
$routerStub,
372+
$routeCsrfProtectorStub,
373+
$twigStub,
374+
$accessCheckerStub,
375+
);
376+
377+
$grid->enableDragAndDrop('Path\To\Entity\Class', 'position');
378+
$grid->createView();
379+
}
380+
340381
public function testReorderColumns(): void
341382
{
342383
$request = new Request();

0 commit comments

Comments
 (0)