diff --git a/src/FastExcelWriter/Sheet.php b/src/FastExcelWriter/Sheet.php index 183957a..90168e5 100644 --- a/src/FastExcelWriter/Sheet.php +++ b/src/FastExcelWriter/Sheet.php @@ -83,7 +83,7 @@ class Sheet public array $colFormulas = []; public array $colStyles = []; - protected array $colSettings = []; + protected array $colAttributes = []; // minimal with of columns protected array $colMinWidths = []; @@ -691,7 +691,7 @@ public function setColVisible($col, bool $val): Sheet $colIndexes = Excel::colIndexRange($col); foreach($colIndexes as $colIdx) { if ($colIdx >= 0) { - $this->colSettings[$colIdx]['hidden'] = (int)$val; + $this->colAttributes[$colIdx]['hidden'] = (int)$val; } } @@ -731,12 +731,12 @@ public function setColWidth($col, $width, ?bool $min = false): Sheet if (is_numeric($width)) { if ($min) { $this->colMinWidths[$colIdx] = $width; - if (!isset($this->colSettings[$colIdx]['width']) || $this->colSettings[$colIdx]['width'] < $width) { - $this->colSettings[$colIdx]['width'] = $width; + if (!isset($this->colAttributes[$colIdx]['width']) || $this->colAttributes[$colIdx]['width'] < $width) { + $this->colAttributes[$colIdx]['width'] = $width; } } elseif (empty($this->colMinWidths[$colIdx]) || $this->colMinWidths[$colIdx] <= $width) { - $this->colSettings[$colIdx]['width'] = $width; + $this->colAttributes[$colIdx]['width'] = $width; } } } @@ -819,20 +819,23 @@ public function setColMinWidths(array $widths): Sheet /** * @return array */ - public function getColSettings(): array + public function getColAttributes(): array { $result = []; - if ($this->colSettings) { - foreach ($this->colSettings as $colIdx => $settings) { - $result[$colIdx] = [ - 'min' => $colIdx + 1, - 'max' => $colIdx + 1, - ]; - if (isset($settings['width'])) { - $result[$colIdx]['width'] = number_format($settings['width'], 6, '.', ''); + if ($this->colAttributes) { + foreach ($this->colAttributes as $colIdx => $attributes) { + $result[$colIdx] = $attributes; + if (!isset($attributes)) { + $result[$colIdx]['min'] = $colIdx + 1; + } + if (!isset($attributes)) { + $result[$colIdx]['max'] = $colIdx + 1; + } + if (isset($attributes['width'])) { + $result[$colIdx]['width'] = number_format($attributes['width'], 6, '.', ''); $result[$colIdx]['customWidth'] = '1'; } - if (isset($settings['hidden'])) { + if (isset($attributes['hidden'])) { $result[$colIdx]['hidden'] = '1'; } } @@ -842,6 +845,17 @@ public function getColSettings(): array return $result; } + /** + * @param int $colIdx + * @param array $settings + * + * @return void + */ + public function _setColAttributes(int $colIdx, array $settings) + { + $this->colAttributes[$colIdx] = $settings; + } + /** * Set style of single or multiple column(s) * @@ -1217,67 +1231,74 @@ protected function _writeRow(?Writer $writer, array $row = [], array $rowOptions $styleStack = [$baseStyle]; } - if (!empty($this->rowStyles[$rowIdx])) { - $styleStack[] = $this->rowStyles[$rowIdx]; - } - if (!empty($this->cells['styles'][$rowIdx][$colIdx])) { - $styleStack[] = $this->cells['styles'][$rowIdx][$colIdx]; - } - if ($rowOptions) { - $styleStack[] = $rowOptions; - } - if (!empty($cellsOptions[$colIdx])) { - $styleStack[] = $cellsOptions[$colIdx]; - } - if (count($styleStack) > 1) { - $cellStyle = Style::mergeStyles($styleStack); + if (isset($cellsOptions[$colIdx]['_xf_id'])) { + $cellStyleIdx = $cellsOptions[$colIdx]['_xf_id']; + $numberFormatType = 'n_auto'; } else { - $cellStyle = $styleStack ? $styleStack[0] : []; - } - if (!empty($cellStyle['format']['format-pattern']) && !empty($this->excel->style->defaultFormatStyles[$cellStyle['format']['format-pattern']])) { - $cellStyle = Style::mergeStyles([$this->excel->style->defaultFormatStyles[$cellStyle['format']['format-pattern']], $cellStyle]); - } + // Define cell style index and number format + if (!empty($this->rowStyles[$rowIdx])) { + $styleStack[] = $this->rowStyles[$rowIdx]; + } + if (!empty($this->cells['styles'][$rowIdx][$colIdx])) { + $styleStack[] = $this->cells['styles'][$rowIdx][$colIdx]; + } + if ($rowOptions) { + $styleStack[] = $rowOptions; + } + if (!empty($cellsOptions[$colIdx])) { + $styleStack[] = $cellsOptions[$colIdx]; + } + if (count($styleStack) > 1) { + $cellStyle = Style::mergeStyles($styleStack); + } + else { + $cellStyle = $styleStack ? $styleStack[0] : []; + } + if (!empty($cellStyle['format']['format-pattern']) && !empty($this->excel->style->defaultFormatStyles[$cellStyle['format']['format-pattern']])) { + $cellStyle = Style::mergeStyles([$this->excel->style->defaultFormatStyles[$cellStyle['format']['format-pattern']], $cellStyle]); + } - if (isset($cellStyle['hyperlink'])) { - if (!empty($cellStyle['hyperlink'])) { - if (is_string($cellStyle['hyperlink'])) { - $link = $cellStyle['hyperlink']; - } - else { - $link = $cellValue; - } - $cellValue = [ - 'shared_value' => $cellValue, - 'shared_index' => $this->excel->addSharedString($cellValue), - ]; - $this->_addExternalLink(Excel::cellAddress($rowIdx + 1, $colIdx + 1), $link); - if (!empty($this->excel->style->hyperlinkStyle)) { - $cellStyle = Style::mergeStyles([$this->excel->style->hyperlinkStyle, $cellStyle]); + if (isset($cellStyle['hyperlink'])) { + if (!empty($cellStyle['hyperlink'])) { + if (is_string($cellStyle['hyperlink'])) { + $link = $cellStyle['hyperlink']; + } + else { + $link = $cellValue; + } + $cellValue = [ + 'shared_value' => $cellValue, + 'shared_index' => $this->excel->addSharedString($cellValue), + ]; + $this->_addExternalLink(Excel::cellAddress($rowIdx + 1, $colIdx + 1), $link); + if (!empty($this->excel->style->hyperlinkStyle)) { + $cellStyle = Style::mergeStyles([$this->excel->style->hyperlinkStyle, $cellStyle]); + } } + unset($cellStyle['hyperlink']); } - unset($cellStyle['hyperlink']); - } - $styleHash = json_encode($cellStyle); - if (!isset($_styleCache[$styleHash])) { - $cellStyleIdx = $this->excel->style->addStyle($cellStyle, $resultStyle); - $_styleCache[$styleHash] = ['cell_style' => $cellStyle, 'result_style' => $resultStyle, 'style_idx' => $cellStyleIdx]; - } - else { - $resultStyle = $_styleCache[$styleHash]['result_style']; - $cellStyleIdx = $_styleCache[$styleHash]['style_idx']; - } + $styleHash = json_encode($cellStyle); + if (!isset($_styleCache[$styleHash])) { + $cellStyleIdx = $this->excel->style->addStyle($cellStyle, $resultStyle); + $_styleCache[$styleHash] = ['cell_style' => $cellStyle, 'result_style' => $resultStyle, 'style_idx' => $cellStyleIdx]; + } + else { + $resultStyle = $_styleCache[$styleHash]['result_style']; + $cellStyleIdx = $_styleCache[$styleHash]['style_idx']; + } - $numberFormat = $resultStyle['number_format']; - $numberFormatType = $resultStyle['number_format_type']; + $numberFormat = $resultStyle['number_format']; + $numberFormatType = $resultStyle['number_format_type']; - if (!empty($cellStyle['options']['width-auto'])) { - $this->_columnWidth($colIdx, $cellValue, $numberFormat, $resultStyle ?? []); - } + if (!empty($cellStyle['options']['width-auto'])) { + $this->_columnWidth($colIdx, $cellValue, $numberFormat, $resultStyle ?? []); + } - if (!$writer) { - $writer = $this->excel->getWriter(); + if (!$writer) { + $writer = $this->excel->getWriter(); + } } if ($cellValue !== null || $cellStyleIdx !== 0 || $numberFormatType !== 'n_auto') { $writer->_writeCell($this->fileWriter, $rowIdx + 1, $colIdx + 1, $cellValue, $numberFormatType, $cellStyleIdx); @@ -1415,8 +1436,8 @@ protected function _columnWidth(int $colIdx, $cellValue, $numberFormat, $style) } $cache[$key] = $len; } - if ((empty($this->colSettings[$colIdx]['width']) || $this->colSettings[$colIdx]['width'] < $len) && (empty($this->colMinWidths[$colIdx]) || $this->colMinWidths[$colIdx] <= $len)) { - $this->colSettings[$colIdx]['width'] = $len; + if ((empty($this->colAttributes[$colIdx]['width']) || $this->colAttributes[$colIdx]['width'] < $len) && (empty($this->colMinWidths[$colIdx]) || $this->colMinWidths[$colIdx] <= $len)) { + $this->colAttributes[$colIdx]['width'] = $len; } } } @@ -2313,6 +2334,23 @@ public function setCellStyle(string $cellAddress, $style, ?bool $mergeStyles = f return $this->setStyle($cellAddress, $style, $mergeStyles); } + /** + * @param string $cellAddress + * @param int $styleIdx + * + * @return $this + */ + public function _setStyleIdx(string $cellAddress, int $styleIdx): Sheet + { + $dimension = $this->_rangeDimension($cellAddress); + if ($dimension['rowNum1'] <= $this->rowCountWritten) { + throw new Exception('Row number must be greater then written rows'); + } + $this->cells['styles'][$dimension['rowIndex']][$dimension['colIndex']]['_xf_id'] = $styleIdx; + + return $this; + } + /** * @param string $cellAddr * @param array $style diff --git a/src/FastExcelWriter/Writer.php b/src/FastExcelWriter/Writer.php index 6189235..8341769 100644 --- a/src/FastExcelWriter/Writer.php +++ b/src/FastExcelWriter/Writer.php @@ -334,7 +334,7 @@ public function saveToFile(string $fileName, ?bool $overWrite = true, ?array $me 'rel_id' => ['workbook' => 0], ]; - $sheets = $this->excel->getSheets();//$this->writeSheetDataBegin($sheet); + $sheets = $this->excel->getSheets(); if (empty($sheets)) { ExceptionFile::throwNew('No worksheets defined'); } @@ -400,19 +400,39 @@ public function saveToFile(string $fileName, ?bool $overWrite = true, ?array $me $this->writeEntriesToZip('xl/'); $this->writeEntriesToZip(''); -/* - if (!$zip->addFile($this->tempFiles[$entry], $entry)) { - ExceptionFile::throwNew('Could not write entry "%s" to zip', $entry); + $this->zip->close(); + + return true; + } + + public function _replaceSheets($inputFile, $outputFile): bool + { + if (!copy($inputFile, $outputFile)) { + ExceptionFile::throwNew('Cannot to write file "%s"', $outputFile); } - if (isset($struct['-'])) { - foreach ($struct['-'] as $entry) { - if (!$zip->addFile($this->tempFiles[$entry], $entry)) { - ExceptionFile::throwNew('Could not write entry "%s" to zip', $entry); + + $this->zip = new \ZipArchive(); + if (!$this->zip->open($outputFile)) { + ExceptionFile::throwNew('Unable to open zip "%s"', $outputFile); + } + $entryList = []; + for ($i = 0; $i < $this->zip->numFiles; $i++) { + $entryList[$i] = $this->zip->getNameIndex($i); + } + $sheets = $this->excel->getSheets(); + $relationShips = []; + $this->_writeSheetsFiles($sheets, $relationShips); + foreach ($entryList as $index => $name) { + if (strpos($name, 'xl/worksheets/sheet') === 0 && !empty($this->tempFiles['zip'][$name])) { + if (version_compare(PHP_VERSION, '8.3.0') >= 0) { + $this->zip->replaceFile($this->tempFiles['zip'][$name], $index); + } + else { + $this->zip->addFile($this->tempFiles['zip'][$name], $name); } } - unset($struct['-']); } -*/ + $this->zip->close(); return true; @@ -795,7 +815,7 @@ protected function _writeSheetHead(Sheet $sheet): WriterBuffer $fileWriter->write(''); - $cols = $sheet->getColSettings(); + $cols = $sheet->getColAttributes(); if ($cols) { $fileWriter->write(''); foreach ($cols as $colSettings) { @@ -969,7 +989,7 @@ protected function _convertFormula($formula, $baseAddress): string $formula = (string) preg_replace(self::XLWSREGEXP, '_xlws.$1(', $formula); } - return $formula; + return ($formula[0] === '=') ? mb_substr($formula, 1) : $formula; } /**