Test Failed
Pull Request — master (#222)
by Rustam
02:30
created

IpHandler::validate()   D

Complexity

Conditions 21
Paths 16

Size

Total Lines 68
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 68
rs 4.1666
c 0
b 0
f 0
cc 21
nc 16
nop 3

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
    public function validate(mixed $value, object $rule, ?ValidationContext $context = null): Result
31
    {
32
        if (!$rule instanceof Ip) {
33
            throw new UnexpectedRuleException(Ip::class, $rule);
34
        }
35
36
        if (!$rule->isAllowIpv4() && !$rule->isAllowIpv6()) {
37
            throw new RuntimeException('Both IPv4 and IPv6 checks can not be disabled at the same time.');
38
        }
39
        $result = new Result();
40
        if (!is_string($value)) {
41
            $result->addError($rule->getMessage());
42
            return $result;
43
        }
44
45
        if (preg_match($rule->getIpParsePattern(), $value, $matches) === 0) {
46
            $result->addError($rule->getMessage());
47
            return $result;
48
        }
49
        $negation = !empty($matches['not'] ?? null);
50
        $ip = $matches['ip'];
51
        $cidr = $matches['cidr'] ?? null;
52
        $ipCidr = $matches['ipCidr'];
53
54
        try {
55
            $ipVersion = IpHelper::getIpVersion($ip, false);
56
        } catch (InvalidArgumentException $e) {
57
            $result->addError($rule->getMessage());
58
            return $result;
59
        }
60
61
        if ($rule->isRequireSubnet() && $cidr === null) {
62
            $result->addError($rule->getNoSubnetMessage());
63
            return $result;
64
        }
65
        if (!$rule->isAllowSubnet() && $cidr !== null) {
66
            $result->addError($rule->getHasSubnetMessage());
67
            return $result;
68
        }
69
        if (!$rule->isAllowNegation() && $negation) {
70
            $result->addError($rule->getMessage());
71
            return $result;
72
        }
73
        if ($ipVersion === IpHelper::IPV6 && !$rule->isAllowIpv6()) {
74
            $result->addError($rule->getIpv6NotAllowedMessage());
75
            return $result;
76
        }
77
        if ($ipVersion === IpHelper::IPV4 && !$rule->isAllowIpv4()) {
78
            $result->addError($rule->getIpv4NotAllowedMessage());
79
            return $result;
80
        }
81
        if (!$result->isValid()) {
82
            return $result;
83
        }
84
        if ($cidr !== null) {
85
            try {
86
                IpHelper::getCidrBits($ipCidr);
87
            } catch (InvalidArgumentException $e) {
88
                $result->addError($rule->getWrongCidrMessage());
89
                return $result;
90
            }
91
        }
92
        if (!$rule->isAllowed($ipCidr)) {
93
            $result->addError($rule->getNotInRangeMessage());
94
            return $result;
95
        }
96
97
        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