• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vjik / yii-validator-scenarios / 11723452805

07 Nov 2024 12:57PM UTC coverage: 100.0%. Remained the same
11723452805

Pull #7

github

web-flow
Merge 70fcc958e into 4b685863d
Pull Request #7: Add Composer require checker

78 of 78 relevant lines covered (100.0%)

19.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/On.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Vjik\Yii\ValidatorScenarios;
6

7
use Attribute;
8
use Closure;
9
use InvalidArgumentException;
10
use Stringable;
11
use Yiisoft\Validator\AfterInitAttributeEventInterface;
12
use Yiisoft\Validator\Helper\RulesDumper;
13
use Yiisoft\Validator\Helper\RulesNormalizer;
14
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
15
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
16
use Yiisoft\Validator\Rule\Trait\WhenTrait;
17
use Yiisoft\Validator\RuleInterface;
18
use Yiisoft\Validator\RuleWithOptionsInterface;
19
use Yiisoft\Validator\SkipOnEmptyInterface;
20
use Yiisoft\Validator\SkipOnErrorInterface;
21
use Yiisoft\Validator\WhenInterface;
22

23
/**
24
 * The rule implement the scenario feature.
25
 *
26
 * Example:
27
 *
28
 * ```php
29
 * final class UserDto
30
 * {
31
 *   public function __construct(
32
 *     #[On(
33
 *       'register',
34
 *       [new Required(), new Length(min: 7, max: 10)]
35
 *     )]
36
 *     public string $name,
37
 *
38
 *     #[Required]
39
 *     #[Email]
40
 *     public string $email,
41
 *
42
 *     #[On(
43
 *       ['login', 'register'],
44
 *       [new Required(), new Length(min: 8)],
45
 *     )]
46
 *     public string $password,
47
 *     ) {
48
 *     }
49
 * }
50
 * ```
51
 *
52
 * @psalm-import-type WhenType from WhenInterface
53
 */
54
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
55
final class On implements
56
    RuleWithOptionsInterface,
57
    SkipOnErrorInterface,
58
    WhenInterface,
59
    SkipOnEmptyInterface,
60
    AfterInitAttributeEventInterface
61
{
62
    use SkipOnEmptyTrait;
63
    use SkipOnErrorTrait;
64
    use WhenTrait;
65

66
    public const SCENARIO_PARAMETER = 'scenario';
67

68
    /**
69
     * @var string[]|null
70
     */
71
    private ?array $scenarios;
72

73
    /**
74
     * @var iterable<int, RuleInterface>
75
     */
76
    private iterable $rules;
77

78
    /**
79
     * @var bool|callable|null
80
     */
81
    private $skipOnEmpty;
82

83
    private ?RulesDumper $rulesDumper = null;
84

85
    /**
86
     * @param string|Stringable|string[]|Stringable[]|null $scenario The scenario(s) that rules are in. `null` if rules
87
     * used always.
88
     * @param iterable<callable|RuleInterface>|callable|RuleInterface $rules Rules that will be applied according
89
     * to `$scenario`.
90
     * @param bool $not Whether the scenario check should be inverted. When this parameter is set `true`, the validator
91
     * checks whether the current scenario is among `$scenario` and if NOT, `$rules` will be applied.
92
     * @param bool|callable|null $skipOnEmpty Whether skip `$rules` on empty value or not, and which value consider as
93
     * empty. More details in {@see SkipOnEmptyInterface}.
94
     * @param bool $skipOnError A boolean value where `true` means to skip `$rules` when the previous one errored
95
     * and `false` - do not skip.
96
     * @param Closure|null $when The closure that allow to apply `$rules` under certain conditions only. More details
97
     * in {@see SkipOnErrorInterface}.
98
     *
99
     * @psalm-param WhenType $when
100
     *
101
     * @throws InvalidArgumentException
102
     */
103
    public function __construct(
22✔
104
        string|Stringable|array|null $scenario = null,
105
        callable|iterable|RuleInterface $rules = [],
106
        private bool $not = false,
107
        bool|callable|null $skipOnEmpty = null,
108
        private bool $skipOnError = false,
109
        private Closure|null $when = null
110
    ) {
111
        $this->setScenarios($scenario);
22✔
112
        $this->rules = RulesNormalizer::normalizeList($rules);
14✔
113
        $this->skipOnEmpty = $skipOnEmpty;
14✔
114
    }
115

116
    public function getName(): string
4✔
117
    {
118
        return 'on';
4✔
119
    }
120

121
    public function getHandler(): string
44✔
122
    {
123
        return OnHandler::class;
44✔
124
    }
125

126
    public function getScenarios(): ?array
44✔
127
    {
128
        return $this->scenarios;
44✔
129
    }
130

131
    /**
132
     * @return iterable<int, RuleInterface>
133
     */
134
    public function getRules(): iterable
41✔
135
    {
136
        return $this->rules;
41✔
137
    }
138

139
    public function isNot(): bool
40✔
140
    {
141
        return $this->not;
40✔
142
    }
143

144
    public function getOptions(): array
12✔
145
    {
146
        return [
12✔
147
            'scenarios' => $this->scenarios,
12✔
148
            'rules' => $this->getRulesDumper()->asArray($this->rules),
12✔
149
            'not' => $this->not,
12✔
150
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
12✔
151
            'skipOnError' => $this->skipOnError,
12✔
152
        ];
12✔
153
    }
154

155
    public function afterInitAttribute(object $object): void
12✔
156
    {
157
        foreach ($this->rules as $rule) {
12✔
158
            if ($rule instanceof AfterInitAttributeEventInterface) {
12✔
159
                $rule->afterInitAttribute($object);
3✔
160
            }
161
        }
162
    }
163

164
    private function getRulesDumper(): RulesDumper
12✔
165
    {
166
        if ($this->rulesDumper === null) {
12✔
167
            $this->rulesDumper = new RulesDumper();
12✔
168
        }
169

170
        return $this->rulesDumper;
12✔
171
    }
172

173
    /**
174
     * @throws InvalidArgumentException
175
     */
176
    private function setScenarios(mixed $sourceScenario): void
22✔
177
    {
178
        if ($sourceScenario === null) {
22✔
179
            $this->scenarios = null;
8✔
180
            return;
8✔
181
        }
182

183
        $this->scenarios = array_map(
18✔
184
            static function (mixed $scenario): string {
18✔
185
                if (
186
                    is_string($scenario)
18✔
187
                    || $scenario instanceof Stringable
18✔
188
                ) {
189
                    return (string) $scenario;
10✔
190
                }
191

192
                throw new InvalidArgumentException(
8✔
193
                    sprintf(
8✔
194
                        'Scenario must be null, a string, or an array of strings or an array of "\Stringable", "%s" given.',
8✔
195
                        get_debug_type($scenario),
8✔
196
                    ),
8✔
197
                );
8✔
198
            },
18✔
199
            is_array($sourceScenario) ? $sourceScenario : [$sourceScenario],
18✔
200
        );
18✔
201
    }
202
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc