From f8baef148f0ffb64ad4270e85c5932ff6e63114c Mon Sep 17 00:00:00 2001 From: Salavat Salakhutdinov Date: Fri, 30 Oct 2020 18:47:08 +0300 Subject: [PATCH] update xlsx reader --- .../Reader/XLSX/Helper/CellValueFormatter.php | 16 +++++++++++ src/Spout/Reader/XLSX/RowIterator.php | 2 ++ tests/Spout/Reader/XLSX/ReaderTest.php | 28 +++++++++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php b/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php index 169c395..baf39a2 100644 --- a/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php +++ b/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php @@ -23,6 +23,7 @@ class CellValueFormatter /** Definition of XML nodes names used to parse data */ const XML_NODE_VALUE = 'v'; + const XML_NODE_FORMULA = 'f'; const XML_NODE_INLINE_STRING_VALUE = 't'; /** Definition of XML attributes used to parse data */ @@ -107,6 +108,21 @@ class CellValueFormatter } } + /** + * Returns the cell formula associated to the given XML node. + * + * @param \DOMNode $node + * @return string The formula associated with the cell + */ + public function extractNodeFormula($node) + { + // for cell types having a "f" tag containing the formula. + // if not, the returned formula should be empty string. + $vNode = $node->getElementsByTagName(self::XML_NODE_FORMULA)->item(0); + + return ($vNode !== null) ? $vNode->nodeValue : ''; + } + /** * Returns the cell's string value from a node's nested value node * diff --git a/src/Spout/Reader/XLSX/RowIterator.php b/src/Spout/Reader/XLSX/RowIterator.php index 4af4530..4395f2b 100644 --- a/src/Spout/Reader/XLSX/RowIterator.php +++ b/src/Spout/Reader/XLSX/RowIterator.php @@ -359,7 +359,9 @@ class RowIterator implements IteratorInterface { try { $cellValue = $this->cellValueFormatter->extractAndFormatNodeValue($node); + $cellFormula = $this->cellValueFormatter->extractNodeFormula($node); $cell = $this->entityFactory->createCell($cellValue); + $cell->setFormula($cellFormula); } catch (InvalidValueException $exception) { $cell = $this->entityFactory->createCell($exception->getInvalidValue()); $cell->setType(Cell::TYPE_ERROR); diff --git a/tests/Spout/Reader/XLSX/ReaderTest.php b/tests/Spout/Reader/XLSX/ReaderTest.php index 51a7b0e..2e892c6 100644 --- a/tests/Spout/Reader/XLSX/ReaderTest.php +++ b/tests/Spout/Reader/XLSX/ReaderTest.php @@ -574,6 +574,29 @@ class ReaderTest extends TestCase $this->assertEquals($expectedRows, $allRows); } + /** + * @return void + */ + public function testReadShouldReadFormulas() + { + $allRows = $this->getAllRowsForFile('sheet_with_formulas.xlsx', false, false, false); + + $expectedRows = [ + ['', '', '', ''], + ['', '', 'A2+B2', 'SUM(A:A)'], + ['', '', 'A3+B3', 'SUM(B:B)'], + ]; + + $rowsWithFormulas = array_map(function($row) { + $cells = $row->getCells(); + return array_map(function($cell) { + return $cell->getFormula(); + }, $cells); + }, $allRows); + + $this->assertEquals($expectedRows, $rowsWithFormulas); + } + /** * @return void */ @@ -703,9 +726,10 @@ class ReaderTest extends TestCase * @param string $fileName * @param bool $shouldFormatDates * @param bool $shouldPreserveEmptyRows + * @param bool $shouldConvertToArray * @return array All the read rows the given file */ - private function getAllRowsForFile($fileName, $shouldFormatDates = false, $shouldPreserveEmptyRows = false) + private function getAllRowsForFile($fileName, $shouldFormatDates = false, $shouldPreserveEmptyRows = false, $shouldConvertToArray = true) { $allRows = []; $resourcePath = $this->getResourcePath($fileName); @@ -717,7 +741,7 @@ class ReaderTest extends TestCase foreach ($reader->getSheetIterator() as $sheetIndex => $sheet) { foreach ($sheet->getRowIterator() as $rowIndex => $row) { - $allRows[] = $row->toArray(); + $allRows[] = $shouldConvertToArray ? $row->toArray() : $row; } }