update xlsx writer

This commit is contained in:
Salavat Salakhutdinov 2020-10-30 18:46:52 +03:00
parent ab973cab34
commit 7f26167be8
3 changed files with 79 additions and 8 deletions

View File

@ -64,14 +64,21 @@ class Cell
*/ */
protected $style; protected $style;
/**
* The cell formula
* @var string|null
*/
protected $formula;
/** /**
* @param $value mixed * @param $value mixed
* @param Style|null $style * @param Style|null $style
*/ */
public function __construct($value, Style $style = null) public function __construct($value, ?Style $style = null, $formula = null)
{ {
$this->setValue($value); $this->setValue($value);
$this->setStyle($style); $this->setStyle($style);
$this->setFormula($formula);
} }
/** /**
@ -131,6 +138,22 @@ class Cell
$this->type = $type; $this->type = $type;
} }
/**
* @return string|null
*/
public function getFormula()
{
return $this->formula;
}
/**
* @param string|null $formula
*/
public function setFormula(?string $formula)
{
$this->formula = $formula;
}
/** /**
* Get the current value type * Get the current value type
* *

View File

@ -211,18 +211,21 @@ EOD;
$columnLetters = CellHelper::getColumnLettersFromColumnIndex($columnIndexZeroBased); $columnLetters = CellHelper::getColumnLettersFromColumnIndex($columnIndexZeroBased);
$cellXML = '<c r="' . $columnLetters . $rowIndexOneBased . '"'; $cellXML = '<c r="' . $columnLetters . $rowIndexOneBased . '"';
$cellXML .= ' s="' . $styleId . '"'; $cellXML .= ' s="' . $styleId . '"';
$cellFormulaXMLFragment = $this->getCellFormulaXMLFragment($cell);
if ($cell->isString()) { if ($cell->isString()) {
$cellXML .= $this->getCellXMLFragmentForNonEmptyString($cell->getValue()); $cellXML .= $this->getCellXMLFragmentForNonEmptyString($cell);
} elseif ($cell->isBoolean()) { } elseif ($cell->isBoolean()) {
$cellXML .= ' t="b"><v>' . (int) ($cell->getValue()) . '</v></c>'; $cellXML .= ' t="b">' . $cellFormulaXMLFragment . '<v>' . (int) ($cell->getValue()) . '</v></c>';
} elseif ($cell->isNumeric()) { } elseif ($cell->isNumeric()) {
$cellXML .= '><v>' . $cell->getValue() . '</v></c>'; $cellXML .= '>' . $cellFormulaXMLFragment . '<v>' . $cell->getValue() . '</v></c>';
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) { } elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
// only writes the error value if it's a string // only writes the error value if it's a string
$cellXML .= ' t="e"><v>' . $cell->getValueEvenIfError() . '</v></c>'; $cellXML .= ' t="e"><v>' . $cell->getValueEvenIfError() . '</v></c>';
} elseif ($cell->isEmpty()) { } elseif ($cell->isEmpty()) {
if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) { if ($cellFormulaXMLFragment) {
$cellXML .= '>' . $cellFormulaXMLFragment . '<v></v></c>';
} else if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) {
$cellXML .= '/>'; $cellXML .= '/>';
} else { } else {
// don't write empty cells that do no need styling // don't write empty cells that do no need styling
@ -237,19 +240,37 @@ EOD;
} }
/** /**
* Returns the XML fragment for a cell containing a non empty string * Returns the XML fragment for a cell formula
* *
* @param string $cellValue The cell value * @param string $cellValue The cell value
* @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell * @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell
* @return string The XML fragment representing the cell * @return string The XML fragment representing the cell
*/ */
private function getCellXMLFragmentForNonEmptyString($cellValue) private function getCellFormulaXMLFragment($cell)
{ {
$cellFormula = $cell->getFormula();
return $cellFormula ? '<f>' . $cellFormula . '</f>' : '';
}
/**
* Returns the XML fragment for a cell containing a non empty string
*
* @param Cell $cell cell
* @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell
* @return string The XML fragment representing the cell
*/
private function getCellXMLFragmentForNonEmptyString($cell)
{
$cellValue = $cell->getValue();
$cellFormulaXMLFragment = $this->getCellFormulaXMLFragment($cell);
if ($this->stringHelper->getStringLength($cellValue) > self::MAX_CHARACTERS_PER_CELL) { if ($this->stringHelper->getStringLength($cellValue) > self::MAX_CHARACTERS_PER_CELL) {
throw new InvalidArgumentException('Trying to add a value that exceeds the maximum number of characters allowed in a cell (32,767)'); throw new InvalidArgumentException('Trying to add a value that exceeds the maximum number of characters allowed in a cell (32,767)');
} }
if ($this->shouldUseInlineStrings) { if ($cellFormulaXMLFragment) {
$cellXMLFragment = ' t="str">' . $cellFormulaXMLFragment . '<v>' . $cellValue . '</v></c>';
} else if ($this->shouldUseInlineStrings) {
$cellXMLFragment = ' t="inlineStr"><is><t>' . $this->stringsEscaper->escape($cellValue) . '</t></is></c>'; $cellXMLFragment = ' t="inlineStr"><is><t>' . $this->stringsEscaper->escape($cellValue) . '</t></is></c>';
} else { } else {
$sharedStringId = $this->sharedStringsManager->writeString($cellValue); $sharedStringId = $this->sharedStringsManager->writeString($cellValue);

View File

@ -189,6 +189,33 @@ class WriterTest extends TestCase
$this->assertEquals($sheets[1], $writer->getCurrentSheet(), 'The current sheet should be the second one.'); $this->assertEquals($sheets[1], $writer->getCurrentSheet(), 'The current sheet should be the second one.');
} }
/**
* @return void
*/
public function testCellFormula()
{
$fileName = 'test_cell_formula.xlsx';
$rowsAsArray = [
[[1], [3], ['Github link', 'HYPERLINK("https://github.com/","Github link")']],
[[0, 'A1+B1'], [-2, 'A1-B1'], ['Google link', 'HYPERLINK("https://google.com/","Google link")'], ['test']],
];
$rows = array_map(function($rowAsArray) {
return WriterEntityFactory::createRow((array_map(function($cellAsArray) {
return new Cell($cellAsArray[0] ?? "", null, $cellAsArray[1] ?? "");
}, $rowAsArray)));
}, $rowsAsArray);
$this->writeToXLSXFile($rows, $fileName);
foreach ($rows as $row) {
foreach ($row->getCells() as $cell) {
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getValue());
$this->assertInlineDataWasWrittenToSheet($fileName, 1, $cell->getFormula());
}
}
}
/** /**
* @return void * @return void
*/ */