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