diff --git a/composer.json b/composer.json index 23df792..374499e 100644 --- a/composer.json +++ b/composer.json @@ -1,43 +1,44 @@ { - "name": "zuko/flex2cell", - "description": "A flexible and efficient library for exporting data to Excel (XLS, XLSX) with support for mappings, formatters, and handling large datasets. Working with less dependencies, avoid future breaks & conclusions.", - "type": "library", - "license": "MIT", - "autoload": { - "psr-4": { - "Zuko\\Flex2Cell\\": "src/" - }, - "files": [ - "src/aliases.php" - ] + "name" : "zuko/flex2cell", + "description" : "A flexible and efficient library for exporting data to Excel (XLS, XLSX) with support for mappings, formatters, and handling large datasets. Working with less dependencies, avoid future breaks & conclusions.", + "type" : "library", + "license" : "MIT", + "autoload" : { + "psr-4" : { + "Zuko\\Flex2Cell\\" : "src/" }, - "authors": [ - { - "name": "Zuko", - "email": "tansautn@gmail.com" - } - ], - "minimum-stability": "stable", - "prefer-stable": true, - "require": { - "php": "^7.0|^8.0", - "phpoffice/phpspreadsheet": "^1.29" - }, - "require-dev": { - "laravel/pint": "^1.18" - }, - "extra": { - "laravel": { - "providers": [ - "Zuko\\Flex2Cell\\Flex2CellServiceProvider" - ] - } - }, - "config": { - "sort-packages": true - }, - "support": { - "issues": "https://github.com/ultra-bugs/flex2cell/issues", - "source": "https://github.com/ultra-bugs/flex2cell" + "files" : [ + "src/aliases.php" + ] + }, + "authors" : [ + { + "name" : "Zuko", + "email" : "tansautn@gmail.com" + } + ], + "minimum-stability" : "stable", + "prefer-stable" : true, + "require" : { + "php" : ">=7.0 <9", + "phpoffice/phpspreadsheet" : "^1.29", + "ext-ctype" : "*" + }, + "require-dev" : { + "laravel/pint" : "^1.18" + }, + "extra" : { + "laravel" : { + "providers" : [ + "Zuko\\Flex2Cell\\Flex2CellServiceProvider" + ] } + }, + "config" : { + "sort-packages" : true + }, + "support" : { + "issues" : "https://github.com/ultra-bugs/flex2cell/issues", + "source" : "https://github.com/ultra-bugs/flex2cell" + } } diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..97073a2 --- /dev/null +++ b/pint.json @@ -0,0 +1,14 @@ +{ + "preset": "laravel", + "rules": { + "simplified_null_return": false, + "no_superfluous_phpdoc_tags": { + "allow_mixed" : true, + "remove_inheritdoc" : false + }, + "new_with_braces": { + "anonymous_class": false, + "named_class": false + } + } +} \ No newline at end of file diff --git a/src/ExcelExporter.php b/src/ExcelExporter.php index f79b417..f9cca19 100644 --- a/src/ExcelExporter.php +++ b/src/ExcelExporter.php @@ -30,15 +30,12 @@ class ExcelExporter use ExcelExportable { export as private exportExcel; } - public static function make() - { - return new static; - } /** * @param array|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection $data - * @param string $filename - * @param array $options + * @param string $filename + * @param array $options + * * @return mixed */ public static function export($data, $filename, array $options = []) @@ -89,14 +86,21 @@ public static function export($data, $filename, array $options = []) // 'E' => ['field' => 'category.name'] // ]) // ->export('export.xlsx'); - return static::make() ->setData($data) ->setHeaders($options['headers'] ?? array_keys(first($data))) - ->setMapping($options['mapping'] ?? array_combine(array_keys(first($data)), array_keys(first($data)))) + ->setMapping($options['mapping'] + ?? + array_combine(array_keys(first($data)), + array_keys(first($data)))) ->setFormatters($options['formatters'] ?? []) ->setColumnMergeRules($options['columnMergeRules'] ?? []) ->setRowMergeRules($options['rowMergeRules'] ?? []) ->exportExcel($filename); } + + public static function make() + { + return new static; + } } diff --git a/src/Flex2CellServiceProvider.php b/src/Flex2CellServiceProvider.php index d5920ed..08257c6 100644 --- a/src/Flex2CellServiceProvider.php +++ b/src/Flex2CellServiceProvider.php @@ -43,7 +43,5 @@ public function register() }); } - public function boot() - { - } + public function boot() {} } diff --git a/src/Traits/ExcelExportable.php b/src/Traits/ExcelExportable.php index b191e1d..b18b9a3 100644 --- a/src/Traits/ExcelExportable.php +++ b/src/Traits/ExcelExportable.php @@ -29,6 +29,8 @@ namespace Zuko\Flex2Cell\Traits; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; @@ -46,13 +48,13 @@ trait ExcelExportable use HasExportMerging; protected $data; - protected $headers = []; - protected $subHeaders = []; - protected $mapping = []; - protected $hiddens = []; + protected $headers = []; + protected $subHeaders = []; + protected $mapping = []; + protected $hiddens = []; protected $metaSettings = []; - protected $chunkSize = 1000; - protected $appendMode = false; + protected $chunkSize = 1000; + protected $appendMode = false; /** * @var bool */ @@ -70,6 +72,7 @@ trait ExcelExportable public function setData($data) { $this->data = $data; + return $this; } @@ -83,6 +86,7 @@ public function setData($data) public function setHeaders(array $headers) { $this->headers = $headers; + return $this; } @@ -96,6 +100,7 @@ public function setHeaders(array $headers) public function setSubHeaders(array $subHeaders) { $this->subHeaders = $subHeaders; + return $this; } @@ -110,6 +115,7 @@ public function setSubHeaders(array $subHeaders) public function setMapping(array $mapping) { $this->mapping = $mapping; + return $this; } @@ -123,6 +129,7 @@ public function setMapping(array $mapping) public function setHiddens(array $hiddens) { $this->hiddens = $hiddens; + return $this; } @@ -142,6 +149,7 @@ public function setHiddens(array $hiddens) public function setMetaSettings(array $metaSettings) { $this->metaSettings = $metaSettings; + return $this; } @@ -159,6 +167,7 @@ public function setMetaSettings(array $metaSettings) public function setChunkSize(int $chunkSize) { $this->chunkSize = $chunkSize; + return $this; } @@ -173,6 +182,7 @@ public function setChunkSize(int $chunkSize) public function setAppendMode(bool $appendMode) { $this->appendMode = $appendMode; + return $this; } @@ -190,6 +200,7 @@ public function setAppendMode(bool $appendMode) public function setSkipHeader(bool $skipHeader) { $this->skipHeader = $skipHeader; + return $this; } @@ -204,26 +215,20 @@ public function export(string $filename) { $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - if (!$this->appendMode || !$this->skipHeader) { $this->writeHeaders($sheet); } - $rowIndex = $this->appendMode ? $sheet->getHighestRow() + 1 : 3; // Start from row 3 due to double header - - if ($this->data instanceof \Illuminate\Support\Collection || $this->data instanceof \Illuminate\Database\Eloquent\Model) { + if ($this->data instanceof Collection || $this->data instanceof Model) { $this->data = $this->data->toArray(); } - foreach (array_chunk($this->data, $this->chunkSize) as $chunk) { foreach ($chunk as $row) { $this->writeRow($sheet, $row, $rowIndex++); } } - $this->applyMerging($sheet); $this->applyMetaSettings($spreadsheet); - $writer = new Xlsx($spreadsheet); $writer->save($filename); } @@ -249,58 +254,13 @@ protected function writeHeaders($sheet) } } - /** - * Write a single row of data to the spreadsheet. - * - * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet The worksheet to write the row to. - * @param array $row The row of data to write. - * @param int $rowIndex The index of the row to write. - * - * @return void - */ - protected function writeRow($sheet, $row, $rowIndex) - { - $columnIndex = 1; - foreach ($this->mapping as $key => $header) { - if (!in_array($header, $this->hiddens, true)) { - $value = $this->getValue($row, $key); - $value = $this->formatValue($header, $value); - $sheet->setCellValue([$columnIndex++, $rowIndex], $value); - } - } - } - - /** - * Apply the meta settings to the spreadsheet. - * - * The meta settings are applied to the spreadsheet properties. The - * supported meta settings are: - * - * - `author`: The author of the spreadsheet. - * - `title`: The title of the spreadsheet. - * - * @param Spreadsheet $spreadsheet The spreadsheet to apply the meta - * settings to. - * - * @return void - */ - protected function applyMetaSettings($spreadsheet) - { - if (isset($this->metaSettings['author'])) { - $spreadsheet->getProperties()->setCreator($this->metaSettings['author']); - } - if (isset($this->metaSettings['title'])) { - $spreadsheet->getProperties()->setTitle($this->metaSettings['title']); - } - // more meta settings as needed in the future - } - /** * Get a header value from the headers array. * * If the header does not exist, the value passed as an argument is returned. * * @param string $header The header for which to get the value + * * @return string The header value */ protected function getHeader($header) @@ -314,6 +274,7 @@ protected function getHeader($header) * If the sub-header does not exist, an empty string is returned. * * @param string $header The header for which to get the sub-header value + * * @return string The sub-header value */ protected function getSubHeader($header) @@ -321,13 +282,35 @@ protected function getSubHeader($header) return $this->subHeaders[$header] ?? ''; } + /** + * Write a single row of data to the spreadsheet. + * + * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet The worksheet to write the row to. + * @param array $row The row of data to write. + * @param int $rowIndex The index of the row to write. + * + * @return void + */ + protected function writeRow($sheet, $row, $rowIndex) + { + $columnIndex = 1; + foreach ($this->mapping as $key => $header) { + if (!in_array($header, $this->hiddens, true)) { + $value = $this->getValue($row, $key); + $value = $this->formatValue($header, $value); + $sheet->setCellValue([$columnIndex++, $rowIndex], $value); + } + } + } + /** * Get a value from the data row for export. * * This method is called once for each value that is exported. * - * @param array $row + * @param array $row * @param string $key + * * @return mixed */ protected function getValue($row, $key) @@ -335,6 +318,34 @@ protected function getValue($row, $key) return $this->dataGet($row, $key); } + /** + * Get an item from an array or object using "dot" notation. + * + * @param mixed $target + * @param string|array|int|null $key + * @param mixed $default + * + * @return mixed + */ + protected function dataGet($target, $key, $default = null) + { + if (is_null($key)) { + return $target; + } + $key = is_array($key) ? $key : explode('.', $key); + foreach ($key as $segment) { + if (is_array($target) && array_key_exists($segment, $target)) { + $target = $target[$segment]; + } elseif (is_object($target) && isset($target->{$segment})) { + $target = $target->{$segment}; + } else { + return $default; + } + } + + return $target; + } + /** * Format a value for export. * @@ -344,7 +355,7 @@ protected function getValue($row, $key) * behavior. * * @param string $mappingKey The key of the mapped column that is being exported. - * @param mixed $value The value that is being exported. + * @param mixed $value The value that is being exported. * * @return mixed The formatted value. */ @@ -353,10 +364,36 @@ protected function formatValue($mappingKey, $value) return $this->parentFormat($mappingKey, $value); } + /** + * Apply the meta settings to the spreadsheet. + * + * The meta settings are applied to the spreadsheet properties. The + * supported meta settings are: + * + * - `author`: The author of the spreadsheet. + * - `title`: The title of the spreadsheet. + * + * @param Spreadsheet $spreadsheet The spreadsheet to apply the meta + * settings to. + * + * @return void + */ + protected function applyMetaSettings($spreadsheet) + { + if (isset($this->metaSettings['author'])) { + $spreadsheet->getProperties()->setCreator($this->metaSettings['author']); + } + if (isset($this->metaSettings['title'])) { + $spreadsheet->getProperties()->setTitle($this->metaSettings['title']); + } + // more meta settings as needed in the future + } + /** * Get the column letter for a mapping key. * * @param string $mappingKey + * * @return string */ protected function getColumnLetter($mappingKey) @@ -365,6 +402,7 @@ protected function getColumnLetter($mappingKey) $index = array_search($mappingKey, array_keys($this->mapping)); $this->columnLetters[$mappingKey] = Coordinate::stringFromColumnIndex($index + 1); } + return $this->columnLetters[$mappingKey]; } @@ -372,6 +410,7 @@ protected function getColumnLetter($mappingKey) * Get the mapping key from a header. * * @param string $header The header + * * @return string The mapping key if found, null otherwise */ protected function getMappingKeyFromHeader($header) @@ -383,39 +422,11 @@ protected function getMappingKeyFromHeader($header) * Get a header from a mapping key. * * @param string $mappingKey The mapping key + * * @return string The header if found, null otherwise */ protected function getHeaderFromMappingKey($mappingKey) { return $this->mapping[$mappingKey] ?? null; } - - /** - * Get an item from an array or object using "dot" notation. - * - * @param mixed $target - * @param string|array|int|null $key - * @param mixed $default - * @return mixed - */ - protected function dataGet($target, $key, $default = null) - { - if (is_null($key)) { - return $target; - } - - $key = is_array($key) ? $key : explode('.', $key); - - foreach ($key as $segment) { - if (is_array($target) && array_key_exists($segment, $target)) { - $target = $target[$segment]; - } elseif (is_object($target) && isset($target->{$segment})) { - $target = $target->{$segment}; - } else { - return $default; - } - } - - return $target; - } } diff --git a/src/Traits/HasExportAttributes.php b/src/Traits/HasExportAttributes.php index 405bd83..02ca045 100644 --- a/src/Traits/HasExportAttributes.php +++ b/src/Traits/HasExportAttributes.php @@ -62,8 +62,10 @@ public function setFormatters(array $formatters) $this->formatters[$key] = $formatter; } } + return $this; } + /** * Format a value for export. * @@ -73,7 +75,7 @@ public function setFormatters(array $formatters) * behavior. * * @param string $mappingKey The key of the mapped column that is being exported. - * @param mixed $value The value that is being exported. + * @param mixed $value The value that is being exported. * * @return mixed The formatted value. */ @@ -85,6 +87,7 @@ protected function formatValue($mappingKey, $value) if (method_exists($this, 'format' . str_replace('.', '', ucwords($mappingKey, '.')) . 'Attribute')) { return $this->{'format' . str_replace('.', '', ucwords($mappingKey, '.')) . 'Attribute'}($value); } + return $value; } diff --git a/src/Traits/HasExportMerging.php b/src/Traits/HasExportMerging.php index 4079c42..92ff43b 100644 --- a/src/Traits/HasExportMerging.php +++ b/src/Traits/HasExportMerging.php @@ -28,6 +28,7 @@ namespace Zuko\Flex2Cell\Traits; + use PhpOffice\PhpSpreadsheet\Cell\Coordinate; /** @@ -38,7 +39,7 @@ trait HasExportMerging { protected $columnMergeRules = []; - protected $rowMergeRules = []; + protected $rowMergeRules = []; public function setColumnMergeRules(array $rules) { @@ -52,6 +53,7 @@ public function setColumnMergeRules(array $rules) $rule['shiftDown'] = $rule['shiftDown'] ?? false; } $this->columnMergeRules = $rules; + return $this; } @@ -64,6 +66,7 @@ public function setRowMergeRules(array $rules) $this->rowMergeRules[$key] = $rule; } } + return $this; } @@ -74,10 +77,9 @@ protected function applyColumnMerging($sheet) $endColumn = $rule['end']; $sheet->mergeCells($startColumn . '1:' . $endColumn . '1'); $sheet->setCellValue($startColumn . '1', $rule['label']); - if ($rule['shiftDown']) { $sheet->insertNewRowBefore(2); - for ($col = Coordinate::columnIndexFromString($startColumn); $col <= Coordinate::columnIndexFromString($endColumn); $col++) { + for ($col = Coordinate::columnIndexFromString($startColumn);$col <= Coordinate::columnIndexFromString($endColumn);$col++) { $letter = Coordinate::stringFromColumnIndex($col); $originalHeader = $sheet->getCell($letter . '3')->getValue(); $sheet->setCellValue($letter . '2', $originalHeader); @@ -93,7 +95,7 @@ protected function applyRowMerging($sheet) $columnLetter = ctype_alpha($column) ? $column : $this->getColumnLetter($rule['field']); $startRow = 2; $currentValue = null; - for ($row = $startRow; $row <= $lastRow; $row++) { + for ($row = $startRow;$row <= $lastRow;$row++) { $cellValue = $sheet->getCell($columnLetter . $row)->getValue(); if ($cellValue !== $currentValue) { if ($currentValue !== null) { diff --git a/src/aliases.php b/src/aliases.php index 8396845..01b6655 100644 --- a/src/aliases.php +++ b/src/aliases.php @@ -14,7 +14,6 @@ * * - - All Rights Reserved - - * * * * * * * * * * * * * * * * * * * * * * * */ - /** * -------------------------------------------------------------------------- * @@ -25,8 +24,7 @@ * @FILE : aliases.php * @CREATED : 14:08 , 13/Oct/2024 */ -(static function () -{ +(static function () { $classes = []; $namespaces = [ 'Flex2cell',