diff --git a/src/Spout/Common/Entity/Cell.php b/src/Spout/Common/Entity/Cell.php
index c1de389..924f880 100644
--- a/src/Spout/Common/Entity/Cell.php
+++ b/src/Spout/Common/Entity/Cell.php
@@ -64,14 +64,21 @@ class Cell
*/
protected $style;
+ /**
+ * The cell formula
+ * @var string|null
+ */
+ protected $formula;
+
/**
* @param $value mixed
* @param Style|null $style
*/
- public function __construct($value, Style $style = null)
+ public function __construct($value, ?Style $style = null, $formula = null)
{
$this->setValue($value);
$this->setStyle($style);
+ $this->setFormula($formula);
}
/**
@@ -131,6 +138,22 @@ class Cell
$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
*
diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php
index 741d0aa..2cca1e7 100644
--- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php
+++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php
@@ -211,18 +211,21 @@ EOD;
$columnLetters = CellHelper::getColumnLettersFromColumnIndex($columnIndexZeroBased);
$cellXML = 'getCellFormulaXMLFragment($cell);
if ($cell->isString()) {
- $cellXML .= $this->getCellXMLFragmentForNonEmptyString($cell->getValue());
+ $cellXML .= $this->getCellXMLFragmentForNonEmptyString($cell);
} elseif ($cell->isBoolean()) {
- $cellXML .= ' t="b">' . (int) ($cell->getValue()) . '';
+ $cellXML .= ' t="b">' . $cellFormulaXMLFragment . '' . (int) ($cell->getValue()) . '';
} elseif ($cell->isNumeric()) {
- $cellXML .= '>' . $cell->getValue() . '';
+ $cellXML .= '>' . $cellFormulaXMLFragment . '' . $cell->getValue() . '';
} elseif ($cell->isError() && is_string($cell->getValueEvenIfError())) {
// only writes the error value if it's a string
$cellXML .= ' t="e">' . $cell->getValueEvenIfError() . '';
} elseif ($cell->isEmpty()) {
- if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) {
+ if ($cellFormulaXMLFragment) {
+ $cellXML .= '>' . $cellFormulaXMLFragment . '';
+ } else if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) {
$cellXML .= '/>';
} else {
// 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
* @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($cellValue)
+ private function getCellFormulaXMLFragment($cell)
{
+ $cellFormula = $cell->getFormula();
+ return $cellFormula ? '' . $cellFormula . '' : '';
+ }
+
+ /**
+ * 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) {
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 . '' . $cellValue . '';
+ } else if ($this->shouldUseInlineStrings) {
$cellXMLFragment = ' t="inlineStr">' . $this->stringsEscaper->escape($cellValue) . '';
} else {
$sharedStringId = $this->sharedStringsManager->writeString($cellValue);
diff --git a/tests/Spout/Writer/XLSX/WriterTest.php b/tests/Spout/Writer/XLSX/WriterTest.php
index 15cc4e4..c00ae54 100644
--- a/tests/Spout/Writer/XLSX/WriterTest.php
+++ b/tests/Spout/Writer/XLSX/WriterTest.php
@@ -189,6 +189,33 @@ class WriterTest extends TestCase
$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
*/