diff --git a/composer.json b/composer.json index 3718de7c..dedb3acf 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "laravel/pint": "^1.13.8", "laradumps/laradumps-core": "^1.1", "larastan/larastan": "^2.8.1", - "pestphp/pest": "^2.30.0", + "pestphp/pest": "2.28.0", "orchestra/testbench": "8.19|^9.0" }, "suggest": { diff --git a/phpstan.neon b/phpstan.neon index 00ffa60f..aeb005a7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -12,7 +12,7 @@ parameters: - '~^Parameter #1 \$value of function intval expects array\|bool\|float\|int\|resource\|string\|null, mixed given\.$~' - '#^Method .*::fromLivewire\(\) has no return type specified\.#' - '#^Method .*::fromLivewire\(\) has parameter \$value with no type specified\.#' - + - '#Call to an undefined method PowerComponents\\LivewirePowerGrid\\PowerGridComponent::datasource\(\).#' paths: - src diff --git a/src/Concerns/Base.php b/src/Concerns/Base.php index 1856a43d..c31ea2be 100644 --- a/src/Concerns/Base.php +++ b/src/Concerns/Base.php @@ -79,14 +79,6 @@ public function filters(): array return []; } - /** - * @return null - */ - public function datasource() - { - return null; - } - public function summarizeFormat(): array { return []; diff --git a/src/Jobs/ExportJob.php b/src/Jobs/ExportJob.php index c299af4d..ac629588 100644 --- a/src/Jobs/ExportJob.php +++ b/src/Jobs/ExportJob.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\{InteractsWithQueue, SerializesModels}; +use Illuminate\Support\Facades\Crypt; use PowerComponents\LivewirePowerGrid\PowerGridComponent; use PowerComponents\LivewirePowerGrid\Traits\ExportableJob; @@ -19,6 +20,8 @@ class ExportJob implements ShouldQueue use SerializesModels; use ExportableJob; + private array $properties; + /** * @param string $componentTable * @param array $columns @@ -34,7 +37,8 @@ public function __construct( $this->fileName = $params['fileName']; $this->offset = $params['offset']; $this->limit = $params['limit']; - $this->filters = $params['filters']; + $this->filters = (array) Crypt::decrypt($params['filters']); + $this->properties = (array) Crypt::decrypt($params['parameters']); /** @var PowerGridComponent $componentTable */ $this->componentTable = new $componentTable(); @@ -56,7 +60,7 @@ public function handle(): void /** @phpstan-ignore-next-line */ $exportable ->fileName($this->getFilename()) - ->setData($columnsWithHiddenState, $this->prepareToExport()) + ->setData($columnsWithHiddenState, $this->prepareToExport($this->properties)) ->download([]); } } diff --git a/src/PowerGridComponent.php b/src/PowerGridComponent.php index 01f90c07..f90f8eba 100644 --- a/src/PowerGridComponent.php +++ b/src/PowerGridComponent.php @@ -184,6 +184,16 @@ private function renderView(mixed $data): Application|Factory|View ]); } + public function getPublicPropertiesDefinedInComponent(): array + { + return collect((new \ReflectionClass($this))->getProperties(\ReflectionProperty::IS_PUBLIC)) + ->where('class', get_class($this)) + ->pluck('name') + ->intersect(array_keys($this->all())) + ->mapWithKeys(fn ($property) => [$property => $this->$property]) + ->all(); + } + /** * @throws Exception|Throwable */ diff --git a/src/ProcessDataSource.php b/src/ProcessDataSource.php index a89feca9..832ca89b 100644 --- a/src/ProcessDataSource.php +++ b/src/ProcessDataSource.php @@ -21,13 +21,14 @@ class ProcessDataSource public bool $isCollection = false; public function __construct( - public PowerGridComponent $component + public PowerGridComponent $component, + public array $properties = [], ) { } - public static function fillData(PowerGridComponent $powerGridComponent): ProcessDataSource + public static function fillData(PowerGridComponent $powerGridComponent, array $properties = []): ProcessDataSource { - return new self($powerGridComponent); + return new self($powerGridComponent, $properties); } /** @@ -55,7 +56,7 @@ public function prepareDataSource(): EloquentBuilder|BaseCollection|Collection|Q $datasource = $this->component->datasource ?? null; if (empty($datasource)) { - $datasource = $this->component->datasource(); + $datasource = $this->component->datasource($this->properties); } if (is_array($datasource)) { @@ -108,7 +109,6 @@ private function processModel(EloquentBuilder|MorphToMany|QueryBuilder|BaseColle ); if ($datasource instanceof EloquentBuilder || $datasource instanceof MorphToMany) { - /** @phpstan-ignore-next-line */ $results = $this->applySoftDeletes($results, $this->component->softDeletes); } @@ -116,7 +116,6 @@ private function processModel(EloquentBuilder|MorphToMany|QueryBuilder|BaseColle $sortField = $this->makeSortField($this->component->sortField); - /** @phpstan-ignore-next-line */ $results = $this->component->multiSort ? $this->applyMultipleSort($results) : $this->applySingleSort($results, $sortField); $results = $this->applyPerPage($results); diff --git a/src/Traits/ExportableJob.php b/src/Traits/ExportableJob.php index cbb80b21..61ec3868 100644 --- a/src/Traits/ExportableJob.php +++ b/src/Traits/ExportableJob.php @@ -31,10 +31,10 @@ private function getFilename(): Stringable ->replace('.csv', ''); } - private function prepareToExport(): Eloquent\Collection|Collection + private function prepareToExport(array $properties = []): Eloquent\Collection|Collection { /** @phpstan-ignore-next-line */ - $processDataSource = tap(ProcessDataSource::fillData($this->componentTable), fn ($datasource) => $datasource->get()); + $processDataSource = tap(ProcessDataSource::fillData($this->componentTable, $properties), fn ($datasource) => $datasource->get()); $inClause = $processDataSource->component->filtered ?? []; diff --git a/src/Traits/WithExport.php b/src/Traits/WithExport.php index 922c7c5f..2d8211d6 100644 --- a/src/Traits/WithExport.php +++ b/src/Traits/WithExport.php @@ -120,7 +120,8 @@ private function putQueuesToBus(string $exportableClass, string $fileExtension): 'fileName' => $fileName, 'offset' => $offset, 'limit' => $limit, - 'filters' => $filters, + 'filters' => Support\Facades\Crypt::encrypt($filters), + 'parameters' => Support\Facades\Crypt::encrypt($processDataSource->component->getPublicPropertiesDefinedInComponent()), ]; $queues->push(new $this->exportableJobClass( diff --git a/tests/Concerns/Components/BatchExportTable.php b/tests/Concerns/Components/BatchExportTable.php new file mode 100644 index 00000000..743357ae --- /dev/null +++ b/tests/Concerns/Components/BatchExportTable.php @@ -0,0 +1,81 @@ +striped() + ->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV) + ->queues(6), + + Header::make() + ->showSearchInput(), + + Footer::make() + ->showPerPage() + ->showRecordCount(), + ]; + } + + public function datasource(array $parameters): Builder + { + return Dish::with('category')->where('id', $parameters['filterDataSourceId'] ?? 1); + } + + public function fields(): PowerGridFields + { + return PowerGrid::fields() + ->add('id') + ->add('name'); + } + + public function columns(): array + { + return [ + Column::add() + ->title(__('ID')) + ->field('id') + ->searchable() + ->sortable(), + + Column::add() + ->title('Dish') + ->field('name') + ->searchable() + ->sortable(), + ]; + } + + public function bootstrap() + { + config(['livewire-powergrid.theme' => 'bootstrap']); + } + + public function tailwind() + { + config(['livewire-powergrid.theme' => 'tailwind']); + } +} diff --git a/tests/Feature/BatchExportTest.php b/tests/Feature/BatchExportTest.php new file mode 100644 index 00000000..3cc3ff9a --- /dev/null +++ b/tests/Feature/BatchExportTest.php @@ -0,0 +1,32 @@ + 77, + ]) + ->call('exportToXLS', false); + + $getPublicPropertiesDefinedInComponent = $component->instance()->getPublicPropertiesDefinedInComponent(); + + Bus::assertBatched(function (PendingBatch $batch) use ($getPublicPropertiesDefinedInComponent) { + $jobs = $batch->jobs[0]; + + $properties = invade($jobs[0])->properties; + + return $getPublicPropertiesDefinedInComponent['filterDataSourceId'] === + $properties['filterDataSourceId']; + }); +})->requiresOpenSpout();