Completed
Push — master ( 166358...a3a10e )
by Vitaly
03:51
created

StructureSorter::compareStringStructure()   C

Complexity

Conditions 16
Paths 140

Size

Total Lines 63
Code Lines 27

Duplication

Lines 14
Ratio 22.22 %

Importance

Changes 0
Metric Value
dl 14
loc 63
rs 5.5345
c 0
b 0
f 0
cc 16
eloc 27
nc 140
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 05.04.17 at 15:18
5
 */
6
namespace samsonframework\stringconditiontree;
7
8
/**
9
 * Parametrized strings sorting.
10
 *
11
 * @author Vitaly Egorov <[email protected]>
12
 */
13
class StructureSorter
14
{
15
    /** Variable length characters group */
16
    const G_VARIABLE = 0;
17
18
    /** Fixed length characters group */
19
    const G_FIXED = 1;
20
21
    /** @var string Parametrized string start marker */
22
    protected $parameterStartMarker;
23
24
    /** @var string Parametrized string end marker */
25
    protected $parameterEndMarker;
26
27
    /**
28
     * StructureSorter constructor.
29
     *
30
     * @param string $parameterStartMarker Parametrized string start marker
31
     * @param string $parameterEndMarker Parametrized string end marker
32
     */
33
    public function __construct(string $parameterStartMarker, string $parameterEndMarker)
34
    {
35
        $this->parameterStartMarker = $parameterStartMarker;
36
        $this->parameterEndMarker = $parameterEndMarker;
37
    }
38
39
    /**
40
     * Sort strings array considering PCG and NPCG string structure.
41
     *
42
     * @param array $input Input array for sorting
43
     *
44
     * @return array Sorted keys array
45
     */
46
    public function sortArrayByKeys(array $input): array
47
    {
48
        // Convert string array keys into structure arrays
49
        $prefixes = array_map([$this, 'getPrefixStructure'], array_keys($input));
50
51
        // Sort parametrized string array according sorting rules
52
        usort($prefixes, [$this, 'compareStringStructure']);
53
54
        // Restore initial strings sub-arrays
55
        $result = [];
56
        foreach ($prefixes as $sortingData) {
57
            $result[$sortingData[0][2]] = $input[$sortingData[0][2]];
58
        }
59
        return $result;
60
    }
61
62
    /**
63
     * Build string character group structure considering parametrized
64
     * and not parametrized character groups and their length(PCG, NPCG).
65
     *
66
     * @param string $prefix Prefix string
67
     *
68
     * @return array String character groups structure
69
     */
70
    protected function getPrefixStructure(string $prefix): array
71
    {
72
        /** @var array $structureMatrix String PCG(0)/NPCG(1) structure matrix for comparison */
73
        $structureMatrix = [];
74
75
        // Flags for showing current string character group
76
        /** @var bool $isPCG Flags showing PCG started */
77
        $isPCG = false;
78
        /** @var bool $isNPCG Flags showing NPCG started */
79
        $isNPCG = true;
80
81
        // Pointer to current CG to count string NPCG length
82
        $currentCG = 0;
83
84
        /**
85
         * TODO: Try to find PCG filter :... pattern and process it also as
86
         * PCG with filters should be prioritized over PSG without filter
87
         * even if filter is .*
88
         */
89
90
        // Iterate string by characters
91
        for ($i = 0, $length = strlen($prefix); $i < $length; $i++) {
92
            if (!$isPCG && $prefix{$i} === $this->parameterStartMarker) {
93
                $isPCG = true;
94
                $isNPCG = false;
95
                $structureMatrix[] = [0, 0, $prefix];
96
                $currentCG = &$structureMatrix[count($structureMatrix) - 1][1];
97
            } elseif ($isPCG && $prefix{$i} === $this->parameterEndMarker) {
98
                $isPCG = false;
99
                $isNPCG = true;
100
            } elseif ($isNPCG) {
101
                $isNPCG = false;
102
                $structureMatrix[] = [1, 0, $prefix];
103
                $currentCG = &$structureMatrix[count($structureMatrix) - 1][1];
104
            }
105
106
            // Store current character group length
107
            $currentCG++;
108
        }
109
110
        return $structureMatrix;
111
    }
112
113
    /**
114
     * Compare string structures.
115
     *
116
     * @param array $initial  Initial string structure
117
     * @param array $compared Compared string structure
118
     *
119
     * @return int Result of array elements comparison
120
     */
121
    protected function compareStringStructure(array $initial, array $compared): int
122
    {
123
        $maxStructureSize = max(count($initial), count($compared));
124
125
        // Make structures same size preserving previous existing structure value
126
        for ($i = 1; $i < $maxStructureSize; $i++) {
127
            if (!array_key_exists($i, $initial)) {
128
                $initial[$i] = $initial[$i - 1];
129
            }
130
            if (!array_key_exists($i, $compared)) {
131
                $compared[$i] = $compared[$i - 1];
132
            }
133
        }
134
135
        // Iterate every structure group
136
        for ($i = 0; $i < $maxStructureSize; $i++) {
137
            // If initial structure has NPCG than it has higher priority
138
            if ($initial[$i][0] > $compared[$i][0]) {
139
                return -1;
140
            }
141
142
            // If compared structure has NPCG than it has higher priority
143
            if ($initial[$i][0] < $compared[$i][0]) {
144
                return 1;
145
            }
146
147
            // Compare NOT starting NPCG length
148
            if ($i > 0 && $initial[$i][0] === 1) {
149
                if ($initial[$i][1] > $compared[$i][1]) {
150
                    return -1;
151
                }
152
153
                if ($initial[$i][1] < $compared[$i][1]) {
154
                    return 1;
155
                }
156
            }
157
158
            // They are equal continue to next structure group comparison
159
        }
160
161
        // If both structures are equal compare lengths of NPCG
162 View Code Duplication
        for ($i = 0; $i < $maxStructureSize; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
163
            // If current CG is NPCG
164
            if ($initial[$i][0] === 1) {
165
                if ($initial[$i][1] > $compared[$i][1]) {
166
                    return 1;
167
                }
168
169
                if ($initial[$i][1] < $compared[$i][1]) {
170
                    return -1;
171
                }
172
            }
173
174
            // Current NPCG character groups have equal length - continue
175
        }
176
177
        $return = $this->compareStructureLengths($maxStructureSize, $initial, $compared, self::G_FIXED);
178
        if ($return === 0) {
179
            $return = $this->compareStructureLengths($maxStructureSize, $initial, $compared, self::G_VARIABLE);
180
        }
181
182
        return $return;
183
    }
184
185
    /**
186
     * Compare two character group structure(CGS) length and define
187
     * which one is longer.
188
     *
189
     * @param int   $size CGS size
190
     * @param array $initial Initial CGS
191
     * @param array $compared Compared CGS
192
     * @param int   $type CGS type (Variable|Fixed length)
193
     *
194
     * @return int -1 if initial CGS longer
195
     *             0 if initial and compared CGS are equal
196
     *             1 if compared CGS longer
197
     */
198
    protected function compareStructureLengths(int $size, array $initial, array $compared, int $type = self::G_FIXED): int
199
    {
200
        // Iterate character group structures
201 View Code Duplication
        for ($i = 0; $i < $size; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
202
            // Check if character group matches passed character group type
203
            if ($initial[$i][$type] === $type) {
204
                // Compare character group length
205
                if ($initial[$i][1] > $compared[$i][1]) {
206
                    return -1;
207
                }
208
209
                if ($initial[$i][1] < $compared[$i][1]) {
210
                    return 1;
211
                }
212
213
                // Continue to next character group structure
214
            }
215
        }
216
217
        // Character group structures have equal length
218
        return 0;
219
    }
220
}
221