diff --git a/src/DataCollector/DataTableDataCollector.php b/src/DataCollector/DataTableDataCollector.php index b8c5eea4..ee378ee5 100644 --- a/src/DataCollector/DataTableDataCollector.php +++ b/src/DataCollector/DataTableDataCollector.php @@ -18,6 +18,7 @@ use Kreyu\Bundle\DataTableBundle\Filter\FiltrationData; use Kreyu\Bundle\DataTableBundle\Pagination\PaginationData; use Kreyu\Bundle\DataTableBundle\Sorting\SortingData; +use Kreyu\Bundle\DataTableBundle\Util\ArrayUtil; use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -42,6 +43,11 @@ public function __sleep(): array return parent::__sleep(); } + public static function getTemplate(): ?string + { + return '@KreyuDataTable/data_collector/template.html.twig'; + } + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void { } @@ -49,27 +55,27 @@ public function collect(Request $request, Response $response, ?\Throwable $excep public function collectDataTable(DataTableInterface $dataTable): void { $data = [ - 'columns' => $this->mapWithKeys( + 'columns' => ArrayUtil::mapWithKeys( fn (ColumnInterface $column) => [$column->getName() => $this->dataExtractor->extractColumnConfiguration($column)], $dataTable->getColumns(), ), - 'filters' => $this->mapWithKeys( + 'filters' => ArrayUtil::mapWithKeys( fn (FilterInterface $filter) => [$filter->getName() => $this->dataExtractor->extractFilterConfiguration($filter)], $dataTable->getFilters(), ), - 'actions' => $this->mapWithKeys( + 'actions' => ArrayUtil::mapWithKeys( fn (ActionInterface $action) => [$action->getName() => $this->dataExtractor->extractActionConfiguration($action)], $dataTable->getActions(), ), - 'row_actions' => $this->mapWithKeys( + 'row_actions' => ArrayUtil::mapWithKeys( fn (ActionInterface $action) => [$action->getName() => $this->dataExtractor->extractActionConfiguration($action)], $dataTable->getRowActions(), ), - 'batch_actions' => $this->mapWithKeys( + 'batch_actions' => ArrayUtil::mapWithKeys( fn (ActionInterface $action) => [$action->getName() => $this->dataExtractor->extractActionConfiguration($action)], $dataTable->getBatchActions(), ), - 'exporters' => $this->mapWithKeys( + 'exporters' => ArrayUtil::mapWithKeys( fn (ExporterInterface $exporter) => [$exporter->getName() => $this->dataExtractor->extractExporterConfiguration($exporter)], $dataTable->getExporters(), ), @@ -83,14 +89,14 @@ public function collectDataTable(DataTableInterface $dataTable): void public function collectDataTableView(DataTableInterface $dataTable, DataTableView $view): void { $this->data[$dataTable->getName()] += [ - 'view_vars' => $this->ksort($view->vars), + 'view_vars' => ArrayUtil::ksort($view->vars), 'value_rows' => $this->dataExtractor->extractValueRows($view), ]; } public function collectColumnHeaderView(ColumnInterface $column, ColumnHeaderView $view): void { - $this->data[$column->getDataTable()->getName()]['columns'][$column->getName()]['header_view_vars'] = $this->ksort($view->vars); + $this->data[$column->getDataTable()->getName()]['columns'][$column->getName()]['header_view_vars'] = ArrayUtil::ksort($view->vars); } public function collectColumnValueView(ColumnInterface $column, ColumnValueView $view): void @@ -100,7 +106,7 @@ public function collectColumnValueView(ColumnInterface $column, ColumnValueView return; } - $this->data[$column->getDataTable()->getName()]['columns'][$column->getName()]['value_view_vars'] = $this->ksort($view->vars); + $this->data[$column->getDataTable()->getName()]['columns'][$column->getName()]['value_view_vars'] = ArrayUtil::ksort($view->vars); } public function collectSortingData(DataTableInterface $dataTable, SortingData $data): void @@ -128,7 +134,7 @@ public function collectPaginationData(DataTableInterface $dataTable, PaginationD public function collectFilterView(FilterInterface $filter, FilterView $view): void { - $this->data[$filter->getDataTable()->getName()]['filters'][$filter->getName()]['view_vars'] = $this->ksort($view->vars); + $this->data[$filter->getDataTable()->getName()]['filters'][$filter->getName()]['view_vars'] = ArrayUtil::ksort($view->vars); } public function collectFiltrationData(DataTableInterface $dataTable, FiltrationData $data): void @@ -156,44 +162,11 @@ public function collectActionView(ActionInterface $action, ActionView $view): vo ActionContext::Batch => 'batch_actions', }; - $this->data[$action->getDataTable()->getName()][$actionsKey][$action->getName()]['view_vars'] = $this->ksort($view->vars); - } - - public static function getTemplate(): ?string - { - return '@KreyuDataTable/data_collector/template.html.twig'; + $this->data[$action->getDataTable()->getName()][$actionsKey][$action->getName()]['view_vars'] = ArrayUtil::ksort($view->vars); } public function getData(): array|Data { return $this->data; } - - /** - * @internal - */ - private function mapWithKeys(callable $callback, array $array): array - { - $data = []; - - foreach ($array as $value) { - foreach ($callback($value) as $mapKey => $mapValue) { - $data[$mapKey] = $mapValue; - } - } - - return $data; - } - - /** - * @internal - */ - private function ksort(array $array): array - { - $copy = $array; - - ksort($copy); - - return $copy; - } } diff --git a/src/DataTable.php b/src/DataTable.php index b04cfaf1..95379f0e 100755 --- a/src/DataTable.php +++ b/src/DataTable.php @@ -134,19 +134,19 @@ public function initialize(): void $this->dispatch(DataTableEvents::PRE_INITIALIZE, new DataTableEvent($this)); - if ($paginationData = $this->getInitialPaginationData()) { + if (null === $this->paginationData && $paginationData = $this->getInitialPaginationData()) { $this->paginate($paginationData, false); } - if ($sortingData = $this->getInitialSortingData()) { + if (null === $this->sortingData && $sortingData = $this->getInitialSortingData()) { $this->sort($sortingData, false); } - if ($filtrationData = $this->getInitialFiltrationData()) { + if (null === $this->filtrationData && $filtrationData = $this->getInitialFiltrationData()) { $this->filter($filtrationData, false); } - if ($personalizationData = $this->getInitialPersonalizationData()) { + if (null === $this->personalizationData && $personalizationData = $this->getInitialPersonalizationData()) { $this->personalize($personalizationData, false); } @@ -584,7 +584,7 @@ public function export(?ExportData $data = null): ExportFile $data = $event->getExportData(); if (ExportStrategy::IncludeAll === $data->strategy) { - $dataTable->getQuery()->paginate(new PaginationData(perPage: null)); + $this->paginate(new PaginationData(page: 1, perPage: null), persistence: false); } if (!$data->includePersonalization) { @@ -784,6 +784,10 @@ public function handleRequest(mixed $request): void public function createView(): DataTableView { + if (!$this->initialized) { + $this->initialize(); + } + $type = $this->config->getType(); $options = $this->config->getOptions(); @@ -796,6 +800,10 @@ public function createView(): DataTableView public function createExportView(): DataTableView { + if (!$this->initialized) { + $this->initialize(); + } + $type = $this->config->getType(); $options = $this->config->getOptions(); diff --git a/src/DataTableBuilder.php b/src/DataTableBuilder.php index bb2bfbe9..8f49c975 100755 --- a/src/DataTableBuilder.php +++ b/src/DataTableBuilder.php @@ -775,10 +775,6 @@ public function getDataTable(): DataTableInterface $dataTable->addExporter($exporter->getExporter()); } - // TODO: Remove initialization logic from builder. - // Instead, add "initialized" flag to the data table itself to allow lazy initialization. - $dataTable->initialize(); - return $dataTable; } diff --git a/src/Util/ArrayUtil.php b/src/Util/ArrayUtil.php new file mode 100644 index 00000000..e303c283 --- /dev/null +++ b/src/Util/ArrayUtil.php @@ -0,0 +1,53 @@ + + * $map = ArrayUtil::mapWithKeys( + * callback: fn (array $array) => [$array['id'] => $array['name']], + * array: [ + * ['id' => 1, 'name' => 'John'], + * ['id' => 2, 'name' => 'Jane'], + * ] + * ); + * + * var_dump($map); // array(2) { [1] => string(4) "John" [2] => string(4) "Jane" } + * + * + * @param callable(mixed): array $callback + */ + public static function mapWithKeys(callable $callback, array $array): array + { + $data = []; + + foreach ($array as $value) { + foreach ($callback($value) as $mapKey => $mapValue) { + $data[$mapKey] = $mapValue; + } + } + + return $data; + } + + /** + * Performs a `ksort` on a copy of given array instead of modifying it by reference. + */ + public static function ksort(array $array, int $flags = SORT_REGULAR): array + { + $copy = $array; + + ksort($copy, $flags); + + return $copy; + } +} \ No newline at end of file diff --git a/tests/Unit/Util/ArrayUtilTest.php b/tests/Unit/Util/ArrayUtilTest.php new file mode 100644 index 00000000..6ae16848 --- /dev/null +++ b/tests/Unit/Util/ArrayUtilTest.php @@ -0,0 +1,39 @@ + 3, 'b' => 2, 'a' => 1]; + $output = ArrayUtil::ksort($input); + + $this->assertSame(['a' => 1, 'b' => 2, 'c' => 3], $output); + $this->assertSame(['c' => 3, 'b' => 2, 'a' => 1], $input); + } + + public function testMapWithKeys() + { + $input = [ + ['id' => 1, 'name' => 'John'], + ['id' => 2, 'name' => 'Jane'], + ]; + + $output = ArrayUtil::mapWithKeys( + callback: fn (array $array) => [$array['id'] => $array['name']], + array: $input, + ); + + $this->assertSame([1 => 'John', 2 => 'Jane'], $output); + $this->assertSame([ + ['id' => 1, 'name' => 'John'], + ['id' => 2, 'name' => 'Jane'], + ], $input); + } +}