HostAndPortValidator   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 63
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 33
dl 0
loc 63
ccs 23
cts 23
cp 1
rs 10
c 1
b 0
f 0
wmc 8

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
B isValid() 0 26 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\Common\Validation;
6
7
use Laminas\Validator\AbstractValidator;
8
use Laminas\Validator\Between;
9
use Laminas\Validator\Digits;
10
use Laminas\Validator\Exception;
11
use Laminas\Validator\Hostname;
12
use Laminas\Validator\ValidatorChain;
13
use Laminas\Validator\ValidatorInterface;
14
use Traversable;
15
16
use function count;
17
use function explode;
18
use function get_class;
19
use function gettype;
20
use function is_object;
21
use function is_string;
22
use function sprintf;
23
24
class HostAndPortValidator extends AbstractValidator
25
{
26
    private const INVALID_AMOUNT_OF_PARTS = 'INVALID_AMOUNT_OF_PARTS';
27
    private const INVALID_HOST = 'INVALID_HOST';
28
    private const INVALID_PORT = 'INVALID_PORT';
29
30
    protected array $messageTemplates = [
31
        self::INVALID_AMOUNT_OF_PARTS =>
32
            'Provided value, once split using the ":" separator, returned more than 2 parts',
33
        self::INVALID_HOST => 'The host part of the value is not valid',
34
        self::INVALID_PORT => 'The port part of the value is not valid. Must be a number between 1 and 65535',
35
    ];
36
37
    private ValidatorInterface $hostValidator;
38
    private ValidatorInterface $portValidator;
39
40
    /**
41
     * @param array|Traversable|null $options
42
     */
43 19
    public function __construct($options = null)
44
    {
45 19
        parent::__construct($options);
46
47 19
        $this->hostValidator = new Hostname([
48 19
            'allow' => Hostname::ALLOW_DNS | Hostname::ALLOW_LOCAL,
49
        ]);
50 19
        $this->portValidator = (new ValidatorChain())->attach(new Digits())
51 19
                                                     ->attach(new Between([
52 19
                                                         'min' => 1,
53
                                                         'max' => 65535,
54
                                                         'inclusive' => true,
55
                                                     ]));
56
    }
57
58
    /**
59
     * @param mixed $value
60
     */
61 19
    public function isValid($value): bool
62
    {
63 19
        if (! is_string($value)) {
64 4
            throw new Exception\RuntimeException(sprintf(
65 4
                'Expected value to be a string. %s provided',
66 4
                is_object($value) ? get_class($value) : gettype($value),
67
            ));
68
        }
69
70 15
        $parts = explode(':', $value);
71 15
        if (count($parts) > 2) {
72 2
            $this->error(self::INVALID_AMOUNT_OF_PARTS);
73 2
            return false;
74
        }
75
76 13
        if (! $this->hostValidator->isValid($parts[0])) {
77 3
            $this->error(self::INVALID_HOST);
78 3
            return false;
79
        }
80
81 10
        if (isset($parts[1]) && ! $this->portValidator->isValid($parts[1])) {
82 6
            $this->error(self::INVALID_PORT);
83 6
            return false;
84
        }
85
86 4
        return true;
87
    }
88
}
89