Completed
Push — master ( 6f57c0...93a727 )
by Viacheslav
14:19 queued 04:20
created

Format::validationError()   D

Complexity

Conditions 26
Paths 26

Size

Total Lines 42
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 26

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
c 1
b 0
f 0
dl 0
loc 42
ccs 37
cts 37
cp 1
rs 4.1666
cc 26
nc 26
nop 2
crap 26

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
3
namespace Swaggest\JsonSchema\Constraint;
4
5
use Swaggest\JsonSchema\Constraint\Format\IdnHostname;
6
use Swaggest\JsonSchema\Constraint\Format\Iri;
7
use Swaggest\JsonSchema\Constraint\Format\Uri;
8
9
class Format
10
{
11
    const DATE_TIME = 'date-time';
12
    const DATE = 'date';
13
    const TIME = 'time';
14
    const URI = 'uri';
15
    const IRI = 'iri';
16
    const EMAIL = 'email';
17
    const IDN_EMAIL = 'idn-email';
18
    const IPV4 = 'ipv4';
19
    const IPV6 = 'ipv6';
20
    const HOSTNAME = 'hostname';
21
    const IDN_HOSTNAME = 'idn-hostname';
22
    const REGEX = 'regex';
23
    const JSON_POINTER = 'json-pointer';
24
    const RELATIVE_JSON_POINTER = 'relative-json-pointer';
25
    const URI_REFERENCE = 'uri-reference';
26
    const IRI_REFERENCE = 'iri-reference';
27
    const URI_TEMPLATE = 'uri-template';
28
29
    public static $strictDateTimeValidation = false;
30
31
    private static $dateRegexPart = '(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])';
32
    private static $timeRegexPart = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):?([0-5][0-9])?)?';
33
    private static $jsonPointerRegex = '_^(?:/|(?:/[^/#]*)*)$_';
34
    private static $jsonPointerRelativeRegex = '~^(0|[1-9][0-9]*)((?:/[^/#]*)*)(#?)$~';
35
    private static $jsonPointerUnescapedTilde = '/~([^01]|$)/';
36
37 445
    public static function validationError($format, $data)
38
    {
39
        switch ($format) {
40 445
            case self::DATE_TIME:
41 39
                return self::dateTimeError($data);
42 406
            case self::DATE:
43 6
                return preg_match('/^' . self::$dateRegexPart . '$/i', $data) ? null : 'Invalid date';
44 400
            case self::TIME:
45 9
                return preg_match('/^' . self::$timeRegexPart . '$/i', $data) ? null : 'Invalid time';
46 391
            case self::URI:
47 166
                return Uri::validationError($data, Uri::IS_SCHEME_REQUIRED);
48 238
            case self::IRI:
49 9
                return Iri::validationError($data);
50 229
            case self::EMAIL:
51 11
                return filter_var($data, FILTER_VALIDATE_EMAIL) ? null : 'Invalid email';
52 219
            case self::IDN_EMAIL:
53 2
                return count(explode('@', $data, 3)) === 2 ? null : 'Invalid email';
54 217
            case self::IPV4:
55 16
                return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? null : 'Invalid ipv4';
56 201
            case self::IPV6:
57 12
                return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? null : 'Invalid ipv6';
58 189
            case self::HOSTNAME:
59 16
                if (strlen(rtrim($data, '.')) >= 254) { // Not sure if it should be 254, higher number fails AJV suite.
60 174
                    return 'Invalid hostname (too long)';
61 4
                }
62 170
                return preg_match(Uri::HOSTNAME_REGEX, $data) ? null : 'Invalid hostname';
63 53
            case self::IDN_HOSTNAME:
64 117
                return IdnHostname::validationError($data);
65 70
            case self::REGEX:
66 47
                return self::regexError($data);
67 14
            case self::JSON_POINTER:
68 33
                return self::jsonPointerError($data);
69 15
            case self::RELATIVE_JSON_POINTER:
70 18
                return self::jsonPointerError($data, true);
71 7
            case self::URI_REFERENCE:
72 11
                return Uri::validationError($data, Uri::IS_URI_REFERENCE);
73 10
            case self::IRI_REFERENCE:
74
                return Iri::validationError($data, Uri::IS_URI_REFERENCE);
75 1
            case self::URI_TEMPLATE:
76
                return Uri::validationError($data, Uri::IS_URI_TEMPLATE);
77
        }
78 39
        return null;
79
    }
80 39
81 14
    public static function dateTimeError($data)
82
    {
83
        if (!preg_match('/^' . self::$dateRegexPart . 'T' . self::$timeRegexPart . '$/i', $data)) {
84 25
            return 'Invalid date-time format: ' . $data;
85 20
        }
86 20
87
        if (self::$strictDateTimeValidation) {
88
            $dt = date_create($data);
89 20
            if ($dt === false) {
90 4
                return 'Failed to parse date-time: ' . $data;
91 20
            }
92
            $isLeapSecond = '6' === $data[17] && (
93 20
                    0 === strpos(substr($data, 5, 5), '12-31') ||
94 20
                    0 === strpos(substr($data, 5, 5), '06-30')
95 3
                );
96
            if (!$isLeapSecond &&
97
                0 !== stripos($dt->format(DATE_RFC3339), substr($data, 0, 19))) {
98
                return 'Invalid date-time value: ' . $data;
99 22
            }
100
        }
101
102 53
        return null;
103
    }
104 53
105 3
    public static function regexError($data)
106
    {
107 50
        if (substr($data, -2) === '\Z') {
108
            return 'Invalid regex: \Z is not supported';
109
        }
110
        if (substr($data, 0, 2) === '\A') {
111 50
            return 'Invalid regex: \A is not supported';
112
        }
113
114 84
        return @preg_match('{' . $data . '}', '') === false ? 'Invalid regex: ' . $data : null;
115
    }
116 84
117 14
    public static function jsonPointerError($data, $isRelative = false)
118
    {
119 70
        if (preg_match(self::$jsonPointerUnescapedTilde, $data)) {
120 13
            return 'Invalid json-pointer: unescaped ~';
121
        }
122 57
        if ($isRelative) {
123
            return preg_match(self::$jsonPointerRelativeRegex, $data) ? null : 'Invalid relative json-pointer';
124
        } else {
125
            return preg_match(self::$jsonPointerRegex, $data) ? null : 'Invalid json-pointer';
126
        }
127
    }
128
}