diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 8911a5d4..340f5cd0 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -131,23 +131,6 @@ class Functions return '#Not Yet Implemented'; } - /** - * NULL. - * - * Returns the error value #NULL! - * - * @Deprecated 1.23.0 - * - * @return string #NULL! - * - *@see Information\ExcelError::null() - * Use the null() method in the Information\Error class instead - */ - public static function null() - { - return Information\ExcelError::null(); - } - public static function isMatrixValue($idx) { return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0); @@ -215,6 +198,23 @@ class Functions return $operand; } + /** + * NULL. + * + * Returns the error value #NULL! + * + * @Deprecated 1.23.0 + * + * @return string #NULL! + * + *@see Information\ExcelError::null() + * Use the null() method in the Information\Error class instead + */ + public static function null() + { + return Information\ExcelError::null(); + } + /** * NaN. * @@ -326,7 +326,7 @@ class Functions * * @Deprecated 1.23.0 * - * @return int|string + * @return array|int|string * * @see Information\ExcelError::type() * Use the type() method in the Information\Error class instead @@ -668,7 +668,7 @@ class Functions * @param mixed $cellReference The cell to check * @param ?Cell $cell The current cell (containing this formula) * - * @return bool|string + * @return array|bool|string */ public static function isFormula($cellReference = '', ?Cell $cell = null) { @@ -698,4 +698,13 @@ class Functions { return Worksheet::pregReplace('/:[\\w\$]+$/', '', $coordinate); } + + public static function trimSheetFromCellReference(string $coordinate): string + { + while (strpos($coordinate, '!') !== false) { + $coordinate = substr($coordinate, strpos($coordinate, '!') + 1); + } + + return $coordinate; + } } diff --git a/src/PhpSpreadsheet/Calculation/Information/ExcelError.php b/src/PhpSpreadsheet/Calculation/Information/ExcelError.php index df003d26..98242eb6 100644 --- a/src/PhpSpreadsheet/Calculation/Information/ExcelError.php +++ b/src/PhpSpreadsheet/Calculation/Information/ExcelError.php @@ -2,10 +2,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Information; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; class ExcelError { + use ArrayEnabled; + /** * List of error codes. * @@ -27,11 +29,13 @@ class ExcelError * * @param mixed $value Value to check * - * @return int|string + * @return array|int|string */ public static function type($value = '') { - $value = Functions::flattenSingleValue($value); + if (is_array($value)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value); + } $i = 1; foreach (self::$errorCodes as $errorCode) { diff --git a/src/PhpSpreadsheet/Calculation/Information/Value.php b/src/PhpSpreadsheet/Calculation/Information/Value.php index 21e05d0b..cdb160d7 100644 --- a/src/PhpSpreadsheet/Calculation/Information/Value.php +++ b/src/PhpSpreadsheet/Calculation/Information/Value.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\Cell; +use PhpOffice\PhpSpreadsheet\Cell\Coordinate; class Value { @@ -170,26 +171,36 @@ class Value * @param mixed $cellReference The cell to check * @param ?Cell $cell The current cell (containing this formula) * - * @return bool|string + * @return array|bool|string */ public static function isFormula($cellReference = '', ?Cell $cell = null) { if ($cell === null) { return ExcelError::REF(); } - $cellReference = Functions::expandDefinedName((string) $cellReference, $cell); - $cellReference = Functions::trimTrailingRange($cellReference); - preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellReference, $matches); + $fullCellReference = Functions::expandDefinedName((string) $cellReference, $cell); - $cellReference = $matches[6] . $matches[7]; + if (strpos($cellReference, '!') !== false) { + $cellReference = Functions::trimSheetFromCellReference($cellReference); + $cellReferences = Coordinate::extractAllCellReferencesInRange($cellReference); + if (count($cellReferences) > 1) { + return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $cellReferences, $cell); + } + } + + $fullCellReference = Functions::trimTrailingRange($fullCellReference); + + preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $fullCellReference, $matches); + + $fullCellReference = $matches[6] . $matches[7]; $worksheetName = str_replace("''", "'", trim($matches[2], "'")); $worksheet = (!empty($worksheetName)) ? $cell->getWorksheet()->getParent()->getSheetByName($worksheetName) : $cell->getWorksheet(); - return ($worksheet !== null) ? $worksheet->getCell($cellReference)->isFormula() : ExcelError::REF(); + return ($worksheet !== null) ? $worksheet->getCell($fullCellReference)->isFormula() : ExcelError::REF(); } /** diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 70df0979..87d13104 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -280,7 +280,7 @@ class Cell */ public function getCalculatedValue($resetLog = true) { - if ($this->dataType == DataType::TYPE_FORMULA) { + if ($this->dataType === DataType::TYPE_FORMULA) { try { $index = $this->getWorksheet()->getParent()->getActiveSheetIndex(); $selected = $this->getWorksheet()->getSelectedCells(); @@ -379,20 +379,16 @@ class Cell /** * Identify if the cell contains a formula. - * - * @return bool */ - public function isFormula() + public function isFormula(): bool { - return $this->dataType == DataType::TYPE_FORMULA; + return $this->dataType === DataType::TYPE_FORMULA && $this->getStyle()->getQuotePrefix() === false; } /** * Does this cell contain Data validation rules? - * - * @return bool */ - public function hasDataValidation() + public function hasDataValidation(): bool { if (!isset($this->parent)) { throw new Exception('Cannot check for data validation when cell is not bound to a worksheet'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/Div0Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/Div0Test.php new file mode 100644 index 00000000..8655ff0b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/Div0Test.php @@ -0,0 +1,15 @@ +_calculateFormulaValue($formula); + self::assertEquals($expectedResult, $result); + } + + public function providerErrorTypeArray(): array + { + return [ + 'vector' => [ + [[2, 4, 7, ExcelError::NA(), ExcelError::NA(), ExcelError::NA(), 5]], + '{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP", "#NAME?"}', + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsErrorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsErrorTest.php index 674062ee..26f5b9c3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsErrorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsErrorTest.php @@ -46,8 +46,8 @@ class IsErrorTest extends TestCase { return [ 'vector' => [ - [[true, true, true, false, false, false]], - '{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP"}', + [[true, true, true, false, false, false, false]], + '{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP", null}', ], ]; } diff --git a/tests/PhpSpreadsheetTests/Calculation/IsFormulaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php similarity index 79% rename from tests/PhpSpreadsheetTests/Calculation/IsFormulaTest.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php index 40e0d949..03e9bb70 100644 --- a/tests/PhpSpreadsheetTests/Calculation/IsFormulaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php @@ -1,7 +1,9 @@ disconnectWorksheets(); } + + public function testIsFormulaArray(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue('=5/2'); + $sheet->getCell('A2')->setValueExplicit('=5/2', DataType::TYPE_STRING); + $sheet->getCell('A3')->setValue('=5/0'); + $sheet->getCell('A4')->setValue(2.5); + $sheet->getCell('A5')->setValue('=NA()'); + $sheet->getCell('A6')->setValue(true); + $sheet->getCell('A7')->setValue('=5/0'); + $sheet->getCell('A7')->getStyle()->setQuotePrefix(true); + + $calculation = Calculation::getInstance($spreadsheet); + + $formula = '=ISFORMULA(A1:A7)'; + $result = $calculation->_calculateFormulaValue($formula, 'C1', $sheet->getCell('C1')); + self::assertEquals([true, false, true, false, true, false, false], $result); + + $spreadsheet->disconnectWorksheets(); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/NaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/NaTest.php new file mode 100644 index 00000000..471619f3 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/NaTest.php @@ -0,0 +1,15 @@ +