Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for IFS() logical function #1442

Merged
merged 6 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/references/function-list-by-category.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ FALSE | \PhpOffice\PhpSpreadsheet\Calculation\Logical::FALSE
IF | \PhpOffice\PhpSpreadsheet\Calculation\Logical::statementIf
IFERROR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFERROR
IFNA | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFNA
IFS | **Not yet Implemented**
IFS | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFS
NOT | \PhpOffice\PhpSpreadsheet\Calculation\Logical::NOT
OR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalOr
SWITCH | \PhpOffice\PhpSpreadsheet\Calculation\Logical::statementSwitch
Expand Down
2 changes: 1 addition & 1 deletion docs/references/function-list-by-name.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ Excel Function | Category | PhpSpreadsheet Function
IF | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::statementIf
IFERROR | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFERROR
IFNA | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFNA
IFS | CATEGORY_LOGICAL | **Not yet Implemented**
IFS | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFS
IMABS | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMABS
IMAGINARY | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMAGINARY
IMARGUMENT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMARGUMENT
Expand Down
2 changes: 1 addition & 1 deletion src/PhpSpreadsheet/Calculation/Calculation.php
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ class Calculation
],
'IFS' => [
'category' => Category::CATEGORY_LOGICAL,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [Logical::class, 'IFS'],
'argumentCount' => '2+',
],
'IMABS' => [
Expand Down
36 changes: 36 additions & 0 deletions src/PhpSpreadsheet/Calculation/Logical.php
Original file line number Diff line number Diff line change
Expand Up @@ -372,4 +372,40 @@ public static function IFNA($testValue = '', $napart = '')

return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
}

/**
* IFS.
*
* Excel Function:
* =IFS(testValue1;returnIfTrue1;testValue2;returnIfTrue2;...;testValue_n;returnIfTrue_n)
*
* testValue1 ... testValue_n
* Conditions to Evaluate
* returnIfTrue1 ... returnIfTrue_n
* Value returned if corresponding testValue (nth) was true
*
* @category Logical Functions
*
* @param mixed ...$arguments Statement arguments
*
* @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A error if none of testValues was true
*/
public static function IFS(...$arguments)
{
if (count($arguments) % 2 != 0) {
return Functions::NA();
}

for ($i = 0; $i < count($arguments); $i += 2) {
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
$result = self::statementIf($testValue, $returnIfTrue, Functions::DUMMY());

if ($result !== Functions::DUMMY()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I understand your concern that there is a possibility that the returned result may be a valid case of the string '#Not Yet Implemented'; unlikely, but not impossible.
I might be inclined to create something purely PHP detectable, that cannot exist in a spreadsheet, such as an exception. Maybe create a new EvaluateIfFalseException which can be returned as $result rather than thrown; and directly type tested rather than simply value tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea. Can I use just simple instance of generic Exception in that case: $falseValueException = new Exception();? Not sure if we need special Exception for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you could use a standard Exception, I was simply thinking about readabilityand providing a named exception where the name provided contextual meaning

return $result;
}
}

return Functions::NA();
}
}
1 change: 1 addition & 0 deletions src/PhpSpreadsheet/Calculation/functionlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ HYPERLINK
HYPGEOMDIST
IF
IFERROR
IFS
IMABS
IMAGINARY
IMARGUMENT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;

use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;

class IfsTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}

/**
* @dataProvider providerIFS
*
* @param mixed $expectedResult
*/
public function testIFS($expectedResult, ...$args)
{
$result = Logical::IFS(...$args);
$this->assertEquals($expectedResult, $result);
}

public function providerIFS()
{
return require 'data/Calculation/Logical/IFS.php';
}
}
50 changes: 50 additions & 0 deletions tests/data/Calculation/Logical/IFS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

return [
[
'#N/A',
],
[
1,
true,
1,
],
[
'#N/A',
false,
1,
true
],
[
'ABC',
true,
'ABC',
],
[
'#N/A',
false,
false,
false,
1,
false,
'ABC'
],
[
'ABC',
false,
false,
false,
1,
true,
'ABC'
],
[
false,
true,
false,
false,
1,
true,
'ABC'
],
];