UseSortFixer::sortGroup()   B
last analyzed

Complexity

Conditions 7
Paths 7

Size

Total Lines 34

Duplication

Lines 20
Ratio 58.82 %

Code Coverage

Tests 12
CRAP Score 14.6516

Importance

Changes 0
Metric Value
dl 20
loc 34
ccs 12
cts 26
cp 0.4615
rs 8.4426
c 0
b 0
f 0
cc 7
nc 7
nop 1
crap 14.6516
1
<?php
2
3
namespace Recca0120\Generator\Fixers;
4
5
// from https://github.com/mmoreram/php-formatter.git
6
class UseSortFixer
7
{
8
    /**
9
     * @var int
10
     *
11
     * Sort type Alphabetic
12
     */
13
    const SORT_TYPE_ALPHABETIC = 'alph';
14
15
    /**
16
     * @var int
17
     *
18
     * Sort type length
19
     */
20
    const SORT_TYPE_LENGTH = 'length';
21
22
    /**
23
     * @var int
24
     *
25
     * Sort direction ascendent
26
     */
27
    const SORT_DIRECTION_ASC = 'asc';
28
29
    /**
30
     * @var int
31
     *
32
     * Sort direction descendent
33
     */
34
    const SORT_DIRECTION_DESC = 'desc';
35
36
    /**
37
     * @var int
38
     *
39
     * Group type one USE
40
     */
41
    const GROUP_TYPE_ONE = 'one';
42
43
    /**
44
     * @var int
45
     *
46
     * Group type each USE
47
     */
48
    const GROUP_TYPE_EACH = 'each';
49
50
    /**
51
     * @var array
52
     *
53
     * Groups
54
     */
55
    private $groups = [];
56
57
    /**
58
     * @var int
59
     *
60
     * Sort type
61
     */
62
    private $sortType = self::SORT_TYPE_ALPHABETIC;
63
64
    /**
65
     * @var int
66
     *
67
     * Sort direction
68
     */
69
    private $sortDirection = self::SORT_DIRECTION_ASC;
70
71
    /**
72
     * @var int
73
     *
74
     * Group type
75
     */
76
    private $groupType = self::GROUP_TYPE_EACH;
77
78
    /**
79
     * @var bool
80
     *
81
     * Skip empty groups
82
     */
83
    private $groupSkipEmpty = false;
84
85
    /**
86
     * Sets Groups.
87
     *
88
     * @param array $groups
89
     *
90
     * @return UseSortFixer
91
     */
92
    public function setGroups($groups)
93
    {
94
        $this->groups = $groups;
95
96
        return $this;
97
    }
98
99
    /**
100
     * Sets SortDirection.
101
     *
102
     * @param mixed $sortDirection
103
     *
104
     * @return UseSortFixer
105
     */
106
    public function setSortDirection($sortDirection)
107
    {
108
        $this->sortDirection = $sortDirection;
109
110
        return $this;
111
    }
112
113
    /**
114
     * Sets SortType.
115
     *
116
     * @param mixed $sortType
117
     *
118
     * @return UseSortFixer
119
     */
120 5
    public function setSortType($sortType)
121
    {
122 5
        $this->sortType = $sortType;
123
124 5
        return $this;
125
    }
126
127
    /**
128
     * Sets GroupType.
129
     *
130
     * @param int $groupType
131
     *
132
     * @return UseSortFixer
133
     */
134
    public function setGroupType($groupType)
135
    {
136
        $this->groupType = $groupType;
137
138
        return $this;
139
    }
140
141
    /**
142
     * Sets GroupSkipEmpty.
143
     *
144
     * @param bool $groupSkipEmpty
145
     *
146
     * @return UseSortFixer
147
     */
148
    public function setGroupSkipEmpty($groupSkipEmpty)
149
    {
150
        $this->groupSkipEmpty = $groupSkipEmpty;
151
152
        return $this;
153
    }
154
155
    /**
156
     * Do the fix. Return the fixed code or false if the code has not changed.
157
     *
158
     * @param string $data
159
     *
160
     * @return string|false
161
     */
162 5
    public function fix($data)
163
    {
164 5
        $regex = '/(\s*(?:(?:\s+use\s+?[\w\\\\\,\s]+?;)+)\s+)/s';
165 5
        preg_match($regex, $data, $results);
166 5
        if (! isset($results[0])) {
167 2
            return false;
168
        }
169 4
        $result = $results[0];
170 4
        $blocks = explode(';', $result);
171 4
        $namespaces = [];
172 4
        foreach ($blocks as $block) {
173
            /**
174
             * Removing use literal.
175
             */
176 4
            $block = trim(preg_replace('/^\s+use\s+/', '', $block));
177 4
            $namespaces = array_merge(
178 4
                $namespaces,
179 4
                explode(',', $block)
180 4
            );
181 4
        }
182
        /**
183
         * Trim all results of blank spaces and line breaks.
184
         */
185
        $namespaces = array_map(function ($namespace) {
186 4
            return trim($namespace);
187 4
        }, $namespaces);
188
        /**
189
         * If any position becomes empty, removes.
190
         */
191
        $namespaces = array_filter($namespaces, function ($namespace) {
192 4
            return ! empty($namespace);
193 4
        });
194
        /**
195
         * Grouping use statements by blocks defined in blocks variable.
196
         */
197 4
        $groups = $this->createGroups($namespaces);
198
        /*
199
         * Every block is sorted as desired
200
         */
201 4
        foreach ($groups as $groupKey => $group) {
202 4
            if (is_int($groupKey)) {
203
                $subGroupSorted = [];
204
                foreach ($group as $subGroupKey => $subGroup) {
205
                    $subGroupSorted = array_merge($subGroupSorted, $this->sortGroup($subGroup));
206
                }
207
                $groups[$groupKey] = $subGroupSorted;
208
            } else {
209 4
                $groups[$groupKey] = $this->sortGroup($group);
210
            }
211
            //  Remove empty groups (if configured) after the sorting has happened.
212
            //  @see https://github.com/mmoreram/php-formatter/issues/24
213 4
            if (0 === count($groups[$groupKey])) {
214
                unset($groups[$groupKey]);
215
            }
216 4
        }
217 4
        $doubleEOL = PHP_EOL.PHP_EOL;
218 4
        $spaceBetweenGroups = $this->groupSkipEmpty
219 4
            ? PHP_EOL
220 4
            : $doubleEOL;
221 4
        $processedResult = $doubleEOL.trim(implode($spaceBetweenGroups, array_map(
222
                    function ($group) {
223 4
                        return $this->renderGroup($group);
224 4
                    }, $groups)
225 4
            )).$doubleEOL;
226 4
        $fixedData = str_replace($result, $processedResult, $data);
227
228
        return $fixedData !== $data
229 4
            ? $fixedData
230 4
            : false;
231
    }
232
233
    /**
234
     * Create blocks.
235
     *
236
     * @param array $namespaces
237
     *
238
     * @return array Groups
239
     */
240 4
    private function createGroups(array $namespaces)
241
    {
242 4
        $groups = [];
243 4
        foreach ($this->groups as $group) {
244
            if (is_array($group)) {
245
                $groups[] = array_fill_keys($group, []);
246
            } else {
247
                $groups[$group] = [];
248
            }
249 4
        }
250 4
        if (! array_key_exists('_main', $groups)) {
251 4
            $groups = array_merge(
252 4
                ['_main' => []],
253
                $groups
254 4
            );
255 4
        }
256 4
        foreach ($namespaces as $namespace) {
257 4
            foreach ($groups as $groupKey => $group) {
258 4
                if (is_int($groupKey)) {
259
                    foreach ($group as $subGroupKey => $subGroup) {
260 View Code Duplication
                        if (strpos($namespace, $subGroupKey) === 0) {
261
                            array_push($groups[$groupKey][$subGroupKey], $namespace);
262
                            continue 3;
263
                        }
264
                    }
265 4 View Code Duplication
                } elseif (is_string($groupKey) && strpos($namespace, $groupKey) === 0) {
266
                    array_push($groups[$groupKey], $namespace);
267
                    continue 2;
268
                }
269 4
            }
270 4
            array_push($groups['_main'], $namespace);
271 4
        }
272
273 4
        return $groups;
274
    }
275
276
    /**
277
     * Sort a group.
278
     *
279
     * @param array $group
280
     *
281
     * @return array $group Sorted
282
     */
283 4
    private function sortGroup(array $group)
284
    {
285 4
        if (empty($group)) {
286
            return [];
287
        }
288 4
        if ($this->sortType == self::SORT_TYPE_LENGTH) {
289 View Code Duplication
            usort($group, function ($a, $b) {
290 3
                $cmp = strlen($b) - strlen($a);
291 3
                if ($cmp === 0) {
292
                    $a = strtolower($a);
293
                    $b = strtolower($b);
294
                    $cmp = strcmp($b, $a);
295
                }
296
297 3
                return $cmp;
298 4
            });
299 4
        } elseif ($this->sortType == self::SORT_TYPE_ALPHABETIC) {
300 View Code Duplication
            usort($group, function ($a, $b) {
301
                $a = strtolower($a);
302
                $b = strtolower($b);
303
                $cmp = strcmp($b, $a);
304
                if ($cmp === 0) {
305
                    $cmp = strlen($b) - strlen($a);
306
                }
307
308
                return $cmp;
309
            });
310
        }
311 4
        if ($this->sortDirection == self::SORT_DIRECTION_ASC) {
312 4
            $group = array_reverse($group);
313 4
        }
314
315 4
        return $group;
316
    }
317
318
    /**
319
     * Render a group.
320
     *
321
     * @param array $group
322
     *
323
     * @return string Group rendered
324
     */
325 4
    private function renderGroup(array $group)
326
    {
327 4
        if (empty($group)) {
328
            return '';
329
        }
330 4
        if ($this->groupType === self::GROUP_TYPE_EACH) {
331 4
            return implode(PHP_EOL, array_map(function ($namespace) {
332 4
                return 'use '.$namespace.';';
333 4
            }, $group));
334
        } elseif ($this->groupType === self::GROUP_TYPE_ONE) {
335
            $group = implode(','.PHP_EOL.'    ', $group);
336
337
            return 'use '.$group.';';
338
        }
339
    }
340
}
341