From 1f3c20c2c2490105d907ddce668fc488cb7bd92b Mon Sep 17 00:00:00 2001 From: daFish81 Date: Fri, 6 Mar 2026 13:42:36 +0100 Subject: [PATCH 1/3] build(deps): allow symfony 8 --- composer.json | 21 ++++++++++--------- tests/ReflectionTrait.php | 9 ++------ .../Filter/DoctrineOrmFilterHandlerTest.php | 14 +++++++++---- .../Orm/Fixtures/TestEntityManagerFactory.php | 4 ++++ 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/composer.json b/composer.json index 7ad9681f..2970177f 100755 --- a/composer.json +++ b/composer.json @@ -14,29 +14,30 @@ "license": "MIT", "require": { "php": "^8.1", - "symfony/framework-bundle": "^6.0|^7.0", - "symfony/translation": "^6.0|^7.0", - "symfony/form": "^6.0|^7.0", - "symfony/mime": "^6.0|^7.0", - "symfony/twig-bundle": "^6.0|^7.0", + "symfony/framework-bundle": "^6.0|^7.0|^8.0", + "symfony/translation": "^6.0|^7.0|^8.0", + "symfony/form": "^6.0|^7.0|^8.0", + "symfony/mime": "^6.0|^7.0|^8.0", + "symfony/twig-bundle": "^6.0|^7.0|^8.0", "twig/extra-bundle": "^3.6", "twig/intl-extra": "^3.6", - "symfony/validator": "^6.0|^7.0" + "symfony/validator": "^6.0|^7.0|^8.0" }, "require-dev": { "roave/security-advisories": "dev-latest", "friendsofphp/php-cs-fixer": "^3.49", "kubawerlos/php-cs-fixer-custom-fixers": "^3.11", "symfony/maker-bundle": "^1.48", - "symfony/security-core": "^6.2|^7.0", + "symfony/security-core": "^6.2|^7.0|^8.0", "phpoffice/phpspreadsheet": "^1.28", - "doctrine/orm": "^2.15", - "doctrine/doctrine-bundle": "^2.9", + "doctrine/orm": "^2.15|^3.0", + "doctrine/doctrine-bundle": "^2.9|^3.0", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^10.4", "dg/bypass-finals": "dev-master", "openspout/openspout": "^4.23", - "symfony/http-foundation": "^6.0|^7.0" + "symfony/http-foundation": "^6.0|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "autoload": { "psr-4": { diff --git a/tests/ReflectionTrait.php b/tests/ReflectionTrait.php index db452ce3..27f67053 100644 --- a/tests/ReflectionTrait.php +++ b/tests/ReflectionTrait.php @@ -8,16 +8,11 @@ trait ReflectionTrait { private function getPrivatePropertyValue(object $object, string $property): mixed { - $reflection = new \ReflectionProperty($object, $property); - $reflection->setAccessible(true); - - return $reflection->getValue($object); + return (new \ReflectionProperty($object, $property))->getValue($object); } private function setPrivatePropertyValue(object $object, string $property, mixed $value): void { - $reflection = new \ReflectionProperty($object, $property); - $reflection->setAccessible(true); - $reflection->setValue($object, $value); + (new \ReflectionProperty($object, $property))->setValue($object, $value); } } diff --git a/tests/Unit/Bridge/Doctrine/Orm/Filter/DoctrineOrmFilterHandlerTest.php b/tests/Unit/Bridge/Doctrine/Orm/Filter/DoctrineOrmFilterHandlerTest.php index f4cce4a4..7bc951f0 100644 --- a/tests/Unit/Bridge/Doctrine/Orm/Filter/DoctrineOrmFilterHandlerTest.php +++ b/tests/Unit/Bridge/Doctrine/Orm/Filter/DoctrineOrmFilterHandlerTest.php @@ -60,8 +60,10 @@ public function testItAppliesExpression(): void ($queryBuilder = $this->createQueryBuilderMock()) ->expects($this->once()) ->method('andWhere') - ->willReturnCallback(function (mixed $expression) { + ->willReturnCallback(function (mixed $expression) use (&$queryBuilder) { $this->assertEquals('expression', $expression); + + return $queryBuilder; }); $this->query->method('getQueryBuilder')->willReturn($queryBuilder); @@ -74,10 +76,12 @@ public function testItSetsParameterWithoutTypeSpecified(): void ($queryBuilder = $this->createQueryBuilderMock()) ->expects($this->once()) ->method('setParameter') - ->willReturnCallback(function ($name, $value, $type) { + ->willReturnCallback(function ($name, $value, $type) use (&$queryBuilder) { $this->assertEquals('foo', $name); $this->assertEquals('bar', $value); $this->assertNull($type); + + return $queryBuilder; }); $this->query->method('getQueryBuilder')->willReturn($queryBuilder); @@ -85,15 +89,17 @@ public function testItSetsParameterWithoutTypeSpecified(): void $this->createHandler(parameters: [new Parameter('foo', 'bar')])->handle($this->query, $this->data, $this->filter); } - public function testItSetsParameterWithTypeSpecified() + public function testItSetsParameterWithTypeSpecified(): void { ($queryBuilder = $this->createQueryBuilderMock()) ->expects($this->once()) ->method('setParameter') - ->willReturnCallback(function ($name, $value, $type) { + ->willReturnCallback(function ($name, $value, $type) use (&$queryBuilder) { $this->assertEquals('foo', $name); $this->assertEquals('bar', $value); $this->assertEquals('date_immutable', $type); + + return $queryBuilder; }); $this->query->method('getQueryBuilder')->willReturn($queryBuilder); diff --git a/tests/Unit/Bridge/Doctrine/Orm/Fixtures/TestEntityManagerFactory.php b/tests/Unit/Bridge/Doctrine/Orm/Fixtures/TestEntityManagerFactory.php index f5f612db..7112268e 100644 --- a/tests/Unit/Bridge/Doctrine/Orm/Fixtures/TestEntityManagerFactory.php +++ b/tests/Unit/Bridge/Doctrine/Orm/Fixtures/TestEntityManagerFactory.php @@ -21,6 +21,10 @@ public static function create(): EntityManagerInterface $config = ORMSetup::createAttributeMetadataConfiguration([], true); + if (PHP_VERSION_ID >= 80400 && method_exists($config, 'enableNativeLazyObjects')) { + $config->enableNativeLazyObjects(true); + } + $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true, From 13b234dbf4058e73f91e99c5ec42d4d2539698f5 Mon Sep 17 00:00:00 2001 From: daFish81 Date: Tue, 24 Mar 2026 12:01:34 +0100 Subject: [PATCH 2/3] fixup! build(deps): allow symfony 8 --- src/DataCollector/DataTableDataCollector.php | 4 +- src/Request/HttpFoundationRequestHandler.php | 19 +- .../DataTableDataCollectorTest.php | 528 ++++++++++++++++++ 3 files changed, 546 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/DataCollector/DataTableDataCollectorTest.php diff --git a/src/DataCollector/DataTableDataCollector.php b/src/DataCollector/DataTableDataCollector.php index 992ee3cd..60ef3ad3 100644 --- a/src/DataCollector/DataTableDataCollector.php +++ b/src/DataCollector/DataTableDataCollector.php @@ -36,11 +36,11 @@ public function __construct( } } - public function __sleep(): array + public function __serialize(): array { $this->data = $this->cloneVar($this->data)->withMaxDepth($this->maxDepth); - return parent::__sleep(); + return parent::__serialize(); } public static function getTemplate(): ?string diff --git a/src/Request/HttpFoundationRequestHandler.php b/src/Request/HttpFoundationRequestHandler.php index 29c9efbe..c0a78ead 100755 --- a/src/Request/HttpFoundationRequestHandler.php +++ b/src/Request/HttpFoundationRequestHandler.php @@ -48,7 +48,7 @@ private function filter(DataTableInterface $dataTable, Request $request): void $form = $dataTable->createFiltrationFormBuilder()->getForm(); - if ($data = $request->get($form->getName())) { + if ($data = $this->getRequestParameter($request, $form->getName())) { $form->submit($data); } @@ -105,7 +105,7 @@ private function personalize(DataTableInterface $dataTable, Request $request): v $form = $dataTable->createPersonalizationFormBuilder()->getForm(); - if ($data = $request->get($form->getName())) { + if ($data = $this->getRequestParameter($request, $form->getName())) { $form->submit($data); } @@ -122,7 +122,7 @@ private function export(DataTableInterface $dataTable, Request $request): void $form = $dataTable->createExportFormBuilder()->getForm(); - if ($data = $request->get($form->getName())) { + if ($data = $this->getRequestParameter($request, $form->getName())) { $form->submit($data); } @@ -131,6 +131,19 @@ private function export(DataTableInterface $dataTable, Request $request): void } } + private function getRequestParameter(Request $request, string $name): mixed + { + if ($request->query->has($name)) { + return $request->query->all()[$name]; + } + + if ($request->request->has($name)) { + return $request->request->all()[$name]; + } + + return null; + } + private function extractQueryParameter(Request $request, string $path): mixed { return $this->propertyAccessor->getValue($request->query->all(), $path); diff --git a/tests/Unit/DataCollector/DataTableDataCollectorTest.php b/tests/Unit/DataCollector/DataTableDataCollectorTest.php new file mode 100644 index 00000000..eeba40be --- /dev/null +++ b/tests/Unit/DataCollector/DataTableDataCollectorTest.php @@ -0,0 +1,528 @@ +dataExtractor = $this->createMock(DataTableDataExtractorInterface::class); + $this->collector = new DataTableDataCollector($this->dataExtractor); + } + + public function testCollectDoesNothing(): void + { + $this->collector->collect(new Request(), new Response()); + + $this->assertSame([], $this->collector->getData()); + } + + public function testGetTemplate(): void + { + $this->assertSame( + '@KreyuDataTable/data_collector/template.html.twig', + DataTableDataCollector::getTemplate(), + ); + } + + public function testCollectDataTable(): void + { + $column = $this->createColumnMock('id'); + $filter = $this->createFilterMock('name'); + $action = $this->createActionMock('edit'); + $rowAction = $this->createActionMock('view'); + $batchAction = $this->createActionMock('delete'); + $exporter = $this->createExporterMock('csv'); + + $config = $this->createMock(DataTableConfigInterface::class); + $config->method('isPaginationEnabled')->willReturn(true); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('getColumns')->willReturn(['id' => $column]); + $dataTable->method('getFilters')->willReturn(['name' => $filter]); + $dataTable->method('getActions')->willReturn(['edit' => $action]); + $dataTable->method('getRowActions')->willReturn(['view' => $rowAction]); + $dataTable->method('getBatchActions')->willReturn(['delete' => $batchAction]); + $dataTable->method('getExporters')->willReturn(['csv' => $exporter]); + $dataTable->method('getConfig')->willReturn($config); + + $this->dataExtractor->method('extractDataTableConfiguration')->willReturn(['type_class' => 'App\\DataTable']); + $this->dataExtractor->method('extractColumnConfiguration')->willReturn(['column_config' => true]); + $this->dataExtractor->method('extractFilterConfiguration')->willReturn(['filter_config' => true]); + $this->dataExtractor->method('extractActionConfiguration')->willReturnCallback( + fn (ActionInterface $a) => ['action_name' => $a->getName()], + ); + $this->dataExtractor->method('extractExporterConfiguration')->willReturn(['exporter_config' => true]); + + $this->collector->collectDataTable($dataTable); + + $data = $this->collector->getData(); + + $this->assertArrayHasKey('users', $data); + $this->assertSame('App\\DataTable', $data['users']['type_class']); + $this->assertSame(['column_config' => true], $data['users']['columns']['id']); + $this->assertSame(['filter_config' => true], $data['users']['filters']['name']); + $this->assertSame(['action_name' => 'edit'], $data['users']['actions']['edit']); + $this->assertSame(['action_name' => 'view'], $data['users']['row_actions']['view']); + $this->assertSame(['action_name' => 'delete'], $data['users']['batch_actions']['delete']); + $this->assertSame(['exporter_config' => true], $data['users']['exporters']['csv']); + } + + public function testCollectDataTableWithPaginationDisabledCollectsTotalCount(): void + { + $config = $this->createMock(DataTableConfigInterface::class); + $config->method('isPaginationEnabled')->willReturn(false); + + $dataTable = $this->createDataTableMock('products'); + $dataTable->method('getColumns')->willReturn([]); + $dataTable->method('getFilters')->willReturn([]); + $dataTable->method('getActions')->willReturn([]); + $dataTable->method('getRowActions')->willReturn([]); + $dataTable->method('getBatchActions')->willReturn([]); + $dataTable->method('getExporters')->willReturn([]); + $dataTable->method('getConfig')->willReturn($config); + $dataTable->method('getItems')->willReturn(new \ArrayIterator([1, 2, 3])); + + $this->dataExtractor->method('extractDataTableConfiguration')->willReturn([]); + + $this->collector->collectDataTable($dataTable); + + $data = $this->collector->getData(); + $this->assertSame(3, $data['products']['total_count']); + } + + public function testCollectDataTableView(): void + { + $this->initializeCollectorWithDataTable('orders'); + + $view = new DataTableView(); + $view->vars = ['foo' => 'bar', 'baz' => 'qux']; + + $dataTable = $this->createDataTableMock('orders'); + $this->dataExtractor->method('extractValueRows')->willReturn([['row1'], ['row2']]); + + $this->collector->collectDataTableView($dataTable, $view); + + $data = $this->collector->getData(); + $this->assertSame(['baz' => 'qux', 'foo' => 'bar'], $data['orders']['view_vars']); + $this->assertSame([['row1'], ['row2']], $data['orders']['value_rows']); + } + + public function testCollectColumnHeaderView(): void + { + $this->initializeCollectorWithDataTable('users', columns: ['email']); + + $column = $this->createColumnMock('email'); + $columnDataTable = $this->createDataTableMock('users'); + $column->method('getDataTable')->willReturn($columnDataTable); + + $headerView = new ColumnHeaderView(new HeaderRowView(new DataTableView())); + $headerView->vars = ['label' => 'Email', 'attr' => ['class' => 'email']]; + + $this->collector->collectColumnHeaderView($column, $headerView); + + $data = $this->collector->getData(); + $this->assertSame( + ['attr' => ['class' => 'email'], 'label' => 'Email'], + $data['users']['columns']['email']['header_view_vars'], + ); + } + + public function testCollectColumnValueViewSkipsNestedColumns(): void + { + $this->initializeCollectorWithDataTable('users', columns: ['tags']); + + $column = $this->createColumnMock('tags'); + $columnDataTable = $this->createDataTableMock('users'); + $column->method('getDataTable')->willReturn($columnDataTable); + + $dataTableView = new DataTableView(); + $parentRow = new ValueRowView($dataTableView, 0, ['id' => 1]); + $parentRow->origin = $parentRow; + + $valueView = new ColumnValueView($parentRow); + $valueView->vars = ['value' => 'test']; + + $this->collector->collectColumnValueView($column, $valueView); + + $data = $this->collector->getData(); + $this->assertArrayNotHasKey('value_view_vars', $data['users']['columns']['tags']); + } + + public function testCollectColumnValueViewCollectsTopLevelColumns(): void + { + $this->initializeCollectorWithDataTable('users', columns: ['name']); + + $column = $this->createColumnMock('name'); + $columnDataTable = $this->createDataTableMock('users'); + $column->method('getDataTable')->willReturn($columnDataTable); + + $dataTableView = new DataTableView(); + $parentRow = new ValueRowView($dataTableView, 0, ['id' => 1]); + + $valueView = new ColumnValueView($parentRow); + $valueView->vars = ['value' => 'John', 'attr' => []]; + + $this->collector->collectColumnValueView($column, $valueView); + + $data = $this->collector->getData(); + $this->assertSame( + ['attr' => [], 'value' => 'John'], + $data['users']['columns']['name']['value_view_vars'], + ); + } + + public function testCollectSortingData(): void + { + $this->initializeCollectorWithDataTable('users', columns: ['name', 'email']); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('hasColumn')->willReturnCallback(fn (string $name) => in_array($name, ['name', 'email'])); + + $nameColumn = $this->createColumnMock('name'); + $nameDataTable = $this->createDataTableMock('users'); + $nameColumn->method('getDataTable')->willReturn($nameDataTable); + + $emailColumn = $this->createColumnMock('email'); + $emailDataTable = $this->createDataTableMock('users'); + $emailColumn->method('getDataTable')->willReturn($emailDataTable); + + $dataTable->method('getColumn')->willReturnMap([ + ['name', $nameColumn], + ['email', $emailColumn], + ]); + + $sortingData = new SortingData([ + new SortingColumnData('name', 'asc'), + new SortingColumnData('email', 'desc'), + ]); + + $this->collector->collectSortingData($dataTable, $sortingData); + + $data = $this->collector->getData(); + $this->assertSame('asc', $data['users']['columns']['name']['sort_direction']); + $this->assertSame('desc', $data['users']['columns']['email']['sort_direction']); + } + + public function testCollectSortingDataSkipsUnknownColumns(): void + { + $this->initializeCollectorWithDataTable('users'); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('hasColumn')->willReturn(false); + + $sortingData = new SortingData([ + new SortingColumnData('nonexistent', 'asc'), + ]); + + $this->collector->collectSortingData($dataTable, $sortingData); + + $data = $this->collector->getData(); + $this->assertArrayNotHasKey('nonexistent', $data['users']['columns']); + } + + public function testCollectPaginationData(): void + { + $this->initializeCollectorWithDataTable('users'); + + $pagination = $this->createMock(PaginationInterface::class); + $pagination->method('getTotalItemCount')->willReturn(100); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('getPagination')->willReturn($pagination); + + $paginationData = new PaginationData(3, 25); + + $this->collector->collectPaginationData($dataTable, $paginationData); + + $data = $this->collector->getData(); + $this->assertSame(3, $data['users']['page']); + $this->assertSame(25, $data['users']['per_page']); + $this->assertSame(100, $data['users']['total_count']); + } + + public function testCollectFilterView(): void + { + $this->initializeCollectorWithDataTable('users', filters: ['status']); + + $filter = $this->createFilterMock('status'); + $filterDataTable = $this->createDataTableMock('users'); + $filter->method('getDataTable')->willReturn($filterDataTable); + + $filterView = new FilterView(new DataTableView()); + $filterView->vars = ['label' => 'Status', 'attr' => []]; + + $this->collector->collectFilterView($filter, $filterView); + + $data = $this->collector->getData(); + $this->assertSame( + ['attr' => [], 'label' => 'Status'], + $data['users']['filters']['status']['view_vars'], + ); + } + + public function testCollectFiltrationData(): void + { + $this->initializeCollectorWithDataTable('users', filters: ['status', 'role']); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('hasFilter')->willReturnCallback(fn (string $name) => in_array($name, ['status', 'role'])); + + $statusFilter = $this->createFilterMock('status'); + $statusDataTable = $this->createDataTableMock('users'); + $statusFilter->method('getDataTable')->willReturn($statusDataTable); + + $roleFilter = $this->createFilterMock('role'); + $roleDataTable = $this->createDataTableMock('users'); + $roleFilter->method('getDataTable')->willReturn($roleDataTable); + + $dataTable->method('getFilter')->willReturnMap([ + ['status', $statusFilter], + ['role', $roleFilter], + ]); + + $statusFilterData = new FilterData('active', Operator::Equals); + $roleFilterData = new FilterData('admin'); + + $filtrationData = new FiltrationData([ + 'status' => $statusFilterData, + 'role' => $roleFilterData, + ]); + + $this->collector->collectFiltrationData($dataTable, $filtrationData); + + $data = $this->collector->getData(); + $this->assertSame($statusFilterData, $data['users']['filters']['status']['data']); + $this->assertSame('Equals', $data['users']['filters']['status']['operator_label']); + $this->assertSame($roleFilterData, $data['users']['filters']['role']['data']); + $this->assertNull($data['users']['filters']['role']['operator_label']); + } + + public function testCollectFiltrationDataSkipsUnknownFilters(): void + { + $this->initializeCollectorWithDataTable('users'); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('hasFilter')->willReturn(false); + + $filtrationData = new FiltrationData([ + 'nonexistent' => new FilterData('value'), + ]); + + $this->collector->collectFiltrationData($dataTable, $filtrationData); + + $data = $this->collector->getData(); + $this->assertArrayNotHasKey('nonexistent', $data['users']['filters']); + } + + public function testCollectActionViewForGlobalAction(): void + { + $this->initializeCollectorWithDataTable('users'); + + $this->assertActionViewCollected(ActionContext::Global, 'actions'); + } + + public function testCollectActionViewForRowAction(): void + { + $this->initializeCollectorWithDataTable('users'); + + $this->assertActionViewCollected(ActionContext::Row, 'row_actions'); + } + + public function testCollectActionViewForBatchAction(): void + { + $this->initializeCollectorWithDataTable('users'); + + $this->assertActionViewCollected(ActionContext::Batch, 'batch_actions'); + } + + public function testCollectDataTableMergesWithExistingData(): void + { + $config = $this->createMock(DataTableConfigInterface::class); + $config->method('isPaginationEnabled')->willReturn(true); + + $dataTable = $this->createDataTableMock('users'); + $dataTable->method('getColumns')->willReturn([]); + $dataTable->method('getFilters')->willReturn([]); + $dataTable->method('getActions')->willReturn([]); + $dataTable->method('getRowActions')->willReturn([]); + $dataTable->method('getBatchActions')->willReturn([]); + $dataTable->method('getExporters')->willReturn([]); + $dataTable->method('getConfig')->willReturn($config); + + $this->dataExtractor->method('extractDataTableConfiguration')->willReturn(['type_class' => 'App\\DataTable']); + + $this->collector->collectDataTable($dataTable); + $this->collector->collectDataTable($dataTable); + + $data = $this->collector->getData(); + $this->assertArrayHasKey('users', $data); + $this->assertSame('App\\DataTable', $data['users']['type_class']); + } + + public function testReset(): void + { + $this->initializeCollectorWithDataTable('users'); + + $this->assertNotEmpty($this->collector->getData()); + + $this->collector->reset(); + + $this->assertSame([], $this->collector->getData()); + } + + public function testDataSurvivesSerializationRoundtrip(): void + { + $this->initializeCollectorWithDataTable('users', columns: ['name']); + + $column = $this->createColumnMock('name'); + $columnDataTable = $this->createDataTableMock('users'); + $column->method('getDataTable')->willReturn($columnDataTable); + + $headerView = new ColumnHeaderView(new HeaderRowView(new DataTableView())); + $headerView->vars = ['label' => 'Name', 'attr' => []]; + $this->collector->collectColumnHeaderView($column, $headerView); + + $serialized = $this->collector->__serialize(); + $this->assertArrayHasKey('data', $serialized); + + $restoredCollector = new DataTableDataCollector($this->dataExtractor); + $restoredCollector->__unserialize($serialized); + + $data = $restoredCollector->getData(); + $this->assertInstanceOf(Data::class, $data); + } + + private function assertActionViewCollected(ActionContext $context, string $dataKey): void + { + $actionConfig = $this->createMock(ActionConfigInterface::class); + $actionConfig->method('getContext')->willReturn($context); + + $action = $this->createActionMock('test_action'); + $actionDataTable = $this->createDataTableMock('users'); + $action->method('getDataTable')->willReturn($actionDataTable); + $action->method('getConfig')->willReturn($actionConfig); + + $actionView = new ActionView(new DataTableView()); + $actionView->vars = ['label' => 'Test', 'attr' => []]; + + $this->collector->collectActionView($action, $actionView); + + $data = $this->collector->getData(); + $this->assertSame( + ['attr' => [], 'label' => 'Test'], + $data['users'][$dataKey]['test_action']['view_vars'], + ); + } + + private function initializeCollectorWithDataTable( + string $name, + array $columns = [], + array $filters = [], + ): void { + $config = $this->createMock(DataTableConfigInterface::class); + $config->method('isPaginationEnabled')->willReturn(true); + + $columnMocks = []; + foreach ($columns as $colName) { + $columnMocks[$colName] = $this->createColumnMock($colName); + } + + $filterMocks = []; + foreach ($filters as $filterName) { + $filterMocks[$filterName] = $this->createFilterMock($filterName); + } + + $dataTable = $this->createDataTableMock($name); + $dataTable->method('getColumns')->willReturn($columnMocks); + $dataTable->method('getFilters')->willReturn($filterMocks); + $dataTable->method('getActions')->willReturn([]); + $dataTable->method('getRowActions')->willReturn([]); + $dataTable->method('getBatchActions')->willReturn([]); + $dataTable->method('getExporters')->willReturn([]); + $dataTable->method('getConfig')->willReturn($config); + + $this->dataExtractor->method('extractDataTableConfiguration')->willReturn([]); + $this->dataExtractor->method('extractColumnConfiguration')->willReturn([]); + $this->dataExtractor->method('extractFilterConfiguration')->willReturn([]); + $this->dataExtractor->method('extractActionConfiguration')->willReturn([]); + $this->dataExtractor->method('extractExporterConfiguration')->willReturn([]); + + $this->collector->collectDataTable($dataTable); + } + + private function createDataTableMock(string $name): MockObject&DataTableInterface + { + $dataTable = $this->createMock(DataTableInterface::class); + $dataTable->method('getName')->willReturn($name); + + return $dataTable; + } + + private function createColumnMock(string $name): MockObject&ColumnInterface + { + $column = $this->createMock(ColumnInterface::class); + $column->method('getName')->willReturn($name); + + return $column; + } + + private function createFilterMock(string $name): MockObject&FilterInterface + { + $filter = $this->createMock(FilterInterface::class); + $filter->method('getName')->willReturn($name); + + return $filter; + } + + private function createActionMock(string $name): MockObject&ActionInterface + { + $action = $this->createMock(ActionInterface::class); + $action->method('getName')->willReturn($name); + + return $action; + } + + private function createExporterMock(string $name): MockObject&ExporterInterface + { + $exporter = $this->createMock(ExporterInterface::class); + $exporter->method('getName')->willReturn($name); + + return $exporter; + } +} From ff9e611db6cd7097269ed23abe1f3c1be0f08c1a Mon Sep 17 00:00:00 2001 From: daFish81 Date: Tue, 24 Mar 2026 12:05:38 +0100 Subject: [PATCH 3/3] fixup! build(deps): allow symfony 8 --- src/DataCollector/DataTableDataCollector.php | 10 +++++++++- .../Unit/DataCollector/DataTableDataCollectorTest.php | 10 +++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/DataCollector/DataTableDataCollector.php b/src/DataCollector/DataTableDataCollector.php index 60ef3ad3..d28e0df4 100644 --- a/src/DataCollector/DataTableDataCollector.php +++ b/src/DataCollector/DataTableDataCollector.php @@ -36,11 +36,19 @@ public function __construct( } } + /** + * @return array + */ public function __serialize(): array { $this->data = $this->cloneVar($this->data)->withMaxDepth($this->maxDepth); - return parent::__serialize(); + if (method_exists(parent::class, '__serialize')) { + return parent::__serialize(); + } + + // Symfony 7: __serialize() does not exist yet, replicate __sleep() behavior + return ['data' => $this->data]; } public static function getTemplate(): ?string diff --git a/tests/Unit/DataCollector/DataTableDataCollectorTest.php b/tests/Unit/DataCollector/DataTableDataCollectorTest.php index eeba40be..9f8758ce 100644 --- a/tests/Unit/DataCollector/DataTableDataCollectorTest.php +++ b/tests/Unit/DataCollector/DataTableDataCollectorTest.php @@ -418,14 +418,10 @@ public function testDataSurvivesSerializationRoundtrip(): void $headerView->vars = ['label' => 'Name', 'attr' => []]; $this->collector->collectColumnHeaderView($column, $headerView); - $serialized = $this->collector->__serialize(); - $this->assertArrayHasKey('data', $serialized); + $restoredCollector = unserialize(serialize($this->collector)); - $restoredCollector = new DataTableDataCollector($this->dataExtractor); - $restoredCollector->__unserialize($serialized); - - $data = $restoredCollector->getData(); - $this->assertInstanceOf(Data::class, $data); + $this->assertInstanceOf(DataTableDataCollector::class, $restoredCollector); + $this->assertInstanceOf(Data::class, $restoredCollector->getData()); } private function assertActionViewCollected(ActionContext $context, string $dataKey): void