Passed
Push — master ( 41da84...3cb7b3 )
by
unknown
13:24 queued 13s
created

Text   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Test Coverage

Coverage 99.02%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 42
eloc 88
c 2
b 0
f 0
dl 0
loc 229
ccs 101
cts 102
cp 0.9902
rs 9.0399

10 Methods

Rating   Name   Duplication   Size   Complexity  
A applyPadding() 0 13 2
A formatValueMode0() 0 7 3
B fromArray() 0 15 7
A buildDelimiter() 0 15 3
A formatValueMode1() 0 9 5
A matchFlags() 0 3 2
A length() 0 13 3
B split() 0 50 10
A exact() 0 14 4
A test() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like Text often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Text, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\TextData;
4
5
use Composer\Pcre\Preg;
6
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
7
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
8
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
9
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
10
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
11
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
12
13
class Text
14
{
15
    use ArrayEnabled;
16
17
    /**
18
     * LEN.
19
     *
20
     * @param mixed $value String Value
21
     *                         Or can be an array of values
22
     *
23
     * @return array|int|string If an array of values is passed for the argument, then the returned result
24
     *            will also be an array with matching dimensions
25
     */
26 47
    public static function length(mixed $value = ''): array|int|string
27
    {
28 47
        if (is_array($value)) {
29 10
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
30
        }
31
32
        try {
33 47
            $value = Helpers::extractString($value, true);
34 1
        } catch (CalcExp $e) {
35 1
            return $e->getMessage();
36
        }
37
38 46
        return mb_strlen($value, 'UTF-8');
39
    }
40
41
    /**
42
     * Compares two text strings and returns TRUE if they are exactly the same, FALSE otherwise.
43
     * EXACT is case-sensitive but ignores formatting differences.
44
     * Use EXACT to test text being entered into a document.
45
     *
46
     * @param mixed $value1 String Value
47
     *                         Or can be an array of values
48
     * @param mixed $value2 String Value
49
     *                         Or can be an array of values
50
     *
51
     * @return array|bool|string If an array of values is passed for either of the arguments, then the returned result
52
     *            will also be an array with matching dimensions
53
     */
54 14
    public static function exact(mixed $value1, mixed $value2): array|bool|string
55
    {
56 14
        if (is_array($value1) || is_array($value2)) {
57 11
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $value1, $value2);
58
        }
59
60
        try {
61 14
            $value1 = Helpers::extractString($value1, true);
62 13
            $value2 = Helpers::extractString($value2, true);
63 1
        } catch (CalcExp $e) {
64 1
            return $e->getMessage();
65
        }
66
67 13
        return $value2 === $value1;
68
    }
69
70
    /**
71
     * T.
72
     *
73
     * @param mixed $testValue Value to check
74
     *                         Or can be an array of values
75
     *
76
     * @return array|string If an array of values is passed for the argument, then the returned result
77
     *            will also be an array with matching dimensions
78
     */
79 10
    public static function test(mixed $testValue = ''): array|string
80
    {
81 10
        if (is_array($testValue)) {
82 8
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $testValue);
83
        }
84
85 10
        if (is_string($testValue)) {
86 6
            return $testValue;
87
        }
88
89 7
        return '';
90
    }
91
92
    /**
93
     * TEXTSPLIT.
94
     *
95
     * @param mixed $text the text that you're searching
96
     * @param null|array|string $columnDelimiter The text that marks the point where to spill the text across columns.
97
     *                          Multiple delimiters can be passed as an array of string values
98
     * @param null|array|string $rowDelimiter The text that marks the point where to spill the text down rows.
99
     *                          Multiple delimiters can be passed as an array of string values
100
     * @param bool $ignoreEmpty Specify FALSE to create an empty cell when two delimiters are consecutive.
101
     *                              true = create empty cells
102
     *                              false = skip empty cells
103
     *                              Defaults to TRUE, which creates an empty cell
104
     * @param bool $matchMode Determines whether the match is case-sensitive or not.
105
     *                              true = case-sensitive
106
     *                              false = case-insensitive
107
     *                         By default, a case-sensitive match is done.
108
     * @param mixed $padding The value with which to pad the result.
109
     *                              The default is #N/A.
110
     *
111
     * @return array|string the array built from the text, split by the row and column delimiters, or an error string
112
     */
113 13
    public static function split(mixed $text, $columnDelimiter = null, $rowDelimiter = null, bool $ignoreEmpty = false, bool $matchMode = true, mixed $padding = '#N/A'): array|string
114
    {
115 13
        $text = Functions::flattenSingleValue($text);
116 13
        if (ErrorValue::isError($text, true)) {
117 1
            return StringHelper::convertToString($text);
118
        }
119
120 12
        $flags = self::matchFlags($matchMode);
121
122 12
        if ($rowDelimiter !== null) {
123 7
            $delimiter = self::buildDelimiter($rowDelimiter);
124 7
            $rows = ($delimiter === '()')
125
                ? [$text]
126 7
                : Preg::split("/{$delimiter}/{$flags}", StringHelper::convertToString($text));
127
        } else {
128 5
            $rows = [$text];
129
        }
130
131 12
        if ($ignoreEmpty === true) {
132 1
            $rows = array_values(array_filter(
133 1
                $rows,
134 1
                fn ($row): bool => $row !== ''
135 1
            ));
136
        }
137
138 12
        if ($columnDelimiter !== null) {
139 12
            $delimiter = self::buildDelimiter($columnDelimiter);
140 12
            array_walk(
141 12
                $rows,
142 12
                function (&$row) use ($delimiter, $flags, $ignoreEmpty): void {
143 12
                    $row = ($delimiter === '()')
144 2
                        ? [$row]
145 10
                        : Preg::split("/{$delimiter}/{$flags}", StringHelper::convertToString($row));
146 12
                    if ($ignoreEmpty === true) {
147 1
                        $row = array_values(array_filter(
148 1
                            $row,
149 1
                            fn ($value): bool => $value !== ''
150 1
                        ));
151
                    }
152 12
                }
153 12
            );
154 12
            if ($ignoreEmpty === true) {
155 1
                $rows = array_values(array_filter(
156 1
                    $rows,
157 1
                    fn ($row): bool => $row !== [] && $row !== ['']
158 1
                ));
159
            }
160
        }
161
162 12
        return self::applyPadding($rows, $padding);
163
    }
164
165 12
    private static function applyPadding(array $rows, mixed $padding): array
166
    {
167 12
        $columnCount = array_reduce(
168 12
            $rows,
169 12
            fn (int $counter, array $row): int => max($counter, count($row)),
170 12
            0
171 12
        );
172
173 12
        return array_map(
174 12
            fn (array $row): array => (count($row) < $columnCount)
175 3
                    ? array_merge($row, array_fill(0, $columnCount - count($row), $padding))
176 12
                    : $row,
177 12
            $rows
178 12
        );
179
    }
180
181
    /**
182
     * @param null|array|string $delimiter the text that marks the point before which you want to split
183
     *                                 Multiple delimiters can be passed as an array of string values
184
     */
185 12
    private static function buildDelimiter($delimiter): string
186
    {
187 12
        $valueSet = Functions::flattenArray($delimiter);
188
189 12
        if (is_array($delimiter) && count($valueSet) > 1) {
190 3
            $quotedDelimiters = array_map(
191 3
                fn ($delimiter): string => preg_quote($delimiter ?? '', '/'),
192 3
                $valueSet
193 3
            );
194 3
            $delimiters = implode('|', $quotedDelimiters);
195
196 3
            return '(' . $delimiters . ')';
197
        }
198
199 10
        return '(' . preg_quote(StringHelper::convertToString(Functions::flattenSingleValue($delimiter)), '/') . ')';
200
    }
201
202 12
    private static function matchFlags(bool $matchMode): string
203
    {
204 12
        return ($matchMode === true) ? 'miu' : 'mu';
205
    }
206
207 2
    public static function fromArray(array $array, int $format = 0): string
208
    {
209 2
        $result = [];
210 2
        foreach ($array as $row) {
211 2
            $cells = [];
212 2
            foreach ($row as $cellValue) {
213 2
                $value = ($format === 1) ? self::formatValueMode1($cellValue) : self::formatValueMode0($cellValue);
214 2
                $cells[] = $value;
215
            }
216 2
            $result[] = implode(($format === 1) ? ',' : ', ', $cells);
217
        }
218
219 2
        $result = implode(($format === 1) ? ';' : ', ', $result);
220
221 2
        return ($format === 1) ? '{' . $result . '}' : $result;
222
    }
223
224 1
    private static function formatValueMode0(mixed $cellValue): string
225
    {
226 1
        if (is_bool($cellValue)) {
227 1
            return Calculation::getLocaleBoolean($cellValue ? 'TRUE' : 'FALSE');
228
        }
229
230 1
        return StringHelper::convertToString($cellValue);
231
    }
232
233 1
    private static function formatValueMode1(mixed $cellValue): string
234
    {
235 1
        if (is_string($cellValue) && ErrorValue::isError($cellValue) === false) {
236 1
            return Calculation::FORMULA_STRING_QUOTE . $cellValue . Calculation::FORMULA_STRING_QUOTE;
237 1
        } elseif (is_bool($cellValue)) {
238 1
            return Calculation::getLocaleBoolean($cellValue ? 'TRUE' : 'FALSE');
239
        }
240
241 1
        return StringHelper::convertToString($cellValue);
242
    }
243
}
244