Completed
Push — master ( b490b9...ed4a79 )
by Jan-Petter
02:49
created

Import   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 277
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
wmc 42
lcom 2
cbo 1
dl 0
loc 277
rs 8.295
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
B arrayMergeRecursiveEx() 0 16 7
A buildHost() 0 7 2
A buildCleanParam() 0 10 3
A buildArray() 0 4 1
A buildUserAgent() 0 21 2
A buildString() 0 4 1
A buildVisitTime() 0 8 2
A buildRequestRate() 0 14 4
A getIgnoredImportData() 0 13 2
B arrayFilterRecursive() 0 12 5
A kSortRecursive() 0 11 4
B arrayDiffAssocRecursive() 0 16 8

How to fix   Complexity   

Complex Class

Complex classes like Import 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Import, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * vipnytt/RobotsTxtParser
4
 *
5
 * @link https://github.com/VIPnytt/RobotsTxtParser
6
 * @license https://github.com/VIPnytt/RobotsTxtParser/blob/master/LICENSE The MIT License (MIT)
7
 */
8
9
namespace vipnytt\RobotsTxtParser;
10
11
/**
12
 * Class Import
13
 *
14
 * @package vipnytt\RobotsTxtParser
15
 */
16
class Import extends TxtClient
17
{
18
    /**
19
     * Root level export template
20
     */
21
    const TEMPLATE_ROOT = [
22
        self::DIRECTIVE_CLEAN_PARAM => [],
23
        self::DIRECTIVE_HOST => null,
24
        self::DIRECTIVE_SITEMAP => [],
25
        self::DIRECTIVE_USER_AGENT => []
26
    ];
27
28
    /**
29
     * User-agent level export template
30
     */
31
    const TEMPLATE_SUB = [
32
        self::DIRECTIVE_ALLOW => [],
33
        self::DIRECTIVE_CACHE_DELAY => null,
34
        self::DIRECTIVE_COMMENT => [],
35
        self::DIRECTIVE_CRAWL_DELAY => null,
36
        self::DIRECTIVE_DISALLOW => [],
37
        self::DIRECTIVE_NO_INDEX => [],
38
        self::DIRECTIVE_REQUEST_RATE => [],
39
        self::DIRECTIVE_ROBOT_VERSION => null,
40
        self::DIRECTIVE_VISIT_TIME => [],
41
    ];
42
43
    /**
44
     * Array
45
     * @var array
46
     */
47
    private $array;
48
49
    /**
50
     * Import constructor.
51
     *
52
     * @param array $export
53
     * @param string $baseUri
54
     */
55
    public function __construct(array $export, $baseUri = 'https://example.com')
56
    {
57
        $this->array = $this->arrayMergeRecursiveEx(self::TEMPLATE_ROOT, $export);
58
        parent::__construct($baseUri, null, implode(PHP_EOL, array_merge(
59
            $this->buildHost($this->array[self::DIRECTIVE_HOST]),
60
            $this->buildCleanParam($this->array[self::DIRECTIVE_CLEAN_PARAM]),
61
            $this->buildArray($this->array[self::DIRECTIVE_SITEMAP], self::DIRECTIVE_SITEMAP),
62
            $this->buildUserAgent($this->array[self::DIRECTIVE_USER_AGENT])
63
        )));
64
    }
65
66
    /**
67
     * array_merge_recursive_ex
68
     * @link http://stackoverflow.com/a/25712428/4396537
69
     *
70
     * @param array $array1
71
     * @param array $array2
72
     * @return array
73
     */
74
    private function arrayMergeRecursiveEx(array $array1, array &$array2)
75
    {
76
        foreach ($array2 as $key => &$value) {
77
            if (is_array($value) &&
78
                isset($array1[$key]) &&
79
                is_array($array1[$key])
80
            ) {
81
                $array1[$key] = $this->arrayMergeRecursiveEx($array1[$key], $value);
82
            } elseif (!is_int($key)) {
83
                $array1[$key] = $value;
84
            } elseif (!in_array($value, $array1)) {
85
                $array1[] = $value;
86
            }
87
        }
88
        return $array1;
89
    }
90
91
    /**
92
     * Host
93
     *
94
     * @param string[]|string|null $array
95
     * @return string[]
96
     */
97
    private function buildHost($array)
98
    {
99
        if (!is_array($array)) {
100
            $array = [$array];
101
        }
102
        return preg_filter('/^/', self::DIRECTIVE_HOST . ':', $array);
103
    }
104
105
    /**
106
     * Clean-param
107
     *
108
     * @param string[][] $array
109
     * @return string[]
110
     */
111
    private function buildCleanParam($array)
112
    {
113
        $result = [];
114
        foreach ($array as $param => $paths) {
115
            foreach ($paths as $path) {
116
                $result[] = self::DIRECTIVE_CLEAN_PARAM . ':' . $param . ' ' . $path;
117
            }
118
        }
119
        return $result;
120
    }
121
122
    /**
123
     * Comment | Sitemap
124
     *
125
     * @param string[] $array
126
     * @param string $directive
127
     * @return string[]
128
     */
129
    private function buildArray($array, $directive)
130
    {
131
        return preg_filter('/^/', $directive . ':', $array);
132
    }
133
134
    /**
135
     * User-agent
136
     *
137
     * @param array $array
138
     * @return string[]
139
     */
140
    private function buildUserAgent($array)
141
    {
142
        $result = [];
143
        foreach ($array as $userAgent => $rules) {
144
            $rules = $this->arrayMergeRecursiveEx(self::TEMPLATE_SUB, $rules);
145
            $result = array_merge(
146
                $result,
147
                [self::DIRECTIVE_USER_AGENT . ':' . $userAgent],
148
                $this->buildString($rules[self::DIRECTIVE_ROBOT_VERSION], self::DIRECTIVE_ROBOT_VERSION),
149
                $this->buildVisitTime($rules[self::DIRECTIVE_VISIT_TIME]),
150
                $this->buildArray($rules[self::DIRECTIVE_NO_INDEX], self::DIRECTIVE_NO_INDEX),
151
                $this->buildArray($rules[self::DIRECTIVE_DISALLOW], self::DIRECTIVE_DISALLOW),
152
                $this->buildArray($rules[self::DIRECTIVE_ALLOW], self::DIRECTIVE_ALLOW),
153
                $this->buildString($rules[self::DIRECTIVE_CRAWL_DELAY], self::DIRECTIVE_CRAWL_DELAY),
154
                $this->buildString($rules[self::DIRECTIVE_CACHE_DELAY], self::DIRECTIVE_CACHE_DELAY),
155
                $this->buildRequestRate($rules[self::DIRECTIVE_REQUEST_RATE]),
156
                $this->buildArray($rules[self::DIRECTIVE_COMMENT], self::DIRECTIVE_COMMENT)
157
            );
158
        }
159
        return $result;
160
    }
161
162
    /**
163
     * Cache-delay | Comment | Crawl-delay | Robot-version
164
     *
165
     * @param float|int|string|null $value
166
     * @param string $directive
167
     * @return string[]
168
     */
169
    private function buildString($value, $directive)
170
    {
171
        return [$directive . ':' . $value];
172
    }
173
174
    /**
175
     * Visit-time
176
     *
177
     * @param int[]|string[] $array
178
     * @return string[]
179
     */
180
    private function buildVisitTime($array)
181
    {
182
        $result = [];
183
        foreach ($array as $pair) {
184
            $result[] = self::DIRECTIVE_VISIT_TIME . ':' . $pair['from'] . '-' . $pair['to'];
185
        }
186
        return $result;
187
    }
188
189
    /**
190
     * Request-rate
191
     *
192
     * @param array $array
193
     * @return string[]
194
     */
195
    private function buildRequestRate($array)
196
    {
197
        $result = [];
198
        foreach ($array as $pair) {
199
            $string = self::DIRECTIVE_REQUEST_RATE . ':1/' . $pair['rate'] . 's';
200
            if (isset($pair['from']) &&
201
                isset($pair['to'])
202
            ) {
203
                $string .= ' ' . $pair['from'] . '-' . $pair['to'];
204
            }
205
            $result[] = $string;
206
        }
207
        return $result;
208
    }
209
210
    /**
211
     * Get difference
212
     *
213
     * @return array
214
     */
215
    public function getIgnoredImportData()
216
    {
217
        $pair = [
218
            'source' => $this->array,
219
            'parsed' => $this->export(),
220
        ];
221
        foreach ($pair as &$array) {
222
            $array = $this->arrayFilterRecursive($array);
223
            array_multisort($array);
224
            $this->kSortRecursive($array);
225
        }
226
        return $this->arrayDiffAssocRecursive($pair['source'], $pair['parsed']);
227
    }
228
229
    /**
230
     * array_filter_recursive
231
     * @link http://php.net/manual/en/function.array-filter.php#87581
232
     *
233
     * @param array $array
234
     * @return array
235
     */
236
    private function arrayFilterRecursive(array &$array)
237
    {
238
        foreach ($array as $key => &$item) {
239
            is_array($item) && $array[$key] = $this->arrayFilterRecursive($item);
240
            if ($array[$key] === null ||
241
                $array[$key] === []
242
            ) {
243
                unset($array[$key]);
244
            }
245
        }
246
        return $array;
247
    }
248
249
    /**
250
     * ksort_recursive
251
     * @link http://stackoverflow.com/a/2543447/4396537
252
     *
253
     * @param array $array
254
     * @return bool
255
     */
256
    private function kSortRecursive(array &$array)
257
    {
258
        foreach ($array as &$current) {
259
            if (is_array($current) &&
260
                $this->kSortRecursive($current) === false
261
            ) {
262
                return false;
263
            }
264
        }
265
        return ksort($array);
266
    }
267
268
    /**
269
     * array_diff_assoc_recursive
270
     * @link http://php.net/manual/en/function.array-diff-assoc.php#111675
271
     *
272
     * @param array $array1
273
     * @param array $array2
274
     * @return array
275
     */
276
    private function arrayDiffAssocRecursive(array &$array1, array &$array2)
277
    {
278
        $difference = [];
279
        foreach ($array1 as $key => &$value) {
280
            if (is_array($value)) {
281
                if (!isset($array2[$key]) || !is_array($array2[$key])) {
282
                    $difference[$key] = $value;
283
                } elseif (!empty($newDiff = $this->arrayDiffAssocRecursive($value, $array2[$key]))) {
284
                    $difference[$key] = $newDiff;
285
                }
286
            } elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
287
                $difference[$key] = $value;
288
            }
289
        }
290
        return $difference;
291
    }
292
}
293