Completed
Pull Request — master (#1596)
by Thomas
32:17
created

DivisionDataValidator::checkPlatformProperties()   B

Complexity

Conditions 10
Paths 2

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 7.2765
c 0
b 0
f 0
cc 10
eloc 11
nc 2
nop 2

How to fix   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
2
declare(strict_types = 1);
3
namespace Browscap\Data\Validator;
4
5
use Assert\Assertion;
6
7
class DivisionDataValidator implements ValidatorInterface
8
{
9
    /**
10
     * valdates the structure of a division
11
     *
12
     * @param array  $divisionData  Data to validate
13
     * @param string $filename
14
     * @param array  &$allDivisions
15
     * @param bool   $isCore
16
     */
17
    public function validate(
18
        array $divisionData,
19
        string $filename,
20
        array &$allDivisions = [],
21
        bool $isCore = false
22
    ) : void {
23
        Assertion::keyExists($divisionData, 'division', 'required attibute "division" is missing in File ' . $filename);
24
        Assertion::string($divisionData['division'], 'required attibute "division" has to be a string in File ' . $filename);
25
26
        Assertion::keyExists($divisionData, 'sortIndex', 'required attibute "sortIndex" is missing in File ' . $filename);
27
        Assertion::integer($divisionData['sortIndex'], 'required attibute "sortIndex" has to be a integer in File ' . $filename);
28
29
        if (!$isCore) {
30
            Assertion::greaterThan($divisionData['sortIndex'], 0, 'required attibute "sortIndex" has to be a positive integer in File ' . $filename);
31
        }
32
33
        Assertion::keyExists($divisionData, 'lite', 'required attibute "lite" is missing in File ' . $filename);
34
        Assertion::boolean($divisionData['lite'], 'required attibute "lite" has to be an boolean in File ' . $filename);
35
36
        Assertion::keyExists($divisionData, 'standard', 'required attibute "standard" is missing in File ' . $filename);
37
        Assertion::boolean($divisionData['standard'], 'required attibute "standard" has to be an boolean in File ' . $filename);
38
39
        Assertion::keyExists($divisionData, 'userAgents', 'required attibute "userAgents" is missing in File ' . $filename);
40
        Assertion::isArray($divisionData['userAgents'], 'required attibute "userAgents" should be an array in File ' . $filename);
41
        Assertion::notEmpty($divisionData['userAgents'], 'required attibute "userAgents" should be an non-empty array in File ' . $filename);
42
43 View Code Duplication
        if (isset($divisionData['versions']) && is_array($divisionData['versions'])) {
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...
44
            $versions = $divisionData['versions'];
45
        } else {
46
            $versions = ['0.0'];
47
        }
48
49
        foreach ($divisionData['userAgents'] as $index => $useragentData) {
50
            $this->validateUserAgentSection($useragentData, $versions, $allDivisions, $isCore, $filename, $index);
51
52
            $allDivisions[] = $useragentData['userAgent'];
53
        }
54
    }
55
56
    /**
57
     * @param array  $useragentData
58
     * @param array  $versions
59
     * @param array  $allDivisions
60
     * @param bool   $isCore
61
     * @param string $filename
62
     * @param int    $index
63
     */
64
    private function validateUserAgentSection(
65
        array $useragentData,
66
        array $versions,
67
        array $allDivisions,
68
        bool $isCore,
69
        string $filename,
70
        int $index
71
    ) : void {
72
        Assertion::keyExists($useragentData, 'userAgent', 'required attibute "userAgent" is missing in userAgents section ' . $index . ' in File ' . $filename);
73
        Assertion::string($useragentData['userAgent'], 'required attibute "userAgent" has to be a string in userAgents section ' . $index . ' in File ' . $filename);
74
75
        if (preg_match('/[\[\]]/', $useragentData['userAgent'])) {
76
            throw new \LogicException('required attibute "userAgent" includes invalid characters in userAgents section ' . $index . ' in File ' . $filename);
77
        }
78
79
        if (false === mb_strpos($useragentData['userAgent'], '#')
80
            && in_array($useragentData['userAgent'], $allDivisions)
81
        ) {
82
            throw new \LogicException('Division "' . $useragentData['userAgent'] . '" is defined twice in file "' . $filename . '"');
83
        }
84
85 View Code Duplication
        if ((false !== mb_strpos($useragentData['userAgent'], '#MAJORVER#')
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...
86
                || false !== mb_strpos($useragentData['userAgent'], '#MINORVER#'))
87
            && ['0.0'] === $versions
88
        ) {
89
            throw new \LogicException(
90
                'Division "' . $useragentData['userAgent']
91
                . '" is defined with version placeholders, but no versions are set in file "' . $filename . '"'
92
            );
93
        }
94
95 View Code Duplication
        if (false === mb_strpos($useragentData['userAgent'], '#MAJORVER#')
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...
96
            && false === mb_strpos($useragentData['userAgent'], '#MINORVER#')
97
            && ['0.0'] !== $versions
98
            && 1 < count($versions)
99
        ) {
100
            throw new \LogicException(
101
                'Division "' . $useragentData['userAgent']
102
                . '" is defined without version placeholders, but there are versions set in file "' . $filename . '"'
103
            );
104
        }
105
106
        Assertion::keyExists($useragentData, 'properties', 'required attibute "properties" is missing in userAgents section ' . $index . ' in File ' . $filename);
107
        Assertion::isArray($useragentData['properties'], 'required attibute "properties" should be an array in userAgents section ' . $index . ' in File ' . $filename);
108
        Assertion::notEmpty($useragentData['properties'], 'required attibute "properties" should be an non-empty array in userAgents section ' . $index . ' in File ' . $filename);
109
110
        if (!$isCore) {
111
            Assertion::keyExists($useragentData['properties'], 'Parent', 'the "Parent" property is missing for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
112
            Assertion::same($useragentData['properties']['Parent'], 'DefaultProperties', 'the "Parent" property is not linked to the "DefaultProperties" for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
113
        }
114
115
        Assertion::keyExists($useragentData['properties'], 'Comment', 'the "Comment" property is missing for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
116
        Assertion::string($useragentData['properties']['Comment'], 'the "Comment" property has to be a string for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
117
118
        if (!array_key_exists('Version', $useragentData['properties']) && ['0.0'] !== $versions) {
119
            throw new \LogicException(
120
                'the "Version" property is missing for key "' . $useragentData['userAgent'] . '" in file "' . $filename
121
                . '", but there are defined versions'
122
            );
123
        }
124
125
        if ($isCore) {
126
            return;
127
        }
128
129
        if (array_key_exists('Version', $useragentData['properties'])) {
130
            Assertion::string($useragentData['properties']['Version'], 'the "Version" property has to be a string for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
131
132 View Code Duplication
            if ((false !== mb_strpos($useragentData['properties']['Version'], '#MAJORVER#')
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...
133
                    || false !== mb_strpos($useragentData['properties']['Version'], '#MINORVER#'))
134
                && ['0.0'] === $versions) {
135
                throw new \LogicException(
136
                    'the "Version" property has version placeholders for key "' . $useragentData['userAgent'] . '" in file "' . $filename
137
                    . '", but no versions are defined'
138
                );
139
            }
140
141 View Code Duplication
            if (false === mb_strpos($useragentData['properties']['Version'], '#MAJORVER#')
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...
142
                && false === mb_strpos($useragentData['properties']['Version'], '#MINORVER#')
143
                && ['0.0'] !== $versions
144
                && 1 < count($versions)
145
            ) {
146
                throw new \LogicException(
147
                    'the "Version" property has no version placeholders for key "' . $useragentData['userAgent'] . '" in file "' . $filename
148
                    . '", but versions are defined'
149
                );
150
            }
151
        }
152
153
        $this->checkPlatformProperties(
154
            $useragentData['properties'],
155
            'the properties array contains platform data for key "' . $useragentData['userAgent']
156
            . '", please use the "platform" keyword'
157
        );
158
159
        $this->checkEngineProperties(
160
            $useragentData['properties'],
161
            'the properties array contains engine data for key "' . $useragentData['userAgent']
162
            . '", please use the "engine" keyword'
163
        );
164
165
        $this->checkDeviceProperties(
166
            $useragentData['properties'],
167
            'the properties array contains device data for key "' . $useragentData['userAgent']
168
            . '", please use the "device" keyword'
169
        );
170
171
        Assertion::keyExists($useragentData, 'children', 'required attibute "children" is missing in userAgents section ' . $index . ' in File ' . $filename);
172
        Assertion::isArray($useragentData['children'], 'required attibute "children" should be an array in userAgents section ' . $index . ' in File ' . $filename);
173
        Assertion::notEmpty($useragentData['children'], 'required attibute "children" should be an non-empty array in userAgents section ' . $index . ' in File ' . $filename);
174
175
        Assertion::keyNotExists($useragentData['children'], 'match', 'the children property shall not have the "match" entry for key "' . $useragentData['userAgent'] . '" in file "' . $filename . '"');
176
177
        foreach ($useragentData['children'] as $child) {
178
            Assertion::isArray($child, 'each entry of the children property has to be an array for key "' . $useragentData['userAgent'] . '"');
179
180
            $this->validateChildSection($child, $useragentData, $versions);
181
        }
182
    }
183
184
    /**
185
     * @param array $childData     The children section to be validated
186
     * @param array $useragentData The complete UserAgent section which is the parent of the children section
187
     * @param array $versions      The versions from the division
188
     *
189
     * @throws \LogicException
190
     */
191
    private function validateChildSection(array $childData, array $useragentData, array $versions) : void
192
    {
193
        if (array_key_exists('device', $childData) && array_key_exists('devices', $childData)) {
194
            throw new \LogicException(
195
                'a child entry may not define both the "device" and the "devices" entries for key "'
196
                . $useragentData['userAgent'] . '"'
197
            );
198
        }
199
200 View Code Duplication
        if (array_key_exists('devices', $childData)) {
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...
201
            Assertion::isArray($childData['devices'], 'the "devices" entry for key "' . $useragentData['userAgent'] . '" has to be an array');
202
203
            if (1 < count($childData['devices'])
204
                && false === mb_strpos($childData['match'], '#DEVICE#')
205
            ) {
206
                throw new \LogicException(
207
                    'the "devices" entry contains multiple devices but there is no #DEVICE# token for key "'
208
                    . $useragentData['userAgent'] . '"'
209
                );
210
            }
211
        }
212
213
        if (array_key_exists('device', $childData)) {
214
            Assertion::string($childData['device'], 'the "device" entry has to be a string for key "' . $useragentData['userAgent'] . '"');
215
        }
216
217
        Assertion::keyExists($childData, 'match', 'each entry of the children property requires an "match" entry for key "' . $useragentData['userAgent'] . '"');
218
        Assertion::string($childData['match'], 'the "match" entry for key "' . $useragentData['userAgent'] . '" has to be a string');
219
220
        if (preg_match('/[\[\]]/', $childData['match'])) {
221
            throw new \LogicException('key "' . $childData['match'] . '" includes invalid characters');
222
        }
223
224
        Assertion::notSame($childData['match'], $useragentData['userAgent'], 'the "match" entry is identical to its parents "userAgent" entry');
225
226
        if (false !== mb_strpos($childData['match'], '#PLATFORM#')
227
            && !array_key_exists('platforms', $childData)
228
        ) {
229
            throw new \LogicException(
230
                'the key "' . $childData['match']
231
                . '" is defined with platform placeholder, but no platforms are assigned'
232
            );
233
        }
234
235 View Code Duplication
        if (array_key_exists('platforms', $childData)) {
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...
236
            Assertion::isArray($childData['platforms'], 'the "platforms" entry for key "' . $useragentData['userAgent'] . '" has to be an array');
237
238
            if (1 < count($childData['platforms'])
239
                && false === mb_strpos($childData['match'], '#PLATFORM#')
240
            ) {
241
                throw new \LogicException(
242
                    'the "platforms" entry contains multiple platforms but there is no #PLATFORM# token for key "'
243
                    . $useragentData['userAgent'] . '"'
244
                );
245
            }
246
        }
247
248 View Code Duplication
        if ((false !== mb_strpos($childData['match'], '#MAJORVER#')
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...
249
                || false !== mb_strpos($childData['match'], '#MINORVER#'))
250
            && ['0.0'] === $versions
251
        ) {
252
            throw new \LogicException(
253
                'the key "' . $childData['match']
254
                . '" is defined with version placeholders, but no versions are set'
255
            );
256
        }
257
258
        if (false === mb_strpos($childData['match'], '#MAJORVER#')
259
            && false === mb_strpos($childData['match'], '#MINORVER#')
260
            && ['0.0'] !== $versions
261
            && 1 < count($versions)
262
        ) {
263
            if (!array_key_exists('platforms', $childData)) {
264
                throw new \LogicException(
265
                    'the key "' . $childData['match']
266
                    . '" is defined without version placeholders, but there are versions set'
267
                );
268
            }
269
270
            $dynamicPlatforms = false;
271
272
            foreach ($childData['platforms'] as $platform) {
273
                if (false !== mb_stripos($platform, 'dynamic')) {
274
                    $dynamicPlatforms = true;
275
276
                    break;
277
                }
278
            }
279
280
            if (!$dynamicPlatforms) {
281
                throw new \LogicException(
282
                    'the key "' . $childData['match']
283
                    . '" is defined without version placeholders, but there are versions set'
284
                );
285
            }
286
        }
287
288
        if (false !== mb_strpos($childData['match'], '#DEVICE#')
289
            && !array_key_exists('devices', $childData)
290
        ) {
291
            throw new \LogicException(
292
                'the key "' . $childData['match']
293
                . '" is defined with device placeholder, but no devices are assigned'
294
            );
295
        }
296
297
        if (array_key_exists('properties', $childData)) {
298
            Assertion::isArray($childData['properties'], 'the "properties" entry for key "' . $childData['match'] . '" has to be an array');
299
            Assertion::keyNotExists($childData['properties'], 'Parent', 'the Parent property must not set inside the children array for key "' . $childData['match'] . '"');
300
301
            if (array_key_exists('Version', $childData['properties'])
302
                && array_key_exists('properties', $useragentData)
303
                && array_key_exists('Version', $useragentData['properties'])
304
                && $useragentData['properties']['Version'] === $childData['properties']['Version']
305
            ) {
306
                throw new \LogicException(
307
                    'the "Version" property is set for key "' . $childData['match']
308
                    . '", but was already set for its parent "' . $useragentData['userAgent'] . '" with the same value'
309
                );
310
            }
311
312
            $this->checkPlatformProperties(
313
                $childData['properties'],
314
                'the properties array contains platform data for key "' . $childData['match']
315
                . '", please use the "platforms" keyword'
316
            );
317
318
            $this->checkEngineProperties(
319
                $childData['properties'],
320
                'the properties array contains engine data for key "' . $childData['match']
321
                . '", please use the "engine" keyword'
322
            );
323
324
            $this->checkDeviceProperties(
325
                $childData['properties'],
326
                'the properties array contains device data for key "' . $childData['match']
327
                . '", please use the "device" or the "devices" keyword'
328
            );
329
        }
330
    }
331
332
    /**
333
     * checks if platform properties are set inside a properties array
334
     *
335
     * @param array  $properties
336
     * @param string $message
337
     *
338
     * @throws \LogicException
339
     */
340
    private function checkPlatformProperties(array $properties, string $message) : void
341
    {
342
        if (array_key_exists('Platform', $properties)
343
            || array_key_exists('Platform_Description', $properties)
344
            || array_key_exists('Platform_Maker', $properties)
345
            || array_key_exists('Platform_Bits', $properties)
346
            || array_key_exists('Platform_Version', $properties)
347
            || array_key_exists('Win16', $properties)
348
            || array_key_exists('Win32', $properties)
349
            || array_key_exists('Win64', $properties)
350
            || array_key_exists('Browser_Bits', $properties)
351
        ) {
352
            throw new \LogicException($message);
353
        }
354
    }
355
356
    /**
357
     * checks if platform properties are set inside a properties array
358
     *
359
     * @param array  $properties
360
     * @param string $message
361
     *
362
     * @throws \LogicException
363
     */
364
    public function checkEngineProperties(array $properties, string $message) : void
365
    {
366
        if (array_key_exists('RenderingEngine_Name', $properties)
367
            || array_key_exists('RenderingEngine_Version', $properties)
368
            || array_key_exists('RenderingEngine_Description', $properties)
369
            || array_key_exists('RenderingEngine_Maker', $properties)
370
            || array_key_exists('VBScript', $properties)
371
            || array_key_exists('ActiveXControls', $properties)
372
            || array_key_exists('BackgroundSounds', $properties)
373
        ) {
374
            throw new \LogicException($message);
375
        }
376
    }
377
378
    /**
379
     * checks if device properties are set inside a properties array
380
     *
381
     * @param array  $properties
382
     * @param string $message
383
     *
384
     * @throws \LogicException
385
     */
386
    public function checkDeviceProperties(array $properties, string $message) : void
387
    {
388
        if (array_key_exists('Device_Name', $properties)
389
            || array_key_exists('Device_Maker', $properties)
390
            || array_key_exists('Device_Type', $properties)
391
            || array_key_exists('Device_Pointing_Method', $properties)
392
            || array_key_exists('Device_Code_Name', $properties)
393
            || array_key_exists('Device_Brand_Name', $properties)
394
            || array_key_exists('isMobileDevice', $properties)
395
            || array_key_exists('isTablet', $properties)
396
        ) {
397
            throw new \LogicException($message);
398
        }
399
    }
400
}
401