Skip to content

Commit c7622e1

Browse files
committedOct 14, 2024·
Improve column merging
Add field map to formatter method
1 parent 4479805 commit c7622e1

File tree

4 files changed

+63
-20
lines changed

4 files changed

+63
-20
lines changed
 

‎src/Contracts/FormatterInterface.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,18 @@
3636
*/
3737
interface FormatterInterface
3838
{
39-
public function formatValue($value);
39+
/**
40+
* Format a value for export.
41+
*
42+
* This method is called once for each cell value that is exported.
43+
* The default implementation simply returns the value as is,
44+
* but you can override this method in your class to change the
45+
* behavior.
46+
*
47+
* @param mixed $value The value that is being exported.
48+
* @param string $mappingKey The key of the mapped column that is being exported.
49+
*
50+
* @return mixed The formatted value.
51+
*/
52+
public function formatValue($value, $mappingKey);
4053
}

‎src/Traits/ExcelExportable.php

+12-9
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
namespace Zuko\Flex2Cell\Traits;
3030

3131

32-
use Illuminate\Database\Eloquent\Model;
33-
use Illuminate\Support\Collection;
3432
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
3533
use PhpOffice\PhpSpreadsheet\Spreadsheet;
3634
use PhpOffice\PhpSpreadsheet\Writer\Xls;
@@ -220,7 +218,9 @@ public function export(string $filename)
220218
$this->writeHeaders($sheet);
221219
}
222220
$rowIndex = $this->appendMode ? $sheet->getHighestRow() + 1 : 3; // Start from row 3 due to double header
223-
if ($this->data instanceof Collection || $this->data instanceof Model) {
221+
/** @noinspection PhpUndefinedClassInspection */
222+
/** @noinspection PhpUndefinedNamespaceInspection */
223+
if ($this->data instanceof \Illuminate\Support\Collection || $this->data instanceof \Illuminate\Database\Eloquent\Model) {
224224
$this->data = $this->data->toArray();
225225
}
226226
foreach (array_chunk($this->data, $this->chunkSize) as $chunk) {
@@ -259,12 +259,15 @@ public function export(string $filename)
259259
*/
260260
protected function writeHeaders($sheet)
261261
{
262+
$this->headerRowIndex = 1; // Start with assuming headers are in the first row
262263
$columnIndex = 1;
263264
foreach ($this->headers as $header) {
264265
if (!in_array($header, $this->hiddens, true)) {
265-
$sheet->setCellValue([$columnIndex, 1], $this->getHeader($header));
266+
$displayHeader = $this->getHeader($header);
267+
$sheet->setCellValue([$columnIndex, $this->headerRowIndex], $displayHeader);
266268
if (isset($this->subHeaders[$header])) {
267-
$sheet->setCellValue([$columnIndex, 2], $this->getSubHeader($header));
269+
$sheet->setCellValue([$columnIndex, $this->headerRowIndex + 1], $this->getSubHeader($header));
270+
$this->headerRowIndex = 2; // If we have subheaders, main headers are now in row 2
268271
}
269272
$columnIndex++;
270273
}
@@ -428,7 +431,7 @@ protected function getColumnLetter($mappingKey)
428431
*
429432
* @param string $header The header
430433
*
431-
* @return string The mapping key if found, null otherwise
434+
* @return string|null The mapping key if found, null otherwise
432435
*/
433436
protected function getMappingKeyFromHeader($header)
434437
{
@@ -440,7 +443,7 @@ protected function getMappingKeyFromHeader($header)
440443
*
441444
* @param string $mappingKey The mapping key
442445
*
443-
* @return string The header if found, null otherwise
446+
* @return string|null The header if found, null otherwise
444447
*/
445448
protected function getHeaderFromMappingKey($mappingKey)
446449
{
@@ -450,7 +453,7 @@ protected function getHeaderFromMappingKey($mappingKey)
450453
private static function first(array $array, $callback = null, $default = null) {
451454
if (is_null($callback)) {
452455
if (empty($array)) {
453-
return value($default);
456+
return $default;
454457
}
455458

456459
foreach ($array as $item) {
@@ -464,6 +467,6 @@ private static function first(array $array, $callback = null, $default = null) {
464467
}
465468
}
466469

467-
return value($default);
470+
return $default;
468471
}
469472
}

‎src/Traits/HasExportAttributes.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
namespace Zuko\Flex2Cell\Traits;
3030

3131

32+
use Zuko\Flex2Cell\Contracts\FormatterInterface;
33+
3234
/**
3335
* Class HasExportAttributes
3436
*
@@ -53,7 +55,7 @@ trait HasExportAttributes
5355
public function setFormatters(array $formatters)
5456
{
5557
foreach ($formatters as $key => $formatter) {
56-
if (is_string($formatter) && class_exists($formatter)) {
58+
if (is_string($formatter) && class_exists($formatter) &&(new $formatter()) instanceof FormatterInterface) {
5759
$formatter = new $formatter();
5860
}
5961
if (is_object($formatter) && method_exists($formatter, 'formatValue')) {
@@ -82,7 +84,7 @@ public function setFormatters(array $formatters)
8284
protected function formatValue($mappingKey, $value)
8385
{
8486
if (isset($this->formatters[$mappingKey])) {
85-
return call_user_func($this->formatters[$mappingKey], $value);
87+
return call_user_func($this->formatters[$mappingKey], [$value, $mappingKey]);
8688
}
8789
if (method_exists($this, 'format' . str_replace('.', '', ucwords($mappingKey, '.')) . 'Attribute')) {
8890
return $this->{'format' . str_replace('.', '', ucwords($mappingKey, '.')) . 'Attribute'}($value);

‎src/Traits/HasExportMerging.php

+33-8
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,42 @@ protected function applyMerging($sheet)
7676
}
7777
protected function applyColumnMerging($sheet)
7878
{
79+
$mergedRanges = [];
80+
$hasShifted = false;
7981
foreach ($this->columnMergeRules as $rule) {
8082
$startColumn = $rule['start'];
8183
$endColumn = $rule['end'];
82-
$sheet->mergeCells($startColumn . '1:' . $endColumn . '1');
83-
$sheet->setCellValue($startColumn . '1', $rule['label']);
84-
if ($rule['shiftDown']) {
85-
$sheet->insertNewRowBefore(2);
86-
for ($col = Coordinate::columnIndexFromString($startColumn);$col <= Coordinate::columnIndexFromString($endColumn);$col++) {
87-
$letter = Coordinate::stringFromColumnIndex($col);
88-
$originalHeader = $sheet->getCell($letter . '3')->getValue();
89-
$sheet->setCellValue($letter . '2', $originalHeader);
84+
$targetRow = $this->headerRowIndex;
85+
if ($rule['shiftDown'] ?? false) {
86+
// Insert a new row above the current header row
87+
if(!$hasShifted) {
88+
$sheet->insertNewRowBefore($this->headerRowIndex);
89+
$this->headerRowIndex++;
90+
$targetRow = ($this->headerRowIndex - 1);
91+
$hasShifted = true;
92+
}
93+
// Set the merged header value
94+
$sheet->setCellValue($startColumn . $targetRow, $rule['label']);
95+
96+
// Merge the cells
97+
$sheet->mergeCells($startColumn . $targetRow . ':' . $endColumn . $targetRow);
98+
$startColumn = Coordinate::columnIndexFromString($startColumn);
99+
$endColumn = Coordinate::columnIndexFromString($endColumn);
100+
if(!in_array($ranges = range($startColumn, $endColumn), $mergedRanges, true)){
101+
$mergedRanges[] = $ranges;
102+
}
103+
} else {
104+
// If not shifting down, merge at the current header row
105+
$sheet->mergeCells($startColumn . $this->headerRowIndex . ':' . $endColumn . $this->headerRowIndex);
106+
$sheet->setCellValue($startColumn . $this->headerRowIndex, $rule['label']);
107+
}
108+
}
109+
if($hasShifted){
110+
$flat = array_merge(...$mergedRanges);
111+
foreach ($this->headers as $index => $header) {
112+
if(!in_array($index, $flat, true)){
113+
$curLetter = Coordinate::stringFromColumnIndex($index);
114+
$sheet->mergeCells($curLetter . $this->headerRowIndex . ':' . $curLetter . ($this->headerRowIndex - 1));
90115
}
91116
}
92117
}

0 commit comments

Comments
 (0)
Please sign in to comment.