Passed
Pull Request — master (#477)
by Alexander
03:43 queued 01:15
created

Url::isIDNEnabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Closure;
9
use RuntimeException;
10
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
11
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
12
use Yiisoft\Validator\Rule\Trait\WhenTrait;
13
use Yiisoft\Validator\RuleWithOptionsInterface;
14
use Yiisoft\Validator\SkipOnEmptyInterface;
15
use Yiisoft\Validator\SkipOnErrorInterface;
16
use Yiisoft\Validator\WhenInterface;
17
18
use function function_exists;
19
20
/**
21
 * Validates that the value is a valid HTTP or HTTPS URL.
22
 *
23
 * Note that this rule only checks if the URL scheme and host parts are correct.
24
 * It does not check the remaining parts of a URL.
25
 *
26
 * @psalm-import-type WhenType from WhenInterface
27
 */
28
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
29
final class Url implements RuleWithOptionsInterface, SkipOnErrorInterface, WhenInterface, SkipOnEmptyInterface
30
{
31
    use SkipOnEmptyTrait;
32
    use SkipOnErrorTrait;
33
    use WhenTrait;
34 4
35
    public function __construct(
36
        /**
37
         * @var string The regular expression used to validate the value.
38
         * The pattern may contain a `{schemes}` token that will be replaced
39
         * by a regular expression which represents the {@see $schemes}.
40
         *
41
         * Note that if you want to reuse the pattern in HTML5 input, it should have `^` and `$`, should not have any
42
         * modifiers, and should not be case-insensitive.
43
         */
44
        private string $pattern = '/^{schemes}:\/\/(([a-zA-Z0-9][a-zA-Z0-9_-]*)(\.[a-zA-Z0-9][a-zA-Z0-9_-]*)+)(?::\d{1,5})?([?\/#].*$|$)/',
45
        /**
46
         * @var string[] List of URI schemes which should be considered valid. By default, http and https
47
         * are considered to be valid schemes.
48
         */
49
        private array $validSchemes = ['http', 'https'],
50
        /**
51
         * @var bool Whether validation process should take into account IDN (internationalized
52
         * domain names). Defaults to `false` meaning that validation of URLs containing IDN will always
53
         * fail. Note that in order to use IDN validation you have to install and enable `intl` PHP
54
         * extension, otherwise an exception would be thrown.
55
         */
56
        private bool $enableIDN = false,
57
        /**
58
         * @var string A message used when the input is incorrect.
59
         *
60
         * You may use the following placeholders in the message:
61
         *
62
         * - `{attribute}`: the label of the attribute being validated.
63
         * - `{value}`: the value of the attribute being validated.
64
         */
65
        private string $incorrectInputMessage = 'The value must have a string type.',
66
        /**
67
         * @var string A message used when the value is not valid.
68
         *
69 4
         * You may use the following placeholders in the message:
70
         *
71
         * - `{attribute}`: the label of the attribute being validated.
72
         * - `{value}`: the value of the attribute being validated.
73
         */
74
        private string $message = 'This value is not a valid URL.',
75
        /**
76
         * @var bool|callable|null Whether to skip this rule if the value validated is empty.
77 1
         *
78
         * @see SkipOnEmptyInterface
79 1
         */
80
        private $skipOnEmpty = null,
81
        /**
82 44
         * @var bool Whether to skip this rule if any of the previous rules gave an error.
83
         */
84 44
        private bool $skipOnError = false,
85
        /**
86
         * @var Closure|null A callable to define a condition for applying the rule.
87
         * @psalm-var WhenType
88
         *
89
         * @see WhenInterface
90 2
         */
91
        private Closure|null $when = null,
92 2
    ) {
93
        if ($enableIDN && !function_exists('idn_to_ascii')) {
94
            // Tested via separate CI configuration (see ".github/workflows/build.yml").
95 40
            // @codeCoverageIgnoreStart
96
            throw new RuntimeException('In order to use IDN validation intl extension must be installed and enabled.');
97 40
            // @codeCoverageIgnoreEnd
98
        }
99
    }
100 6
101
    public function getName(): string
102 6
    {
103
        return 'url';
104
    }
105 19
106
    /**
107 19
     * @return string Ready to use regular expression pattern used for URL validation.
108
     */
109
    public function getPattern(): string
110 4
    {
111
        return str_replace('{schemes}', '((?i)' . implode('|', $this->validSchemes) . ')', $this->pattern);
112
    }
113 4
114 4
    /**
115 4
     * @return string[] List of URI schemes which should be considered valid. By default, http and https
116
     * are considered to be valid schemes.
117 4
     *
118
     * @see $validSchemes
119
     */
120
    public function getValidSchemes(): array
121 4
    {
122
        return $this->validSchemes;
123
    }
124 4
125 4
    /**
126
     * @return bool Whether validation process should take into account IDN (internationalized
127
     * domain names). `false` meaning that validation of URLs containing IDN will always
128
     * fail. Note that in order to use IDN validation you have to install and enable `intl` PHP
129 48
     * extension, otherwise an exception would be thrown.
130
     *
131 48
     * @see $enableIDN
132
     */
133
    public function isIDNEnabled(): bool
134
    {
135
        return $this->enableIDN;
136
    }
137
138
    /**
139
     * @return string A message used when the input is incorrect.
140
     *
141
     * @see $incorrectInputMessage
142
     */
143
    public function getIncorrectInputMessage(): string
144
    {
145
        return $this->incorrectInputMessage;
146
    }
147
148
    /**
149
     * @return string A message used when the value is not valid.
150
     *
151
     * @see $message
152
     */
153
    public function getMessage(): string
154
    {
155
        return $this->message;
156
    }
157
158
    public function getOptions(): array
159
    {
160
        return [
161
            'pattern' => $this->getPattern(),
162
            'validSchemes' => $this->validSchemes,
163
            'enableIDN' => $this->enableIDN,
164
            'incorrectInputMessage' => [
165
                'template' => $this->incorrectInputMessage,
166
                'parameters' => [],
167
            ],
168
            'message' => [
169
                'template' => $this->message,
170
                'parameters' => [],
171
            ],
172
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
173
            'skipOnError' => $this->skipOnError,
174
        ];
175
    }
176
177
    public function getHandler(): string
178
    {
179
        return UrlHandler::class;
180
    }
181
}
182