diff --git a/composer.json b/composer.json index 152628506..8b0837fe1 100644 --- a/composer.json +++ b/composer.json @@ -25,9 +25,9 @@ } }, "require": { - "php": "^7.4|^8.0", + "php": "^7.4|^8", "livewire/livewire": "^2.4", - "shuchkin/simplexlsxgen": "^0.9.25" + "box/spout": "^3.2" }, "require-dev": { "phpunit/phpunit": "^9.5" diff --git a/resources/views/tailwind/2/header.blade.php b/resources/views/tailwind/2/header.blade.php index 643b3c033..1a20a510f 100644 --- a/resources/views/tailwind/2/header.blade.php +++ b/resources/views/tailwind/2/header.blade.php @@ -28,6 +28,7 @@ class="block px-4 py-2 text-gray-800 hover:bg-gray-100 hover:text-black-200">Exc Csv +
diff --git a/src/PowerGridComponent.php b/src/PowerGridComponent.php index 0d029c214..3abc2857a 100644 --- a/src/PowerGridComponent.php +++ b/src/PowerGridComponent.php @@ -5,8 +5,8 @@ use Livewire\Component; use Livewire\WithPagination; use PowerComponents\LivewirePowerGrid\Helpers\Collection; -use PowerComponents\LivewirePowerGrid\Services\ExportToCsv; -use PowerComponents\LivewirePowerGrid\Services\ExportToXLS; +use PowerComponents\LivewirePowerGrid\Services\Spout\ExportToCsv; +use PowerComponents\LivewirePowerGrid\Services\Spout\ExportToXLS; use PowerComponents\LivewirePowerGrid\Traits\Checkbox; use PowerComponents\LivewirePowerGrid\Traits\Filter; use Symfony\Component\HttpFoundation\BinaryFileResponse; @@ -330,6 +330,7 @@ public function exportToExcel(): BinaryFileResponse ->fromCollection($this->columns(), $this->collection()) ->withCheckedRows(array_merge($this->checkbox_values, $this->filtered)) ->download(); + } /** diff --git a/src/Services/Export.php b/src/Services/Export.php index 96319edb3..af83dff21 100644 --- a/src/Services/Export.php +++ b/src/Services/Export.php @@ -13,29 +13,48 @@ class Export public array $columns; public array $checked_values; + public function fileName(string $name): Export + { + $this->fileName = $name; + return $this; + } + + public function fromCollection(array $columns, Collection $collection): Export + { + $this->columns = $columns; + $this->collection = $collection; + return $this; + } + + public function withCheckedRows($checked_values): Export + { + $this->checked_values = $checked_values; + return $this; + } + /** * @throws Exception */ public function prepare(Collection $collection, array $columns, array $checkedValues): array { - $header = []; - $title = collect(); + + $header = collect(); if (count($checkedValues)) { $collection = $collection->whereIn('id', $checkedValues); } - $collection = $collection->map(function ($row) use ($columns, $title) { + $collection = $collection->map(function ($row) use ($columns, $header) { $item = collect(); - collect($columns)->each(function ($column) use ($row, $title, $item) { + collect($columns)->each(function ($column) use ($row, $header, $item) { if ($column->hidden === false && $column->visible_in_export === true) { foreach ($row as $key => $value) { if ($key === $column->field) { $item->put($column->title, $value); } } - if (!$title->contains($column->title)) { - $title->push($column->title); + if (!$header->contains($column->title)) { + $header->push($column->title); } } @@ -43,29 +62,10 @@ public function prepare(Collection $collection, array $columns, array $checkedVa return $item->toArray(); }); - $header[] = $title->toArray(); - - return array_merge($header, $collection->toArray()); + return [ + 'headers' => $header->toArray(), + 'rows' => $collection->toArray() + ]; } - public function fileName(string $name): Export - { - $this->fileName = $name; - return $this; - } - - public function fromCollection(array $columns, Collection $collection): Export - { - $this->columns = $columns; - $this->collection = $collection; - return $this; - } - - public function withCheckedRows($checked_values): Export - { - $this->checked_values = $checked_values; - return $this; - } - - } diff --git a/src/Services/ExportToCsv.php b/src/Services/ExportToCsv.php deleted file mode 100644 index 155e242c5..000000000 --- a/src/Services/ExportToCsv.php +++ /dev/null @@ -1,34 +0,0 @@ -put($this->fileName . '.csv', $this->build()); - - return response() - ->download(storage_path("app/public/" . $this->fileName . '.csv')); - - } - - public function build() - { - $data = $this->prepare($this->collection, $this->columns, $this->checked_values); - - $f = fopen('php://memory', 'w'); - foreach ($data as $line) { - fputcsv($f, $line, ";"); - } - return $f; - } -} diff --git a/src/Services/ExportToXLS.php b/src/Services/ExportToXLS.php deleted file mode 100644 index 718c03b1e..000000000 --- a/src/Services/ExportToXLS.php +++ /dev/null @@ -1,34 +0,0 @@ -put($this->fileName . '.xlsx', $this->build()); - - return response() - ->download(storage_path("app/public/" . $this->fileName . '.xlsx')); - } - - public function build() - { - $data = $this->prepare($this->collection, $this->columns, $this->checked_values); - return \SimpleXLSXGen::fromArray($data, $this->fileName); - } - -} diff --git a/src/Services/Spout/ExportToCsv.php b/src/Services/Spout/ExportToCsv.php new file mode 100644 index 000000000..3edb74898 --- /dev/null +++ b/src/Services/Spout/ExportToCsv.php @@ -0,0 +1,46 @@ +build(); + + return response() + ->download(storage_path($this->fileName . '.csv')); + + } + + public function build() + { + + $data = $this->prepare($this->collection, $this->columns, $this->checked_values); + + $writer = WriterEntityFactory::createCSVWriter(); + $writer->openToFile(storage_path($this->fileName . '.csv')); + + $row = WriterEntityFactory::createRowFromArray($data['headers']); + + $writer->addRow($row); + + foreach ($data['rows'] as $row) { + $row = WriterEntityFactory::createRowFromArray($row); + $writer->addRow($row); + } + + $writer->close(); + + } +} diff --git a/src/Services/Spout/ExportToXLS.php b/src/Services/Spout/ExportToXLS.php new file mode 100644 index 000000000..4bb410b5a --- /dev/null +++ b/src/Services/Spout/ExportToXLS.php @@ -0,0 +1,53 @@ +build(); + + return response() + ->download(storage_path($this->fileName . '.xlsx')); + + } + + public function build() + { + $data = $this->prepare($this->collection, $this->columns, $this->checked_values); + + $writer = WriterEntityFactory::createXLSXWriter(); + $writer->openToFile(storage_path($this->fileName . '.xlsx')); + + $style = (new StyleBuilder()) + ->setFontBold() + ->setFontColor(Color::BLACK) + ->setShouldWrapText(false) + ->setCellAlignment(CellAlignment::CENTER) + ->setBackgroundColor('d0d3d8') + ->build(); + + $row = WriterEntityFactory::createRowFromArray($data['headers'], $style); + + $writer->addRow($row); + + foreach ($data['rows'] as $row) { + $row = WriterEntityFactory::createRowFromArray($row); + $writer->addRow($row); + } + + $writer->close(); + + } +} diff --git a/src/Traits/Filter.php b/src/Traits/Filter.php index 327a2cd1a..0716096eb 100644 --- a/src/Traits/Filter.php +++ b/src/Traits/Filter.php @@ -11,10 +11,10 @@ trait Filter public Collection $make_filters; public array $filters = []; public array $filters_enabled = []; - private string $format_date = ''; public array $select = []; + private string $format_date = ''; - public function clearFilter( $field = '' ) + public function clearFilter($field = '') { $this->search = ''; unset($this->filters_enabled[$field]); @@ -40,7 +40,7 @@ private function renderFilter() } - private function advancedFilter( Collection $collection ): Collection + private function advancedFilter(Collection $collection): Collection { foreach ($this->filters as $key => $type) { @@ -51,93 +51,23 @@ private function advancedFilter( Collection $collection ): Collection switch ($key) { case 'date_picker': - if (isset($value[0]) && isset($value[1])) { - $collection = $collection->whereBetween($field, [Carbon::parse($value[0]), Carbon::parse($value[1])]); - } - break; - + $collection = $this->usingDatePicker($collection, $field, $value); + break; case 'multi_select': - if (count(collect($value)->get('values'))) { - $collection = $collection->whereIn($field, collect($value)->get('values')); - } - break; - + $collection = $this->usingMultiSelect($collection, $field, $value); + break; case 'select': - $collection = $collection->where($field, $value); - break; - + $collection = $this->usingSelect($collection, $field, $value); + break; case 'boolean': - - if ($value != "all") { - $value = ($value == "true"); - $collection = $collection->where($field, '=', $value); - } - break; - + $collection = $this->usingBoolean($collection, $field, $value); + break; case 'input_text': - - $textFieldOperator = ( $this->validatenputTextOptions($field) ? strtolower($this->filters['input_text_options'][$field]) : 'contains'); - - if ($textFieldOperator == 'is') { - $collection = $collection->where($field, '=', $value); - } - - if ($textFieldOperator == 'is_not') { - $collection = $collection->where($field, '!=', $value); - } - - if ($textFieldOperator == 'starts_with') { - $collection = $collection->filter(function ($row) use ($field, $value) { - return Str::startsWith(Str::lower( $row->$field), Str::lower($value)); - //return preg_match("#^{$value}(.*)$#i", $row->$field); - }); - } - - if ($textFieldOperator == 'ends_with') { - $collection = $collection->filter(function ($row) use ($field, $value) { - return Str::endsWith(Str::lower($row->$field), Str::lower($value)); - - }); - } - - if ($textFieldOperator == 'contains') { - $collection = $collection->filter(function ($row) use ($field, $value) { - return false !== stristr($row->$field, strtolower($value)); - }); - } - - if ($textFieldOperator == 'contains_not') { - $collection = $collection->filter(function ($row) use ($field, $value) { - return !Str::Contains(Str::lower($row->$field), Str::lower($value)); - //return (!preg_match("#(.*?)(?i)({$value})(.*?)#", $row->$field)); - }); - } - break; - + $collection = $this->usingInputText($collection, $field, $value); + break; case 'number': - - if (isset($value['start']) && !isset($value['end'])) { - $start = str_replace($value['thousands'], '', $value['start']); - $start = (float)str_replace($value['decimal'], '.', $start); - - $collection = $collection->where($field, '>=', $start); - } - if (!isset($value['start']) && isset($value['end'])) { - $end = str_replace($value['thousands'], '', $value['end']); - $end = (float)str_replace($value['decimal'], '.', $end); - - $collection = $collection->where($field, '<=', $end); - } - if (isset($value['start']) && isset($value['end'])) { - $start = str_replace($value['thousands'], '', $value['start']); - $start = str_replace($value['decimal'], '.', $start); - - $end = str_replace($value['thousands'], '', $value['end']); - $end = str_replace($value['decimal'], '.', $end); - - $collection = $collection->whereBetween($field, [$start, $end]); - } - break; + $collection = $this->usingNumber($collection, $field, $value); + break; } } } @@ -148,7 +78,7 @@ private function advancedFilter( Collection $collection ): Collection /** * @param $data */ - public function eventChangeDatePiker(array $data ): void + public function eventChangeDatePiker(array $data): void { $input = explode('.', $data['values']); $this->filters['date_picker'][$input[2]] = $data['selectedDates']; @@ -157,7 +87,7 @@ public function eventChangeDatePiker(array $data ): void /** * @param $data */ - public function eventMultiSelect(array $data ) + public function eventMultiSelect(array $data) { $this->filters['multi_select'][$data['id']] = $data; } @@ -168,7 +98,7 @@ public function eventMultiSelect(array $data ) * @param string $thousands * @param string $decimal */ - public function filterNumberStart( string $field, string $value, string $thousands, string $decimal ): void + public function filterNumberStart(string $field, string $value, string $thousands, string $decimal): void { $this->filters['number'][$field]['start'] = $value; $this->filters['number'][$field]['thousands'] = $thousands; @@ -181,7 +111,7 @@ public function filterNumberStart( string $field, string $value, string $thousan * @param string $thousands * @param string $decimal */ - public function filterNumberEnd( string $field, string $value, string $thousands, string $decimal ): void + public function filterNumberEnd(string $field, string $value, string $thousands, string $decimal): void { $this->filters['number'][$field]['end'] = $value; $this->filters['number'][$field]['thousands'] = $thousands; @@ -192,7 +122,7 @@ public function filterNumberEnd( string $field, string $value, string $thousands * @param string $field * @param string $value */ - public function filterInputText( string $field, string $value ): void + public function filterInputText(string $field, string $value): void { $this->filters['input_text'][$field] = $value; } @@ -218,12 +148,146 @@ public function filterInputTextOptions(string $field, string $value): void /** * Validate if the given value is valid as an Input Option * - * @param string $field Field to be checked - * @return void + * @param string $field Field to be checked + * @return bool + */ + private function validateInputTextOptions(string $field) + { + + return isset($this->filters['input_text_options'][$field]) && in_array(strtolower($this->filters['input_text_options'][$field]), + ['is', 'is_not', 'contains', 'contains_not', 'starts_with', 'ends_with']); + + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection + */ + private function usingDatePicker(Collection $collection, string $field, $value): Collection + { + if (isset($value[0]) && isset($value[1])) { + $collection = $collection->whereBetween($field, [Carbon::parse($value[0]), Carbon::parse($value[1])]); + } + return $collection; + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection */ - private function validatenputTextOptions(string $field) { + private function usingInputText(Collection $collection, string $field, $value): Collection + { + + $textFieldOperator = ($this->validateInputTextOptions($field) ? strtolower($this->filters['input_text_options'][$field]) : 'contains'); - return isset($this->filters['input_text_options'][$field]) && in_array(strtolower($this->filters['input_text_options'][$field]), ['is', 'is_not', 'contains', 'contains_not', 'starts_with', 'ends_with']); + if ($textFieldOperator == 'is') { + return $collection->where($field, '=', $value); + } + + if ($textFieldOperator == 'is_not') { + return $collection->where($field, '!=', $value); + } + + if ($textFieldOperator == 'starts_with') { + return $collection->filter(function ($row) use ($field, $value) { + return Str::startsWith(Str::lower($row->$field), Str::lower($value)); + }); + } + if ($textFieldOperator == 'ends_with') { + return $collection->filter(function ($row) use ($field, $value) { + return Str::endsWith(Str::lower($row->$field), Str::lower($value)); + + }); + } + + if ($textFieldOperator == 'contains') { + return $collection->filter(function ($row) use ($field, $value) { + return false !== stristr($row->$field, strtolower($value)); + }); + } + + if ($textFieldOperator == 'contains_not') { + return $collection->filter(function ($row) use ($field, $value) { + return !Str::Contains(Str::lower($row->$field), Str::lower($value)); + }); + } + return $collection; + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection + */ + private function usingBoolean(Collection $collection, string $field, $value): Collection + { + if ($value != "all") { + $value = ($value == "true"); + return $collection->where($field, '=', $value); + } + return $collection; + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection + */ + private function usingSelect(Collection $collection, string $field, $value): Collection + { + return $collection->where($field, $value); + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection + */ + private function usingMultiSelect(Collection $collection, string $field, $value): Collection + { + if (count(collect($value)->get('values'))) { + return $collection->whereIn($field, collect($value)->get('values')); + } + return $collection; + } + + /** + * @param Collection $collection + * @param string $field + * @param $value + * @return Collection + */ + private function usingNumber(Collection $collection, string $field, $value): Collection + { + if (isset($value['start']) && !isset($value['end'])) { + $start = str_replace($value['thousands'], '', $value['start']); + $start = (float)str_replace($value['decimal'], '.', $start); + + return $collection->where($field, '>=', $start); + } + if (!isset($value['start']) && isset($value['end'])) { + $end = str_replace($value['thousands'], '', $value['end']); + $end = (float)str_replace($value['decimal'], '.', $end); + + return $collection->where($field, '<=', $end); + } + if (isset($value['start']) && isset($value['end'])) { + $start = str_replace($value['thousands'], '', $value['start']); + $start = str_replace($value['decimal'], '.', $start); + + $end = str_replace($value['thousands'], '', $value['end']); + $end = str_replace($value['decimal'], '.', $end); + + return $collection->whereBetween($field, [$start, $end]); + } + return $collection; } }