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
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
class Conditional
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
/**
|
||||
* STATEMENT_IF.
|
||||
*
|
||||
|
|
@ -34,7 +37,9 @@ class Conditional
|
|||
*
|
||||
* @param mixed $condition Condition to evaluate
|
||||
* @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
|
||||
* Note that this can be an array value
|
||||
*
|
||||
* @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);
|
||||
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
|
||||
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
|
||||
$returnIfTrue = $returnIfTrue ?? 0;
|
||||
$returnIfFalse = $returnIfFalse ?? false;
|
||||
|
||||
return ($condition) ? $returnIfTrue : $returnIfFalse;
|
||||
}
|
||||
|
|
@ -67,9 +72,11 @@ class Conditional
|
|||
* result1, result2, ... result_n
|
||||
* A list of results. The SWITCH function returns the corresponding result when a value
|
||||
* matches expression.
|
||||
* Note that these can be array values to be returned
|
||||
* default
|
||||
* Optional. It is the default to return if expression does not match any of the values
|
||||
* (value1, value2, ... value_n).
|
||||
* Note that this can be an array value to be returned
|
||||
*
|
||||
* @param mixed $arguments Statement arguments
|
||||
*
|
||||
|
|
@ -113,14 +120,21 @@ class Conditional
|
|||
* =IFERROR(testValue,errorpart)
|
||||
*
|
||||
* @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
|
||||
* Note that this can be an array value to be returned
|
||||
*
|
||||
* @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 = '')
|
||||
{
|
||||
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
|
||||
$errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart);
|
||||
if (is_array($testValue)) {
|
||||
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $errorpart);
|
||||
}
|
||||
|
||||
$errorpart = $errorpart ?? '';
|
||||
|
||||
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
|
||||
}
|
||||
|
|
@ -132,14 +146,21 @@ class Conditional
|
|||
* =IFNA(testValue,napart)
|
||||
*
|
||||
* @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
|
||||
* Note that this can be an array value to be returned
|
||||
*
|
||||
* @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 = '')
|
||||
{
|
||||
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
|
||||
$napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
|
||||
if (is_array($testValue)) {
|
||||
return self::evaluateArrayArgumentsSubset([self::class, __FUNCTION__], 1, $testValue, $napart);
|
||||
}
|
||||
|
||||
$napart = $napart ?? '';
|
||||
|
||||
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
|
||||
}
|
||||
|
|
@ -156,6 +177,7 @@ class Conditional
|
|||
* Value returned if corresponding testValue (nth) was true
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
|
@ -170,7 +192,7 @@ class Conditional
|
|||
$falseValueException = new Exception();
|
||||
for ($i = 0; $i < $argumentCount; $i += 2) {
|
||||
$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);
|
||||
|
||||
if ($result !== $falseValueException) {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
class Operations
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$logical = Functions::flattenSingleValue($logical);
|
||||
if (is_array($logical)) {
|
||||
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $logical);
|
||||
}
|
||||
|
||||
if (is_string($logical)) {
|
||||
$logical = mb_strtoupper($logical, 'UTF-8');
|
||||
|
|
|
|||
|
|
@ -55,6 +55,22 @@ class ArrayFormulaTest extends TestCase
|
|||
'=SUM(SEQUENCE(3,3,0,1))',
|
||||
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;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -30,4 +31,32 @@ class IfErrorTest extends TestCase
|
|||
{
|
||||
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;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -30,4 +31,32 @@ class IfNaTest extends TestCase
|
|||
{
|
||||
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;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -28,4 +29,26 @@ class NotTest extends TestCase
|
|||
{
|
||||
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,
|
||||
'ABC',
|
||||
],
|
||||
'array return' => [
|
||||
[[4, 5, 6]],
|
||||
false,
|
||||
[[1, 2, 3]],
|
||||
true,
|
||||
[[4, 5, 6]],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -39,6 +39,24 @@ return [
|
|||
'DEF',
|
||||
'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
|
||||
[
|
||||
'#VALUE!',
|
||||
|
|
|
|||
Loading…
Reference in New Issue