Issues (138)

src/Rule/AtLeast.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Closure;
9
use InvalidArgumentException;
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\DumpedRuleInterface;
14
use Yiisoft\Validator\SkipOnEmptyInterface;
15
use Yiisoft\Validator\SkipOnErrorInterface;
16
use Yiisoft\Validator\WhenInterface;
17
18
use function count;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Yiisoft\Validator\Rule\count. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
19
20
/**
21
 * Defines validation options to check that a minimum number of specified attributes are filled.
22
 *
23
 * Both arrays and objects with public properties are supported as validated values.
24
 *
25
 * @see AtLeastHandler
26
 *
27
 * @psalm-import-type WhenType from WhenInterface
28 3
 */
29
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
30
final class AtLeast implements DumpedRuleInterface, SkipOnErrorInterface, WhenInterface, SkipOnEmptyInterface
31
{
32
    use SkipOnEmptyTrait;
33
    use SkipOnErrorTrait;
34
    use WhenTrait;
35
36
    /**
37
     * @param string[] $attributes The list of required attributes that will be checked.
38
     * @param int $min The minimum required quantity of filled attributes to pass the validation. Defaults to 1.
39
     * @param string $incorrectInputMessage A message used when the input is incorrect.
40
     *
41
     * You may use the following placeholders in the message:
42
     *
43
     * - `{attribute}`: the translated label of the attribute being validated.
44
     * - `{type}`: the type of the value being validated.
45
     * @param string $message A message used when the value is not valid.
46
     *
47
     * You may use the following placeholders in the message:
48
     *
49
     * - `{attribute}`: the translated label of the attribute being validated.
50
     * - `{min}`: the minimum number of attribute values that was not met.
51
     * @param bool|callable|null $skipOnEmpty Whether to skip this rule if the value validated is empty.
52
     * See {@see SkipOnEmptyInterface}.
53
     * @param bool $skipOnError Whether to skip this rule if any of the previous rules gave an error.
54 1
     * See {@see SkipOnErrorInterface}.
55
     * @param Closure|null $when A callable to define a condition for applying the rule.
56 1
     * See {@see WhenInterface}.
57
     *
58
     * @psalm-param WhenType $when
59
     */
60
    public function __construct(
61
        private array $attributes,
62 15
        private int $min = 1,
63
        private string $incorrectInputMessage = 'The value must be an array or an object.',
64 15
        private string $message = 'At least {min, number} {min, plural, one{attribute} other{attributes}} from this ' .
65
        'list must be filled: {attributes}.',
66
        private mixed $skipOnEmpty = null,
67 15
        private bool $skipOnError = false,
68
        private Closure|null $when = null
69 15
    ) {
70
        if ($min > count($this->attributes)) {
71
            throw new InvalidArgumentException('$min must be no greater than amount of $attributes.');
72 4
        }
73
    }
74 4
75
    public function getName(): string
76
    {
77 7
        return self::class;
78
    }
79 7
80
    /**
81
     * Get the list of required attributes that will be checked.
82 2
     *
83
     * @return string[] The list of attributes.
84
     *
85 2
     * @see $attributes
86 2
     */
87
    public function getAttributes(): array
88 2
    {
89
        return $this->attributes;
90
    }
91
92 2
    /**
93 2
     * Get the minimum required quantity of filled attributes to pass the validation.
94
     *
95 2
     * @return int Minimum require quantity.
96 2
     *
97
     * @see $min
98
     */
99
    public function getMin(): int
100 19
    {
101
        return $this->min;
102 19
    }
103
104
    /**
105
     * Get the message used when the input is incorrect.
106
     *
107
     * @return string Error message.
108
     *
109
     * @see $incorrectInputMessage
110
     */
111
    public function getIncorrectInputMessage(): string
112
    {
113
        return $this->incorrectInputMessage;
114
    }
115
116
    /**
117
     * Get the message used when the value is not valid.
118
     *
119
     * @return string Error message.
120
     *
121
     * @see $message
122
     */
123
    public function getMessage(): string
124
    {
125
        return $this->message;
126
    }
127
128
    public function getOptions(): array
129
    {
130
        return [
131
            'attributes' => $this->attributes,
132
            'min' => $this->min,
133
            'incorrectInputMessage' => [
134
                'template' => $this->incorrectInputMessage,
135
                'parameters' => [],
136
            ],
137
            'message' => [
138
                'template' => $this->message,
139
                'parameters' => ['min' => $this->min],
140
            ],
141
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
142
            'skipOnError' => $this->skipOnError,
143
        ];
144
    }
145
146
    public function getHandler(): string
147
    {
148
        return AtLeastHandler::class;
149
    }
150
}
151