Passed
Push — master ( c380b2...9239b3 )
by Adrien
10:06
created

Subtotal   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 43
c 1
b 0
f 0
dl 0
loc 89
ccs 32
cts 32
cp 1
rs 10
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A filterFormulaArgs() 0 18 3
A filterHiddenArgs() 0 10 1
A funcSubtotal() 0 23 4
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
4
5
use Exception;
6
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
7
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
8
9
class Subtotal
10
{
11 11
    protected static function filterHiddenArgs($cellReference, $args)
12
    {
13 11
        return array_filter(
14
            $args,
15 11
            function ($index) use ($cellReference) {
16 11
                [, $row, ] = explode('.', $index);
17
18 11
                return $cellReference->getWorksheet()->getRowDimension($row)->getVisible();
19 11
            },
20 11
            ARRAY_FILTER_USE_KEY
21
        );
22
    }
23
24 41
    protected static function filterFormulaArgs($cellReference, $args)
25
    {
26 41
        return array_filter(
27
            $args,
28 41
            function ($index) use ($cellReference) {
29 40
                [, $row, $column] = explode('.', $index);
30 40
                $retVal = true;
31 40
                if ($cellReference->getWorksheet()->cellExists($column . $row)) {
32
                    //take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
33 40
                    $isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
34 40
                    $cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
35
36 40
                    $retVal = !$isFormula || $cellFormula;
37
                }
38
39 40
                return $retVal;
40 41
            },
41 41
            ARRAY_FILTER_USE_KEY
42
        );
43
    }
44
45
    private const CALL_FUNCTIONS = [
46
        1 => [Statistical\Averages::class, 'AVERAGE'],
47
        [Statistical\Counts::class, 'COUNT'], // 2
48
        [Statistical\Counts::class, 'COUNTA'], // 3
49
        [Statistical\Maximum::class, 'MAX'], // 4
50
        [Statistical\Minimum::class, 'MIN'], // 5
51
        [Product::class, 'funcProduct'], // 6
52
        [Statistical\StandardDeviations::class, 'STDEV'], // 7
53
        [Statistical\StandardDeviations::class, 'STDEVP'], // 8
54
        [Sum::class, 'funcSum'], // 9
55
        [Statistical\Variances::class, 'VAR'], // 10
56
        [Statistical\Variances::class, 'VARP'], // 11
57
    ];
58
59
    /**
60
     * SUBTOTAL.
61
     *
62
     * Returns a subtotal in a list or database.
63
     *
64
     * @param mixed $functionType
65
     *            A number 1 to 11 that specifies which function to
66
     *                    use in calculating subtotals within a range
67
     *                    list
68
     *            Numbers 101 to 111 shadow the functions of 1 to 11
69
     *                    but ignore any values in the range that are
70
     *                    in hidden rows or columns
71
     * @param mixed[] $args A mixed data series of values
72
     *
73
     * @return float|string
74
     */
75 43
    public static function funcSubtotal($functionType, ...$args)
76
    {
77 43
        $cellReference = array_pop($args);
78 43
        $aArgs = Functions::flattenArrayIndexed($args);
79
80
        try {
81 43
            $subtotal = (int) Helpers::validateNumericNullBool($functionType);
82 2
        } catch (Exception $e) {
83 2
            return $e->getMessage();
84
        }
85
86
        // Calculate
87 41
        if ($subtotal > 100) {
88 11
            $aArgs = self::filterHiddenArgs($cellReference, $aArgs);
89 11
            $subtotal -= 100;
90
        }
91
92 41
        $aArgs = self::filterFormulaArgs($cellReference, $aArgs);
93 41
        if (array_key_exists($subtotal, self::CALL_FUNCTIONS)) {
94 35
            return call_user_func_array(self::CALL_FUNCTIONS[$subtotal], $aArgs);
95
        }
96
97 6
        return Functions::VALUE();
98
    }
99
}
100