Completed
Push — develop ( 3ee9cc...870d86 )
by Adrien
29:45
created

Functions::isNonText()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
/* MAX_VALUE */
6 60
define('MAX_VALUE', 1.2e308);
7
8
/* 2 / PI */
9 60
define('M_2DIVPI', 0.63661977236758134307553505349006);
10
11
/* MAX_ITERATIONS */
12 60
define('MAX_ITERATIONS', 256);
13
14
/* PRECISION */
15 60
define('PRECISION', 8.88E-016);
16
17
/**
18
 * Copyright (c) 2006 - 2016 PhpSpreadsheet.
19
 *
20
 * This library is free software; you can redistribute it and/or
21
 * modify it under the terms of the GNU Lesser General Public
22
 * License as published by the Free Software Foundation; either
23
 * version 2.1 of the License, or (at your option) any later version.
24
 *
25
 * This library is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
 * Lesser General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Lesser General Public
31
 * License along with this library; if not, write to the Free Software
32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33
 *
34
 * @category    PhpSpreadsheet
35
 *
36
 * @copyright   Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
37
 * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
38
 */
39
class Functions
40
{
41
    /** constants */
42
    const COMPATIBILITY_EXCEL = 'Excel';
43
    const COMPATIBILITY_GNUMERIC = 'Gnumeric';
44
    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
45
46
    const RETURNDATE_PHP_NUMERIC = 'P';
47
    const RETURNDATE_PHP_OBJECT = 'O';
48
    const RETURNDATE_EXCEL = 'E';
49
50
    /**
51
     * Compatibility mode to use for error checking and responses.
52
     *
53
     * @var string
54
     */
55
    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
56
57
    /**
58
     * Data Type to use when returning date values.
59
     *
60
     * @var string
61
     */
62
    protected static $returnDateType = self::RETURNDATE_EXCEL;
63
64
    /**
65
     * List of error codes.
66
     *
67
     * @var array
68
     */
69
    protected static $errorCodes = [
70
        'null' => '#NULL!',
71
        'divisionbyzero' => '#DIV/0!',
72
        'value' => '#VALUE!',
73
        'reference' => '#REF!',
74
        'name' => '#NAME?',
75
        'num' => '#NUM!',
76
        'na' => '#N/A',
77
        'gettingdata' => '#GETTING_DATA',
78
    ];
79
80
    /**
81
     * Set the Compatibility Mode.
82
     *
83
     * @category Function Configuration
84
     *
85
     * @param string $compatibilityMode Compatibility Mode
86
     *                                                Permitted values are:
87
     *                                                    Functions::COMPATIBILITY_EXCEL            'Excel'
88
     *                                                    Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
89
     *                                                    Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
90
     *
91
     * @return bool (Success or Failure)
92
     */
93 3628
    public static function setCompatibilityMode($compatibilityMode)
94
    {
95 3628
        if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
96 54
            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
97 54
            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)
98
        ) {
99 3628
            self::$compatibilityMode = $compatibilityMode;
100
101 3628
            return true;
102
        }
103
104
        return false;
105
    }
106
107
    /**
108
     * Return the current Compatibility Mode.
109
     *
110
     * @category Function Configuration
111
     *
112
     * @return string Compatibility Mode
113
     *                            Possible Return values are:
114
     *                                Functions::COMPATIBILITY_EXCEL            'Excel'
115
     *                                Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
116
     *                                Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
117
     */
118 673
    public static function getCompatibilityMode()
119
    {
120 673
        return self::$compatibilityMode;
121
    }
122
123
    /**
124
     * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
125
     *
126
     * @category Function Configuration
127
     *
128
     * @param string $returnDateType Return Date Format
129
     *                                                Permitted values are:
130
     *                                                    Functions::RETURNDATE_PHP_NUMERIC        'P'
131
     *                                                    Functions::RETURNDATE_PHP_OBJECT        'O'
132
     *                                                    Functions::RETURNDATE_EXCEL            'E'
133
     *
134
     * @return bool Success or failure
135
     */
136 428
    public static function setReturnDateType($returnDateType)
137
    {
138 428
        if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
139 428
            ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
140 428
            ($returnDateType == self::RETURNDATE_EXCEL)
141
        ) {
142 428
            self::$returnDateType = $returnDateType;
143
144 428
            return true;
145
        }
146
147
        return false;
148
    }
149
150
    /**
151
     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
152
     *
153
     * @category Function Configuration
154
     *
155
     * @return string Return Date Format
156
     *                            Possible Return values are:
157
     *                                Functions::RETURNDATE_PHP_NUMERIC        'P'
158
     *                                Functions::RETURNDATE_PHP_OBJECT        'O'
159
     *                                Functions::RETURNDATE_EXCEL            'E'
160
     */
161 591
    public static function getReturnDateType()
162
    {
163 591
        return self::$returnDateType;
164
    }
165
166
    /**
167
     * DUMMY.
168
     *
169
     * @category Error Returns
170
     *
171
     * @return string #Not Yet Implemented
172
     */
173 1
    public static function DUMMY()
174
    {
175 1
        return '#Not Yet Implemented';
176
    }
177
178
    /**
179
     * DIV0.
180
     *
181
     * @category Error Returns
182
     *
183
     * @return string #Not Yet Implemented
184
     */
185 37
    public static function DIV0()
186
    {
187 37
        return self::$errorCodes['divisionbyzero'];
188
    }
189
190
    /**
191
     * NA.
192
     *
193
     * Excel Function:
194
     *        =NA()
195
     *
196
     * Returns the error value #N/A
197
     *        #N/A is the error value that means "no value is available."
198
     *
199
     * @category Logical Functions
200
     *
201
     * @return string #N/A!
202
     */
203 39
    public static function NA()
204
    {
205 39
        return self::$errorCodes['na'];
206
    }
207
208
    /**
209
     * NaN.
210
     *
211
     * Returns the error value #NUM!
212
     *
213
     * @category Error Returns
214
     *
215
     * @return string #NUM!
216
     */
217 307
    public static function NAN()
218
    {
219 307
        return self::$errorCodes['num'];
220
    }
221
222
    /**
223
     * NAME.
224
     *
225
     * Returns the error value #NAME?
226
     *
227
     * @category Error Returns
228
     *
229
     * @return string #NAME?
230
     */
231 5
    public static function NAME()
232
    {
233 5
        return self::$errorCodes['name'];
234
    }
235
236
    /**
237
     * REF.
238
     *
239
     * Returns the error value #REF!
240
     *
241
     * @category Error Returns
242
     *
243
     * @return string #REF!
244
     */
245 3
    public static function REF()
246
    {
247 3
        return self::$errorCodes['reference'];
248
    }
249
250
    /**
251
     * NULL.
252
     *
253
     * Returns the error value #NULL!
254
     *
255
     * @category Error Returns
256
     *
257
     * @return string #NULL!
258
     */
259 1
    public static function null()
260
    {
261 1
        return self::$errorCodes['null'];
262
    }
263
264
    /**
265
     * VALUE.
266
     *
267
     * Returns the error value #VALUE!
268
     *
269
     * @category Error Returns
270
     *
271
     * @return string #VALUE!
272
     */
273 179
    public static function VALUE()
274
    {
275 179
        return self::$errorCodes['value'];
276
    }
277
278 3
    public static function isMatrixValue($idx)
279
    {
280 3
        return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
281
    }
282
283
    public static function isValue($idx)
284
    {
285
        return substr_count($idx, '.') == 0;
286
    }
287
288 4
    public static function isCellValue($idx)
289
    {
290 4
        return substr_count($idx, '.') > 1;
291
    }
292
293 5
    public static function ifCondition($condition)
294
    {
295 5
        $condition = self::flattenSingleValue($condition);
296 5
        if (!isset($condition[0])) {
297
            $condition = '=""';
298
        }
299 5
        if (!in_array($condition[0], ['>', '<', '='])) {
300
            if (!is_numeric($condition)) {
301
                $condition = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($condition));
302
            }
303
304
            return '=' . $condition;
305
        }
306 5
        preg_match('/([<>=]+)(.*)/', $condition, $matches);
307 5
        list(, $operator, $operand) = $matches;
308
309 5
        if (!is_numeric($operand)) {
310 4
            $operand = str_replace('"', '""', $operand);
311 4
            $operand = \PhpOffice\PhpSpreadsheet\Calculation::wrapResult(strtoupper($operand));
312
        }
313
314 5
        return $operator . $operand;
315
    }
316
317
    /**
318
     * ERROR_TYPE.
319
     *
320
     * @param mixed $value Value to check
321
     *
322
     * @return bool
323
     */
324 14
    public static function errorType($value = '')
325
    {
326 14
        $value = self::flattenSingleValue($value);
327
328 14
        $i = 1;
329 14
        foreach (self::$errorCodes as $errorCode) {
330 14
            if ($value === $errorCode) {
331 7
                return $i;
332
            }
333 13
            ++$i;
334
        }
335
336 7
        return self::NA();
337
    }
338
339
    /**
340
     * IS_BLANK.
341
     *
342
     * @param mixed $value Value to check
343
     *
344
     * @return bool
345
     */
346 16
    public static function isBlank($value = null)
347
    {
348 16
        if (!is_null($value)) {
349 14
            $value = self::flattenSingleValue($value);
350
        }
351
352 16
        return is_null($value);
353
    }
354
355
    /**
356
     * IS_ERR.
357
     *
358
     * @param mixed $value Value to check
359
     *
360
     * @return bool
361
     */
362 16
    public static function isErr($value = '')
363
    {
364 16
        $value = self::flattenSingleValue($value);
365
366 16
        return self::isError($value) && (!self::isNa(($value)));
367
    }
368
369
    /**
370
     * IS_ERROR.
371
     *
372
     * @param mixed $value Value to check
373
     *
374
     * @return bool
375
     */
376 56
    public static function isError($value = '')
377
    {
378 56
        $value = self::flattenSingleValue($value);
379
380 56
        if (!is_string($value)) {
381 16
            return false;
382
        }
383
384 40
        return in_array($value, array_values(self::$errorCodes));
385
    }
386
387
    /**
388
     * IS_NA.
389
     *
390
     * @param mixed $value Value to check
391
     *
392
     * @return bool
393
     */
394 18
    public static function isNa($value = '')
395
    {
396 18
        $value = self::flattenSingleValue($value);
397
398 18
        return $value === self::NA();
399
    }
400
401
    /**
402
     * IS_EVEN.
403
     *
404
     * @param mixed $value Value to check
405
     *
406
     * @return string|bool
407
     */
408 20 View Code Duplication
    public static function isEven($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
409
    {
410 20
        $value = self::flattenSingleValue($value);
411
412 20
        if ($value === null) {
413 2
            return self::NAME();
414 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
415 7
            return self::VALUE();
416
        }
417
418 11
        return $value % 2 == 0;
419
    }
420
421
    /**
422
     * IS_ODD.
423
     *
424
     * @param mixed $value Value to check
425
     *
426
     * @return string|bool
427
     */
428 20 View Code Duplication
    public static function isOdd($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
429
    {
430 20
        $value = self::flattenSingleValue($value);
431
432 20
        if ($value === null) {
433 2
            return self::NAME();
434 18
        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
435 7
            return self::VALUE();
436
        }
437
438 11
        return abs($value) % 2 == 1;
439
    }
440
441
    /**
442
     * IS_NUMBER.
443
     *
444
     * @param mixed $value Value to check
445
     *
446
     * @return bool
447
     */
448 16
    public static function isNumber($value = null)
449
    {
450 16
        $value = self::flattenSingleValue($value);
451
452 16
        if (is_string($value)) {
453 8
            return false;
454
        }
455
456 8
        return is_numeric($value);
457
    }
458
459
    /**
460
     * IS_LOGICAL.
461
     *
462
     * @param mixed $value Value to check
463
     *
464
     * @return bool
465
     */
466 16
    public static function isLogical($value = null)
467
    {
468 16
        $value = self::flattenSingleValue($value);
469
470 16
        return is_bool($value);
471
    }
472
473
    /**
474
     * IS_TEXT.
475
     *
476
     * @param mixed $value Value to check
477
     *
478
     * @return bool
479
     */
480 32
    public static function isText($value = null)
481
    {
482 32
        $value = self::flattenSingleValue($value);
483
484 32
        return is_string($value) && !self::isError($value);
485
    }
486
487
    /**
488
     * IS_NONTEXT.
489
     *
490
     * @param mixed $value Value to check
491
     *
492
     * @return bool
493
     */
494 16
    public static function isNonText($value = null)
495
    {
496 16
        return !self::isText($value);
497
    }
498
499
    /**
500
     * N.
501
     *
502
     * Returns a value converted to a number
503
     *
504
     * @param value The value you want converted
505
     * @param null|mixed $value
506
     *
507
     * @return number N converts values listed in the following table
508
     *        If value is or refers to N returns
509
     *        A number            That number
510
     *        A date                The serial number of that date
511
     *        TRUE                1
512
     *        FALSE                0
513
     *        An error value        The error value
514
     *        Anything else        0
515
     */
516 20
    public static function n($value = null)
517
    {
518 20
        while (is_array($value)) {
519 9
            $value = array_shift($value);
520
        }
521
522 20
        switch (gettype($value)) {
523 20
            case 'double':
524 19
            case 'float':
525 19
            case 'integer':
526 8
                return $value;
527 12
            case 'boolean':
528 1
                return (int) $value;
529 11
            case 'string':
530
                //    Errors
531 8
                if ((strlen($value) > 0) && ($value[0] == '#')) {
532 2
                    return $value;
533
                }
534 6
                break;
535
        }
536
537 9
        return 0;
538
    }
539
540
    /**
541
     * TYPE.
542
     *
543
     * Returns a number that identifies the type of a value
544
     *
545
     * @param value The value you want tested
546
     * @param null|mixed $value
547
     *
548
     * @return number N converts values listed in the following table
549
     *        If value is or refers to N returns
550
     *        A number            1
551
     *        Text                2
552
     *        Logical Value        4
553
     *        An error value        16
554
     *        Array or Matrix        64
555
     */
556 16
    public static function TYPE($value = null)
557
    {
558 16
        $value = self::flattenArrayIndexed($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, PhpOffice\PhpSpreadsheet...::flattenArrayIndexed() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
559 16
        if (is_array($value) && (count($value) > 1)) {
560 3
            end($value);
561 3
            $a = key($value);
562
            //    Range of cells is an error
563 3
            if (self::isCellValue($a)) {
564
                return 16;
565
                //    Test for Matrix
566 3
            } elseif (self::isMatrixValue($a)) {
567 3
                return 64;
568
            }
569
        } elseif (empty($value)) {
570
            //    Empty Cell
571 2
            return 1;
572
        }
573 11
        $value = self::flattenSingleValue($value);
574
575 11
        if (($value === null) || (is_float($value)) || (is_int($value))) {
576 4
            return 1;
577 7
        } elseif (is_bool($value)) {
578 1
            return 4;
579 6
        } elseif (is_array($value)) {
580
            return 64;
581 6
        } elseif (is_string($value)) {
582
            //    Errors
583 6
            if ((strlen($value) > 0) && ($value[0] == '#')) {
584 2
                return 16;
585
            }
586
587 4
            return 2;
588
        }
589
590
        return 0;
591
    }
592
593
    /**
594
     * Convert a multi-dimensional array to a simple 1-dimensional array.
595
     *
596
     * @param array $array Array to be flattened
597
     *
598
     * @return array Flattened array
599
     */
600 282
    public static function flattenArray($array)
601
    {
602 282
        if (!is_array($array)) {
603
            return (array) $array;
604
        }
605
606 282
        $arrayValues = [];
607 282
        foreach ($array as $value) {
608 257
            if (is_array($value)) {
609 55
                foreach ($value as $val) {
610 55
                    if (is_array($val)) {
611 25
                        foreach ($val as $v) {
612 25
                            $arrayValues[] = $v;
613
                        }
614
                    } else {
615 55
                        $arrayValues[] = $val;
616
                    }
617
                }
618
            } else {
619 217
                $arrayValues[] = $value;
620
            }
621
        }
622
623 282
        return $arrayValues;
624
    }
625
626
    /**
627
     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing.
628
     *
629
     * @param array $array Array to be flattened
630
     *
631
     * @return array Flattened array
632
     */
633 18
    public static function flattenArrayIndexed($array)
634
    {
635 18
        if (!is_array($array)) {
636 11
            return (array) $array;
637
        }
638
639 7
        $arrayValues = [];
640 7
        foreach ($array as $k1 => $value) {
641 7
            if (is_array($value)) {
642 4
                foreach ($value as $k2 => $val) {
643 4
                    if (is_array($val)) {
644 2
                        foreach ($val as $k3 => $v) {
645 2
                            $arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v;
646
                        }
647
                    } else {
648 4
                        $arrayValues[$k1 . '.' . $k2] = $val;
649
                    }
650
                }
651
            } else {
652 3
                $arrayValues[$k1] = $value;
653
            }
654
        }
655
656 7
        return $arrayValues;
657
    }
658
659
    /**
660
     * Convert an array to a single scalar value by extracting the first element.
661
     *
662
     * @param mixed $value Array or scalar value
663
     *
664
     * @return mixed
665
     */
666 3121
    public static function flattenSingleValue($value = '')
667
    {
668 3121
        while (is_array($value)) {
669 34
            $value = array_pop($value);
670
        }
671
672 3121
        return $value;
673
    }
674
}
675