Convert all relevant Logical functions to support array arguments (#2600)
This commit is contained in:
parent
e580f10c46
commit
0371ccb686
|
|
@ -163,7 +163,7 @@ class Logical
|
||||||
*
|
*
|
||||||
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
|
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
|
||||||
*
|
*
|
||||||
* @return bool|string the boolean inverse of the argument
|
* @return array|bool|string the boolean inverse of the argument
|
||||||
*/
|
*/
|
||||||
public static function NOT($logical = false)
|
public static function NOT($logical = false)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Conditional
|
class Conditional
|
||||||
{
|
{
|
||||||
|
use ArrayEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STATEMENT_IF.
|
* STATEMENT_IF.
|
||||||
*
|
*
|
||||||
|
|
@ -34,7 +37,9 @@ class Conditional
|
||||||
*
|
*
|
||||||
* @param mixed $condition Condition to evaluate
|
* @param mixed $condition Condition to evaluate
|
||||||
* @param mixed $returnIfTrue Value to return when condition is true
|
* @param mixed $returnIfTrue Value to return when condition is true
|
||||||
|
* Note that this can be an array value
|
||||||
* @param mixed $returnIfFalse Optional value to return when condition is false
|
* @param mixed $returnIfFalse Optional value to return when condition is false
|
||||||
|
* Note that this can be an array value
|
||||||
*
|
*
|
||||||
* @return mixed The value of returnIfTrue or returnIfFalse determined by condition
|
* @return mixed The value of returnIfTrue or returnIfFalse determined by condition
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,8 +50,8 @@ class Conditional
|
||||||
}
|
}
|
||||||
|
|
||||||
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
|
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
|
||||||
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
|
$returnIfTrue = $returnIfTrue ?? 0;
|
||||||
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
|
$returnIfFalse = $returnIfFalse ?? false;
|
||||||
|
|
||||||
return ($condition) ? $returnIfTrue : $returnIfFalse;
|
return ($condition) ? $returnIfTrue : $returnIfFalse;
|
||||||
}
|
}
|
||||||
|
|
@ -67,9 +72,11 @@ class Conditional
|
||||||
* result1, result2, ... result_n
|
* result1, result2, ... result_n
|
||||||
* A list of results. The SWITCH function returns the corresponding result when a value
|
* A list of results. The SWITCH function returns the corresponding result when a value
|
||||||
* matches expression.
|
* matches expression.
|
||||||
|
* Note that these can be array values to be returned
|
||||||
* default
|
* default
|
||||||
* Optional. It is the default to return if expression does not match any of the values
|
* Optional. It is the default to return if expression does not match any of the values
|
||||||
* (value1, value2, ... value_n).
|
* (value1, value2, ... value_n).
|
||||||
|
* Note that this can be an array value to be returned
|
||||||
*
|
*
|
||||||
* @param mixed $arguments Statement arguments
|
* @param mixed $arguments Statement arguments
|
||||||
*
|
*
|
||||||
|
|
@ -113,14 +120,21 @@ class Conditional
|
||||||
* =IFERROR(testValue,errorpart)
|
* =IFERROR(testValue,errorpart)
|
||||||
*
|
*
|
||||||
* @param mixed $testValue Value to check, is also the value returned when no error
|
* @param mixed $testValue Value to check, is also the value returned when no error
|
||||||
|
* Or can be an array of values
|
||||||
* @param mixed $errorpart Value to return when testValue is an error condition
|
* @param mixed $errorpart Value to return when testValue is an error condition
|
||||||
|
* Note that this can be an array value to be returned
|
||||||
*
|
*
|
||||||
* @return mixed The value of errorpart or testValue determined by error condition
|
* @return mixed The value of errorpart or testValue determined by error condition
|
||||||
|
* If an array of values is passed as the $testValue argument, then the returned result will also be
|
||||||
|
* an array with the same dimensions
|
||||||
*/
|
*/
|
||||||
public static function IFERROR($testValue = '', $errorpart = '')
|
public static function IFERROR($testValue = '', $errorpart = '')
|
||||||
{
|
{
|
||||||
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
|
if (is_array($testValue)) {
|
||||||
$errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart);
|
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $errorpart);
|
||||||
|
}
|
||||||
|
|
||||||
|
$errorpart = $errorpart ?? '';
|
||||||
|
|
||||||
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
|
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
|
||||||
}
|
}
|
||||||
|
|
@ -132,14 +146,21 @@ class Conditional
|
||||||
* =IFNA(testValue,napart)
|
* =IFNA(testValue,napart)
|
||||||
*
|
*
|
||||||
* @param mixed $testValue Value to check, is also the value returned when not an NA
|
* @param mixed $testValue Value to check, is also the value returned when not an NA
|
||||||
|
* Or can be an array of values
|
||||||
* @param mixed $napart Value to return when testValue is an NA condition
|
* @param mixed $napart Value to return when testValue is an NA condition
|
||||||
|
* Note that this can be an array value to be returned
|
||||||
*
|
*
|
||||||
* @return mixed The value of errorpart or testValue determined by error condition
|
* @return mixed The value of errorpart or testValue determined by error condition
|
||||||
|
* If an array of values is passed as the $testValue argument, then the returned result will also be
|
||||||
|
* an array with the same dimensions
|
||||||
*/
|
*/
|
||||||
public static function IFNA($testValue = '', $napart = '')
|
public static function IFNA($testValue = '', $napart = '')
|
||||||
{
|
{
|
||||||
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
|
if (is_array($testValue)) {
|
||||||
$napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
|
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $napart);
|
||||||
|
}
|
||||||
|
|
||||||
|
$napart = $napart ?? '';
|
||||||
|
|
||||||
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
|
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
|
||||||
}
|
}
|
||||||
|
|
@ -156,6 +177,7 @@ class Conditional
|
||||||
* Value returned if corresponding testValue (nth) was true
|
* Value returned if corresponding testValue (nth) was true
|
||||||
*
|
*
|
||||||
* @param mixed ...$arguments Statement arguments
|
* @param mixed ...$arguments Statement arguments
|
||||||
|
* Note that this can be an array value to be returned
|
||||||
*
|
*
|
||||||
* @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true
|
* @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true
|
||||||
*/
|
*/
|
||||||
|
|
@ -170,7 +192,7 @@ class Conditional
|
||||||
$falseValueException = new Exception();
|
$falseValueException = new Exception();
|
||||||
for ($i = 0; $i < $argumentCount; $i += 2) {
|
for ($i = 0; $i < $argumentCount; $i += 2) {
|
||||||
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
|
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
|
||||||
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
|
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : $arguments[$i + 1];
|
||||||
$result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
|
$result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
|
||||||
|
|
||||||
if ($result !== $falseValueException) {
|
if ($result !== $falseValueException) {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Operations
|
class Operations
|
||||||
{
|
{
|
||||||
|
use ArrayEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LOGICAL_AND.
|
* LOGICAL_AND.
|
||||||
*
|
*
|
||||||
|
|
@ -146,12 +149,17 @@ class Operations
|
||||||
* holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
|
* holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
|
||||||
*
|
*
|
||||||
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
|
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
|
||||||
|
* Or can be an array of values
|
||||||
*
|
*
|
||||||
* @return bool|string the boolean inverse of the argument
|
* @return array|bool|string the boolean inverse of the argument
|
||||||
|
* If an array of values is passed as an argument, then the returned result will also be an array
|
||||||
|
* with the same dimensions
|
||||||
*/
|
*/
|
||||||
public static function NOT($logical = false)
|
public static function NOT($logical = false)
|
||||||
{
|
{
|
||||||
$logical = Functions::flattenSingleValue($logical);
|
if (is_array($logical)) {
|
||||||
|
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $logical);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_string($logical)) {
|
if (is_string($logical)) {
|
||||||
$logical = mb_strtoupper($logical, 'UTF-8');
|
$logical = mb_strtoupper($logical, 'UTF-8');
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,22 @@ class ArrayFormulaTest extends TestCase
|
||||||
'=SUM(SEQUENCE(3,3,0,1))',
|
'=SUM(SEQUENCE(3,3,0,1))',
|
||||||
36,
|
36,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'=IFERROR({5/2, 5/0}, MAX(ABS({-2,4,-6})))',
|
||||||
|
[[2.5, 6]],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'=MAX(IFERROR({5/2, 5/0}, 2.1))',
|
||||||
|
2.5,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'=IF(FALSE,{1,2,3},{4,5,6})',
|
||||||
|
[[4, 5, 6]],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'=IFS(FALSE, {1,2,3}, TRUE, {4,5,6})',
|
||||||
|
[[4, 5, 6]],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
@ -30,4 +31,32 @@ class IfErrorTest extends TestCase
|
||||||
{
|
{
|
||||||
return require 'tests/data/Calculation/Logical/IFERROR.php';
|
return require 'tests/data/Calculation/Logical/IFERROR.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerIfErrorArray
|
||||||
|
*/
|
||||||
|
public function testIfErrorArray(array $expectedResult, string $argument1, string $argument2): void
|
||||||
|
{
|
||||||
|
$calculation = Calculation::getInstance();
|
||||||
|
|
||||||
|
$formula = "=IFERROR({$argument1}, {$argument2})";
|
||||||
|
$result = $calculation->_calculateFormulaValue($formula);
|
||||||
|
self::assertEquals($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerIfErrorArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'vector' => [
|
||||||
|
[[2.5, 6]],
|
||||||
|
'{5/2, 5/0}',
|
||||||
|
'MAX(ABS({-2,4,-6}))',
|
||||||
|
],
|
||||||
|
'return value' => [
|
||||||
|
[[2.5, [[2, 3, 4]]]],
|
||||||
|
'{5/2, 5/0}',
|
||||||
|
'{2,3,4}',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
@ -30,4 +31,32 @@ class IfNaTest extends TestCase
|
||||||
{
|
{
|
||||||
return require 'tests/data/Calculation/Logical/IFNA.php';
|
return require 'tests/data/Calculation/Logical/IFNA.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerIfNaArray
|
||||||
|
*/
|
||||||
|
public function testIfNaArray(array $expectedResult, string $argument1, string $argument2): void
|
||||||
|
{
|
||||||
|
$calculation = Calculation::getInstance();
|
||||||
|
|
||||||
|
$formula = "=IFNA({$argument1}, {$argument2})";
|
||||||
|
$result = $calculation->_calculateFormulaValue($formula);
|
||||||
|
self::assertEquals($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerIfNaArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'vector' => [
|
||||||
|
[[2.5, '#DIV/0!', 6]],
|
||||||
|
'{5/2, 5/0, "#N/A"}',
|
||||||
|
'MAX(ABS({-2,4,-6}))',
|
||||||
|
],
|
||||||
|
'return value' => [
|
||||||
|
[[2.5, '#DIV/0!', [[2, 3, 4]]]],
|
||||||
|
'{5/2, 5/0, "#N/A"}',
|
||||||
|
'{2,3,4}',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
@ -28,4 +29,26 @@ class NotTest extends TestCase
|
||||||
{
|
{
|
||||||
return require 'tests/data/Calculation/Logical/NOT.php';
|
return require 'tests/data/Calculation/Logical/NOT.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerNotArray
|
||||||
|
*/
|
||||||
|
public function testNotArray(array $expectedResult, string $argument1): void
|
||||||
|
{
|
||||||
|
$calculation = Calculation::getInstance();
|
||||||
|
|
||||||
|
$formula = "=NOT({$argument1})";
|
||||||
|
$result = $calculation->_calculateFormulaValue($formula);
|
||||||
|
self::assertEquals($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerNotArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'vector' => [
|
||||||
|
[[false, true, true, false]],
|
||||||
|
'{TRUE, FALSE, FALSE, TRUE}',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,11 @@ return [
|
||||||
true,
|
true,
|
||||||
'ABC',
|
'ABC',
|
||||||
],
|
],
|
||||||
|
'array return' => [
|
||||||
|
[[4, 5, 6]],
|
||||||
|
false,
|
||||||
|
[[1, 2, 3]],
|
||||||
|
true,
|
||||||
|
[[4, 5, 6]],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,24 @@ return [
|
||||||
'DEF',
|
'DEF',
|
||||||
'Z',
|
'Z',
|
||||||
],
|
],
|
||||||
|
'Array return' => [
|
||||||
|
[[4, 5, 6]],
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
[[1, 2, 3]],
|
||||||
|
2,
|
||||||
|
[[4, 5, 6]],
|
||||||
|
[[7, 8, 9]],
|
||||||
|
],
|
||||||
|
'Array return as default' => [
|
||||||
|
[[7, 8, 9]],
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
[[1, 2, 3]],
|
||||||
|
2,
|
||||||
|
[[4, 5, 6]],
|
||||||
|
[[7, 8, 9]],
|
||||||
|
],
|
||||||
// Must be value - no parameter
|
// Must be value - no parameter
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue