Failed Conditions
Push — master ( 4b6ad7...9fab89 )
by Adrien
06:57
created

Functions::isValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
use PhpOffice\PhpSpreadsheet\Cell\Cell;
6
7
class Functions
8
{
9
    const PRECISION = 8.88E-016;
10
11
    /**
12
     * 2 / PI.
13
     */
14
    const M_2DIVPI = 0.63661977236758134307553505349006;
15
16
    /** constants */
17
    const COMPATIBILITY_EXCEL = 'Excel';
18
    const COMPATIBILITY_GNUMERIC = 'Gnumeric';
19
    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
20
21
    const RETURNDATE_PHP_NUMERIC = 'P';
22
    const RETURNDATE_UNIX_TIMESTAMP = 'P';
23
    const RETURNDATE_PHP_OBJECT = 'O';
24
    const RETURNDATE_PHP_DATETIME_OBJECT = 'O';
25
    const RETURNDATE_EXCEL = 'E';
26
27
    /**
28
     * Compatibility mode to use for error checking and responses.
29
     *
30
     * @var string
31
     */
32
    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
33
34
    /**
35
     * Data Type to use when returning date values.
36
     *
37
     * @var string
38
     */
39
    protected static $returnDateType = self::RETURNDATE_EXCEL;
40
41
    /**
42
     * List of error codes.
43
     *
44
     * @var array
45
     */
46
    protected static $errorCodes = [
47
        'null' => '#NULL!',
48
        'divisionbyzero' => '#DIV/0!',
49
        'value' => '#VALUE!',
50
        'reference' => '#REF!',
51
        'name' => '#NAME?',
52
        'num' => '#NUM!',
53
        'na' => '#N/A',
54
        'gettingdata' => '#GETTING_DATA',
55
    ];
56
57
    /**
58
     * Set the Compatibility Mode.
59
     *
60
     * @category Function Configuration
61
     *
62
     * @param string $compatibilityMode Compatibility Mode
63
     *                                                Permitted values are:
64
     *                                                    Functions::COMPATIBILITY_EXCEL            'Excel'
65
     *                                                    Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
66
     *                                                    Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
67
     *
68
     * @return bool (Success or Failure)
69
     */
70 4514
    public static function setCompatibilityMode($compatibilityMode)
71
    {
72 4514
        if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
73 4514
            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
74 4514
            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)
75
        ) {
76 4514
            self::$compatibilityMode = $compatibilityMode;
77
78 4514
            return true;
79
        }
80
81 1
        return false;
82
    }
83
84
    /**
85
     * Return the current Compatibility Mode.
86
     *
87
     * @category Function Configuration
88
     *
89
     * @return string Compatibility Mode
90
     *                            Possible Return values are:
91
     *                                Functions::COMPATIBILITY_EXCEL            'Excel'
92
     *                                Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
93
     *                                Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
94
     */
95 945
    public static function getCompatibilityMode()
96
    {
97 945
        return self::$compatibilityMode;
98
    }
99
100
    /**
101
     * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
102
     *
103
     * @category Function Configuration
104
     *
105
     * @param string $returnDateType Return Date Format
106
     *                                                Permitted values are:
107
     *                                                    Functions::RETURNDATE_UNIX_TIMESTAMP        'P'
108
     *                                                    Functions::RETURNDATE_PHP_DATETIME_OBJECT        'O'
109
     *                                                    Functions::RETURNDATE_EXCEL            'E'
110
     *
111
     * @return bool Success or failure
112
     */
113 1037
    public static function setReturnDateType($returnDateType)
114
    {
115 1037
        if (($returnDateType == self::RETURNDATE_UNIX_TIMESTAMP) ||
116 1037
            ($returnDateType == self::RETURNDATE_PHP_DATETIME_OBJECT) ||
117 1037
            ($returnDateType == self::RETURNDATE_EXCEL)
118
        ) {
119 1037
            self::$returnDateType = $returnDateType;
120
121 1037
            return true;
122
        }
123
124 1
        return false;
125
    }
126
127
    /**
128
     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
129
     *
130
     * @category Function Configuration
131
     *
132
     * @return string Return Date Format
133
     *                            Possible Return values are:
134
     *                                Functions::RETURNDATE_UNIX_TIMESTAMP        'P'
135
     *                                Functions::RETURNDATE_PHP_DATETIME_OBJECT        'O'
136
     *                                Functions::RETURNDATE_EXCEL            'E'
137
     */
138 700
    public static function getReturnDateType()
139
    {
140 700
        return self::$returnDateType;
141
    }
142
143
    /**
144
     * DUMMY.
145
     *
146
     * @category Error Returns
147
     *
148
     * @return string #Not Yet Implemented
149
     */
150 1
    public static function DUMMY()
151
    {
152 1
        return '#Not Yet Implemented';
153
    }
154
155
    /**
156
     * DIV0.
157
     *
158
     * @category Error Returns
159
     *
160
     * @return string #Not Yet Implemented
161
     */
162 56
    public static function DIV0()
163
    {
164 56
        return self::$errorCodes['divisionbyzero'];
165
    }
166
167
    /**
168
     * NA.
169
     *
170
     * Excel Function:
171
     *        =NA()
172
     *
173
     * Returns the error value #N/A
174
     *        #N/A is the error value that means "no value is available."
175
     *
176
     * @category Logical Functions
177
     *
178
     * @return string #N/A!
179
     */
180 63
    public static function NA()
181
    {
182 63
        return self::$errorCodes['na'];
183
    }
184
185
    /**
186
     * NaN.
187
     *
188
     * Returns the error value #NUM!
189
     *
190
     * @category Error Returns
191
     *
192
     * @return string #NUM!
193
     */
194 187
    public static function NAN()
195
    {
196 187
        return self::$errorCodes['num'];
197
    }
198
199
    /**
200
     * NAME.
201
     *
202
     * Returns the error value #NAME?
203
     *
204
     * @category Error Returns
205
     *
206
     * @return string #NAME?
207
     */
208 5
    public static function NAME()
209
    {
210 5
        return self::$errorCodes['name'];
211
    }
212
213
    /**
214
     * REF.
215
     *
216
     * Returns the error value #REF!
217
     *
218
     * @category Error Returns
219
     *
220
     * @return string #REF!
221
     */
222 5
    public static function REF()
223
    {
224 5
        return self::$errorCodes['reference'];
225
    }
226
227
    /**
228
     * NULL.
229
     *
230
     * Returns the error value #NULL!
231
     *
232
     * @category Error Returns
233
     *
234
     * @return string #NULL!
235
     */
236 1
    public static function null()
237
    {
238 1
        return self::$errorCodes['null'];
239
    }
240
241
    /**
242
     * VALUE.
243
     *
244
     * Returns the error value #VALUE!
245
     *
246
     * @category Error Returns
247
     *
248
     * @return string #VALUE!
249
     */
250 233
    public static function VALUE()
251
    {
252 233
        return self::$errorCodes['value'];
253
    }
254
255 6
    public static function isMatrixValue($idx)
256
    {
257 6
        return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
258
    }
259
260 1
    public static function isValue($idx)
261
    {
262 1
        return substr_count($idx, '.') == 0;
263
    }
264
265 19
    public static function isCellValue($idx)
266
    {
267 19
        return substr_count($idx, '.') > 1;
268
    }
269
270 55
    public static function ifCondition($condition)
271
    {
272 55
        $condition = self::flattenSingleValue($condition);
273
274 55
        if ($condition === '') {
275
            $condition = '=""';
276
        }
277
278 55
        if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='])) {
279 11
            if (!is_numeric($condition)) {
280 5
                $condition = Calculation::wrapResult(strtoupper($condition));
281
            }
282
283 11
            return str_replace('""""', '""', '=' . $condition);
284
        }
285 46
        preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
286 46
        [, $operator, $operand] = $matches;
287
288 46
        if (is_numeric(trim($operand, '"'))) {
289 17
            $operand = trim($operand, '"');
290 33
        } elseif (!is_numeric($operand)) {
291 33
            $operand = str_replace('"', '""', $operand);
292 33
            $operand = Calculation::wrapResult(strtoupper($operand));
293
        }
294
295 46
        return str_replace('""""', '""', $operator . $operand);
296
    }
297
298
    /**
299
     * ERROR_TYPE.
300
     *
301
     * @param mixed $value Value to check
302
     *
303
     * @return bool
304
     */
305 14
    public static function errorType($value = '')
306
    {
307 14
        $value = self::flattenSingleValue($value);
308
309 14
        $i = 1;
310 14
        foreach (self::$errorCodes as $errorCode) {
311 14
            if ($value === $errorCode) {
312 7
                return $i;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $i returns the type integer which is incompatible with the documented return type boolean.
Loading history...
313
            }
314 13
            ++$i;
315
        }
316
317 7
        return self::NA();
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::NA() returns the type string which is incompatible with the documented return type boolean.
Loading history...
318
    }
319
320
    /**
321
     * IS_BLANK.
322
     *
323
     * @param mixed $value Value to check
324
     *
325
     * @return bool
326
     */
327 16
    public static function isBlank($value = null)
328
    {
329 16
        if ($value !== null) {
330 14
            $value = self::flattenSingleValue($value);
331
        }
332
333 16
        return $value === null;
334
    }
335
336
    /**
337
     * IS_ERR.
338
     *
339
     * @param mixed $value Value to check
340
     *
341
     * @return bool
342
     */
343 16
    public static function isErr($value = '')
344
    {
345 16
        $value = self::flattenSingleValue($value);
346
347 16
        return self::isError($value) && (!self::isNa(($value)));
348
    }
349
350
    /**
351
     * IS_ERROR.
352
     *
353
     * @param mixed $value Value to check
354
     *
355
     * @return bool
356
     */
357 88
    public static function isError($value = '')
358
    {
359 88
        $value = self::flattenSingleValue($value);
360
361 88
        if (!is_string($value)) {
362 53
            return false;
363
        }
364
365 44
        return in_array($value, self::$errorCodes);
366
    }
367
368
    /**
369
     * IS_NA.
370
     *
371
     * @param mixed $value Value to check
372
     *
373
     * @return bool
374
     */
375 20
    public static function isNa($value = '')
376
    {
377 20
        $value = self::flattenSingleValue($value);
378
379 20
        return $value === self::NA();
380
    }
381
382
    /**
383
     * IS_EVEN.
384
     *
385
     * @param mixed $value Value to check
386
     *
387
     * @return bool|string
388
     */
389 20
    public static function isEven($value = null)
390
    {
391 20
        $value = self::flattenSingleValue($value);
392
393 20
        if ($value === null) {
394 2
            return self::NAME();
395 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
396 7
            return self::VALUE();
397
        }
398
399 11
        return $value % 2 == 0;
400
    }
401
402
    /**
403
     * IS_ODD.
404
     *
405
     * @param mixed $value Value to check
406
     *
407
     * @return bool|string
408
     */
409 20
    public static function isOdd($value = null)
410
    {
411 20
        $value = self::flattenSingleValue($value);
412
413 20
        if ($value === null) {
414 2
            return self::NAME();
415 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
416 7
            return self::VALUE();
417
        }
418
419 11
        return abs($value) % 2 == 1;
420
    }
421
422
    /**
423
     * IS_NUMBER.
424
     *
425
     * @param mixed $value Value to check
426
     *
427
     * @return bool
428
     */
429 16
    public static function isNumber($value = null)
430
    {
431 16
        $value = self::flattenSingleValue($value);
432
433 16
        if (is_string($value)) {
434 8
            return false;
435
        }
436
437 8
        return is_numeric($value);
438
    }
439
440
    /**
441
     * IS_LOGICAL.
442
     *
443
     * @param mixed $value Value to check
444
     *
445
     * @return bool
446
     */
447 16
    public static function isLogical($value = null)
448
    {
449 16
        $value = self::flattenSingleValue($value);
450
451 16
        return is_bool($value);
452
    }
453
454
    /**
455
     * IS_TEXT.
456
     *
457
     * @param mixed $value Value to check
458
     *
459
     * @return bool
460
     */
461 32
    public static function isText($value = null)
462
    {
463 32
        $value = self::flattenSingleValue($value);
464
465 32
        return is_string($value) && !self::isError($value);
466
    }
467
468
    /**
469
     * IS_NONTEXT.
470
     *
471
     * @param mixed $value Value to check
472
     *
473
     * @return bool
474
     */
475 16
    public static function isNonText($value = null)
476
    {
477 16
        return !self::isText($value);
478
    }
479
480
    /**
481
     * N.
482
     *
483
     * Returns a value converted to a number
484
     *
485
     * @param null|mixed $value The value you want converted
486
     *
487
     * @return number N converts values listed in the following table
488
     *        If value is or refers to N returns
489
     *        A number            That number
490
     *        A date                The serial number of that date
491
     *        TRUE                1
492
     *        FALSE                0
493
     *        An error value        The error value
494
     *        Anything else        0
495
     */
496 20
    public static function n($value = null)
497
    {
498 20
        while (is_array($value)) {
499 9
            $value = array_shift($value);
500
        }
501
502 20
        switch (gettype($value)) {
503 20
            case 'double':
504 19
            case 'float':
505 19
            case 'integer':
506 8
                return $value;
507 12
            case 'boolean':
508 1
                return (int) $value;
509 11
            case 'string':
510
                //    Errors
511 8
                if ((strlen($value) > 0) && ($value[0] == '#')) {
512 2
                    return $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $value returns the type string which is incompatible with the documented return type double|integer.
Loading history...
513
                }
514
515 6
                break;
516
        }
517
518 9
        return 0;
519
    }
520
521
    /**
522
     * TYPE.
523
     *
524
     * Returns a number that identifies the type of a value
525
     *
526
     * @param null|mixed $value The value you want tested
527
     *
528
     * @return number N converts values listed in the following table
529
     *        If value is or refers to N returns
530
     *        A number            1
531
     *        Text                2
532
     *        Logical Value        4
533
     *        An error value        16
534
     *        Array or Matrix        64
535
     */
536 16
    public static function TYPE($value = null)
537
    {
538 16
        $value = self::flattenArrayIndexed($value);
539 16
        if (is_array($value) && (count($value) > 1)) {
540 3
            end($value);
541 3
            $a = key($value);
542
            //    Range of cells is an error
543 3
            if (self::isCellValue($a)) {
544
                return 16;
545
            //    Test for Matrix
546 3
            } elseif (self::isMatrixValue($a)) {
547 3
                return 64;
548
            }
549 13
        } elseif (empty($value)) {
550
            //    Empty Cell
551 2
            return 1;
552
        }
553 11
        $value = self::flattenSingleValue($value);
554
555 11
        if (($value === null) || (is_float($value)) || (is_int($value))) {
556 4
            return 1;
557 7
        } elseif (is_bool($value)) {
558 1
            return 4;
559 6
        } elseif (is_array($value)) {
560
            return 64;
561 6
        } elseif (is_string($value)) {
562
            //    Errors
563 6
            if ((strlen($value) > 0) && ($value[0] == '#')) {
564 2
                return 16;
565
            }
566
567 4
            return 2;
568
        }
569
570
        return 0;
571
    }
572
573
    /**
574
     * Convert a multi-dimensional array to a simple 1-dimensional array.
575
     *
576
     * @param array $array Array to be flattened
577
     *
578
     * @return array Flattened array
579
     */
580 403
    public static function flattenArray($array)
581
    {
582 403
        if (!is_array($array)) {
0 ignored issues
show
introduced by
The condition is_array($array) is always true.
Loading history...
583 6
            return (array) $array;
584
        }
585
586 397
        $arrayValues = [];
587 397
        foreach ($array as $value) {
588 371
            if (is_array($value)) {
589 107
                foreach ($value as $val) {
590 107
                    if (is_array($val)) {
591 36
                        foreach ($val as $v) {
592 36
                            $arrayValues[] = $v;
593
                        }
594
                    } else {
595 72
                        $arrayValues[] = $val;
596
                    }
597
                }
598
            } else {
599 286
                $arrayValues[] = $value;
600
            }
601
        }
602
603 397
        return $arrayValues;
604
    }
605
606
    /**
607
     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing.
608
     *
609
     * @param array $array Array to be flattened
610
     *
611
     * @return array Flattened array
612
     */
613 79
    public static function flattenArrayIndexed($array)
614
    {
615 79
        if (!is_array($array)) {
0 ignored issues
show
introduced by
The condition is_array($array) is always true.
Loading history...
616 11
            return (array) $array;
617
        }
618
619 68
        $arrayValues = [];
620 68
        foreach ($array as $k1 => $value) {
621 68
            if (is_array($value)) {
622 65
                foreach ($value as $k2 => $val) {
623 65
                    if (is_array($val)) {
624 26
                        foreach ($val as $k3 => $v) {
625 26
                            $arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v;
626
                        }
627
                    } else {
628 50
                        $arrayValues[$k1 . '.' . $k2] = $val;
629
                    }
630
                }
631
            } else {
632 26
                $arrayValues[$k1] = $value;
633
            }
634
        }
635
636 68
        return $arrayValues;
637
    }
638
639
    /**
640
     * Convert an array to a single scalar value by extracting the first element.
641
     *
642
     * @param mixed $value Array or scalar value
643
     *
644
     * @return mixed
645
     */
646 3776
    public static function flattenSingleValue($value = '')
647
    {
648 3776
        while (is_array($value)) {
649 70
            $value = array_pop($value);
650
        }
651
652 3776
        return $value;
653
    }
654
655
    /**
656
     * ISFORMULA.
657
     *
658
     * @param mixed $cellReference The cell to check
659
     * @param Cell $pCell The current cell (containing this formula)
660
     *
661
     * @return bool|string
662
     */
663 19
    public static function isFormula($cellReference = '', Cell $pCell = null)
664
    {
665 19
        if ($pCell === null) {
666
            return self::REF();
667
        }
668
669 19
        preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellReference, $matches);
670
671 19
        $cellReference = $matches[6] . $matches[7];
672 19
        $worksheetName = trim($matches[3], "'");
673
674 19
        $worksheet = (!empty($worksheetName))
675 3
            ? $pCell->getWorksheet()->getParent()->getSheetByName($worksheetName)
676 19
            : $pCell->getWorksheet();
677
678 19
        return $worksheet->getCell($cellReference)->isFormula();
1 ignored issue
show
Bug introduced by
The method getCell() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

678
        return $worksheet->/** @scrutinizer ignore-call */ getCell($cellReference)->isFormula();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
679
    }
680
}
681