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

Handle #REF! As Argument to COUNTIF, AVERAGEIF, SUMIF #4382

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
35 changes: 30 additions & 5 deletions src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpOffice\PhpSpreadsheet\Calculation\Database\DSum;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;

class Conditional
{
Expand All @@ -24,13 +25,17 @@ class Conditional
* Excel Function:
* AVERAGEIF(range,condition[, average_range])
*
* @param mixed $range Data values
* @param mixed $range Data values, expect array
* @param null|array|string $condition the criteria that defines which cells will be checked
* @param mixed $averageRange Data values
*/
public static function AVERAGEIF(mixed $range, null|array|string $condition, mixed $averageRange = []): null|int|float|string
{
if (!is_array($range) || !is_array($averageRange) || array_key_exists(0, $range) || array_key_exists(0, $averageRange)) {
if ($range === ExcelError::REF()) {
return $range;
}

throw new CalcException('Must specify range of cells, not any kind of literal');
}
$database = self::databaseFromRangeAndValue($range, $averageRange);
Expand Down Expand Up @@ -76,11 +81,21 @@ public static function AVERAGEIFS(mixed ...$args): null|int|float|string
* Excel Function:
* COUNTIF(range,condition)
*
* @param mixed[] $range Data values
* @param mixed $range Data values, expect array
* @param null|array|string $condition the criteria that defines which cells will be counted
*/
public static function COUNTIF(array $range, null|array|string $condition): string|int
public static function COUNTIF(mixed $range, null|array|string $condition): string|int
{
if (
!is_array($range)
|| array_key_exists(0, $range)
) {
if ($range === ExcelError::REF()) {
return $range;
}

throw new CalcException('Must specify range of cells, not any kind of literal');
}
// Filter out any empty values that shouldn't be included in a COUNT
$range = array_filter(
Functions::flattenArray($range),
Expand Down Expand Up @@ -169,10 +184,20 @@ public static function MINIFS(mixed ...$args): null|float|string
* Excel Function:
* SUMIF(range, criteria, [sum_range])
*
* @param array $range Data values
* @param mixed $range Data values, expecting array
*/
public static function SUMIF(array $range, mixed $condition, array $sumRange = []): null|float|string
public static function SUMIF(mixed $range, mixed $condition, array $sumRange = []): null|float|string
{
if (
!is_array($range)
|| array_key_exists(0, $range)
) {
if ($range === ExcelError::REF()) {
return $range;
}

throw new CalcException('Must specify range of cells, not any kind of literal');
}
$database = self::databaseFromRangeAndValue($range, $sumRange);
$condition = [[self::CONDITION_COLUMN_NAME, self::VALUE_COLUMN_NAME], [$condition, null]];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;

use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PHPUnit\Framework\Attributes\DataProvider;

class SumIfTest extends AllSetupTeardown
Expand Down Expand Up @@ -38,4 +39,20 @@ public static function providerSUMIF(): array
{
return require 'tests/data/Calculation/MathTrig/SUMIF.php';
}

public function testOutliers(): void
{
$sheet = $this->getSheet();
$sheet->getCell('A1')->setValue('=SUMIF(5,"<32")');

try {
$sheet->getCell('A1')->getCalculatedValue();
self::fail('Should receive exception for non-array arg');
} catch (CalcException $e) {
self::assertStringContainsString('Must specify range of cells', $e->getMessage());
}

$sheet->getCell('A4')->setValue('=SUMIF(#REF!,"<32")');
self::assertSame('#REF!', $sheet->getCell('A4')->getCalculatedValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@ public function testOutliers(): void
}
$sheet->getCell('A3')->setValue('=AVERAGEIF(C1:C1,"<32")');
self::assertSame(5, $sheet->getCell('A3')->getCalculatedValue(), 'first arg is single cell');

$sheet->getCell('A4')->setValue('=AVERAGEIF(#REF!,1)');
self::assertSame('#REF!', $sheet->getCell('A4')->getCalculatedValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical;

use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PHPUnit\Framework\Attributes\DataProvider;

class CountIfTest extends AllSetupTeardown
{
#[\PHPUnit\Framework\Attributes\DataProvider('providerCOUNTIF')]
#[DataProvider('providerCOUNTIF')]
public function testCOUNTIF(mixed $expectedResult, mixed ...$args): void
{
$this->runTestCaseNoBracket('COUNTIF', $expectedResult, ...$args);
Expand All @@ -27,4 +30,20 @@ public static function providerCOUNTIF(): array
{
return require 'tests/data/Calculation/Statistical/COUNTIF.php';
}

public function testOutliers(): void
{
$sheet = $this->getSheet();
$sheet->getCell('A1')->setValue('=COUNTIF(5,"<32")');

try {
$sheet->getCell('A1')->getCalculatedValue();
self::fail('Should receive exception for non-array arg');
} catch (CalcException $e) {
self::assertStringContainsString('Must specify range of cells', $e->getMessage());
}

$sheet->getCell('A4')->setValue('=COUNTIF(#REF!,1)');
self::assertSame('#REF!', $sheet->getCell('A4')->getCalculatedValue());
}
}