Passed
Pull Request — master (#222)
by Dmitriy
02:35
created

IpHandler::validate()   D

Complexity

Conditions 21
Paths 16

Size

Total Lines 68
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 21.2902

Importance

Changes 0
Metric Value
eloc 47
c 0
b 0
f 0
dl 0
loc 68
ccs 42
cts 46
cp 0.913
rs 4.1666
cc 21
nc 16
nop 3
crap 21.2902

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
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Yiisoft\NetworkUtilities\IpHelper;
10
use Yiisoft\Validator\Result;
11
use Yiisoft\Validator\ValidationContext;
12
use function is_string;
13
use Yiisoft\Validator\Exception\UnexpectedRuleException;
14
15
/**
16
 * Checks if the value is a valid IPv4/IPv6 address or subnet.
17
 *
18
 * It also may change the value if normalization of IPv6 expansion is enabled.
19
 */
20
final class IpHandler implements RuleHandlerInterface
21
{
22
    /**
23
     * Negation char.
24
     *
25
     * Used to negate {@see $ranges} or {@see $network} or to negate validating value when {@see $allowNegation}
26
     * is used.
27
     */
28
    private const NEGATION_CHAR = '!';
29
30 118
    public function validate(mixed $value, object $rule, ?ValidationContext $context = null): Result
31
    {
32 118
        if (!$rule instanceof Ip) {
33 1
            throw new UnexpectedRuleException(Ip::class, $rule);
34
        }
35
36 117
        if (!$rule->allowIpv4 && !$rule->allowIpv6) {
37 1
            throw new RuntimeException('Both IPv4 and IPv6 checks can not be disabled at the same time.');
38
        }
39 116
        $result = new Result();
40 116
        if (!is_string($value)) {
41 4
            $result->addError($rule->message);
42 4
            return $result;
43
        }
44
45 112
        if (preg_match($rule->getIpParsePattern(), $value, $matches) === 0) {
46 26
            $result->addError($rule->message);
47 26
            return $result;
48
        }
49 86
        $negation = !empty($matches['not'] ?? null);
50 86
        $ip = $matches['ip'];
51 86
        $cidr = $matches['cidr'] ?? null;
52 86
        $ipCidr = $matches['ipCidr'];
53
54
        try {
55 86
            $ipVersion = IpHelper::getIpVersion($ip, false);
56
        } catch (InvalidArgumentException $e) {
57
            $result->addError($rule->message);
58
            return $result;
59
        }
60
61 86
        if ($rule->requireSubnet === true && $cidr === null) {
62 4
            $result->addError($rule->noSubnetMessage);
63 4
            return $result;
64
        }
65 82
        if ($rule->allowSubnet === false && $cidr !== null) {
66 4
            $result->addError($rule->hasSubnetMessage);
67 4
            return $result;
68
        }
69 78
        if ($rule->allowNegation === false && $negation) {
70 4
            $result->addError($rule->message);
71 4
            return $result;
72
        }
73 74
        if ($ipVersion === IpHelper::IPV6 && !$rule->allowIpv6) {
74 1
            $result->addError($rule->ipv6NotAllowedMessage);
75 1
            return $result;
76
        }
77 73
        if ($ipVersion === IpHelper::IPV4 && !$rule->allowIpv4) {
78 2
            $result->addError($rule->ipv4NotAllowedMessage);
79 2
            return $result;
80
        }
81 71
        if (!$result->isValid()) {
82
            return $result;
83
        }
84 71
        if ($cidr !== null) {
85
            try {
86 28
                IpHelper::getCidrBits($ipCidr);
87 2
            } catch (InvalidArgumentException $e) {
88 2
                $result->addError($rule->wrongCidrMessage);
89 2
                return $result;
90
            }
91
        }
92 69
        if (!$rule->isAllowed($ipCidr)) {
93 16
            $result->addError($rule->notInRangeMessage);
94 16
            return $result;
95
        }
96
97 53
        return $result;
98
    }
99
100
    /**
101
     * Used to get the Regexp pattern for initial IP address parsing.
102
     */
103
    public function getIpParsePattern(): string
104
    {
105
        return '/^(?<not>' . preg_quote(
106
            self::NEGATION_CHAR,
107
            '/'
108
        ) . ')?(?<ipCidr>(?<ip>(?:' . IpHelper::IPV4_PATTERN . ')|(?:' . IpHelper::IPV6_PATTERN . '))(?:\/(?<cidr>-?\d+))?)$/';
109
    }
110
}
111