Skip to content

Commit c6f78ac

Browse files
committed
Add support for scenario attributes.
1 parent bede151 commit c6f78ac

File tree

3 files changed

+147
-30
lines changed

3 files changed

+147
-30
lines changed

src/AttributesValidator.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,26 @@ public function validate(): bool
7272
continue;
7373
}
7474

75+
// Related scenarios for just this rule.
76+
$scenarios = Scenario::parseReflector($rule->reflect);
77+
78+
// Insert a default scenario.
79+
if (empty($scenarios)) {
80+
$scenarios[] = new Scenario();
81+
}
82+
83+
$ok = false;
84+
85+
foreach ($scenarios as $scenario) {
86+
if ($scenario->name === $this->scenario) {
87+
$ok = true;
88+
break;
89+
}
90+
}
91+
92+
// Skip validations if not scenario matches.
93+
if (!$ok) continue;
94+
7595
$this->process($rule);
7696
}
7797

src/Scenario.php

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
/**
1313
* This adds a scenario to an existing attribute rule.
1414
*
15+
* @attribute scenario property
1516
* @package karmabunny\kb
1617
*/
17-
#[Attribute(Attribute::TARGET_PROPERTY)]
18-
class Scenario
18+
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
19+
class Scenario extends AttributeTag
1920
{
2021

2122
/** @var string|null */
@@ -34,26 +35,10 @@ public function __construct(string $name = null)
3435
}
3536

3637

37-
/**
38-
* Create a set of scenarios from a doc comment.
39-
*
40-
* This parses a '@scenario' tag.
41-
*
42-
* @param string $doc
43-
* @return self[]
44-
*/
45-
public static function parseDoc(string $doc): array
38+
/** @inheritdoc */
39+
protected static function build(string $args)
4640
{
47-
$tags = Reflect::getDocTags($doc, ['scenario']);
48-
$tags = $tags['scenario'];
49-
50-
$scenarios = [];
51-
52-
foreach ($tags as $tag) {
53-
$tag = trim($tag) ?: null;
54-
$scenarios[] = new self($tag);
55-
}
56-
57-
return $scenarios;
41+
return new static(trim($args) ?: null);
5842
}
43+
5944
}

tests/AttributeValidatorTest.php

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
use karmabunny\kb\AttributeValidatorTrait;
88
use karmabunny\kb\Collection;
99
use karmabunny\kb\Rule;
10+
use karmabunny\kb\Scenario;
1011
use karmabunny\kb\Validates;
1112
use karmabunny\kb\ValidationException;
1213
use PHPUnit\Framework\TestCase;
1314

1415

16+
/**
17+
* Test the attribute rules validator.
18+
*/
1519
class AttributeValidatorTest extends TestCase
1620
{
1721
public function testEmpty()
@@ -30,6 +34,7 @@ public function testEmpty()
3034

3135
if (PHP_VERSION_ID >= 80000) {
3236
$expected[] = 'php8';
37+
$expected[] = 'php8_scenario';
3338
}
3439

3540
$actual = array_keys($exception->errors);
@@ -53,14 +58,14 @@ public function testValid()
5358
// range - 10-20
5459
'ten_twenty' => 13,
5560

56-
// range - 20-30
57-
'twenty_thirty' => 26,
58-
5961
// email + end in karmabunny.com.au
6062
'address' => '[email protected]',
6163

6264
// Not tested in PHP7
6365
'php8' => '[email protected]',
66+
67+
// Not tested in PHP7
68+
'php8_scenario' => 'OK',
6469
]);
6570

6671
$thing->validate();
@@ -72,6 +77,74 @@ public function testValid()
7277
}
7378

7479

80+
public function testScenarios()
81+
{
82+
// Test required.
83+
// missing twenty_thirty + (php8_scenario, when applicable)
84+
try {
85+
$thing = new AttrThing([
86+
'id' => 100,
87+
'amount' => 400,
88+
'address' => '[email protected]',
89+
'php8' => '[email protected]',
90+
]);
91+
92+
$thing->validate(AttrThing::SCENARIO_TEST);
93+
$this->fail('Expected ValidationException.');
94+
}
95+
catch (ValidationException $exception) {
96+
$expected = [
97+
'twenty_thirty',
98+
];
99+
100+
if (PHP_VERSION_ID >= 80000) {
101+
$expected[] = 'php8_scenario';
102+
}
103+
104+
$actual = array_keys($exception->errors);
105+
$this->assertEquals($expected, $actual);
106+
}
107+
108+
// Just bad validations.
109+
try {
110+
$thing = new AttrThing([
111+
'ten_twenty' => -13,
112+
'twenty_thirty' => 10,
113+
'php8_scenario' => 'OK',
114+
]);
115+
116+
$thing->validate(AttrThing::SCENARIO_TEST);
117+
$this->fail('Expected ValidationException.');
118+
}
119+
catch (ValidationException $exception) {
120+
$expected = [
121+
'ten_twenty',
122+
'twenty_thirty',
123+
];
124+
125+
$actual = array_keys($exception->errors);
126+
$this->assertEquals($expected, $actual);
127+
}
128+
129+
try {
130+
$thing = new AttrThing([
131+
'ten_twenty' => 15,
132+
133+
'twenty_thirty' => 25,
134+
135+
// Not tested in PHP7
136+
'php8_scenario' => 'OK',
137+
]);
138+
139+
$thing->validate(AttrThing::SCENARIO_TEST);
140+
$this->assertTrue(true);
141+
}
142+
catch (ValidationException $exception) {
143+
$this->fail($exception->getMessage());
144+
}
145+
}
146+
147+
75148
public function testFailure()
76149
{
77150
try {
@@ -84,9 +157,6 @@ public function testFailure()
84157
// range - 10-20
85158
'ten_twenty' => -13,
86159

87-
// range - 20-30
88-
'twenty_thirty' => 31,
89-
90160
// email, matchDomain
91161
'address' => 'eeeeee',
92162
]);
@@ -100,12 +170,12 @@ public function testFailure()
100170
'id',
101171
'amount',
102172
'ten_twenty',
103-
'twenty_thirty',
104173
'address',
105174
];
106175

107176
if (PHP_VERSION_ID >= 80000) {
108177
$expected[] = 'php8';
178+
$expected[] = 'php8_scenario';
109179
}
110180

111181
$actual = array_keys($exception->errors);
@@ -114,7 +184,6 @@ public function testFailure()
114184
$this->assertTrue(isset($exception->errors['id']['required']));
115185
$this->assertCount(1, $exception->errors['amount'] ?? []);
116186
$this->assertCount(1, $exception->errors['ten_twenty'] ?? []);
117-
$this->assertCount(1, $exception->errors['twenty_thirty'] ?? []);
118187
$this->assertCount(2, $exception->errors['address'] ?? []);
119188
}
120189
}
@@ -137,6 +206,7 @@ public function testAttributes()
137206
// test valid.
138207
try {
139208
$thing->php8 = '[email protected]';
209+
$thing->php8_scenario = 'OK';
140210

141211
$thing->validate();
142212
$this->assertTrue(true);
@@ -148,24 +218,51 @@ public function testAttributes()
148218
// test required.
149219
try {
150220
$thing->php8 = null;
221+
$thing->php8_scenario = 'OK';
151222

152223
$thing->validate();
153224
$this->fail('Expected ValidationException.');
154225
}
155226
catch (ValidationException $exception) {
156227
$this->assertTrue(isset($exception->errors['php8']['required']));
228+
$this->assertFalse(isset($exception->errors['php8_scenario']['required']));
157229
}
158230

159231
// test invalid.
160232
try {
161233
$thing->php8 = 'eee';
234+
$thing->php8_scenario = 'OK';
162235

163236
$thing->validate();
164237
$this->fail('Expected ValidationException.');
165238
}
166239
catch (ValidationException $exception) {
167240
$this->assertCount(3, $exception->errors['php8'] ?? []);
168241
}
242+
243+
// test bad scenario.
244+
try {
245+
$thing->php8 = null;
246+
$thing->php8_scenario = null;
247+
248+
$thing->validate(AttrThing::SCENARIO_TEST);
249+
$this->fail('Expected ValidationException.');
250+
}
251+
catch (ValidationException $exception) {
252+
$this->assertTrue(isset($exception->errors['php8_scenario']['required']));
253+
}
254+
255+
// test good scenario.
256+
try {
257+
$thing->php8 = null;
258+
$thing->php8_scenario = 'OK';
259+
260+
$thing->validate(AttrThing::SCENARIO_TEST);
261+
$this->assertTrue(true);
262+
}
263+
catch (ValidationException $exception) {
264+
$this->fail($exception->getMessage());
265+
}
169266
}
170267
}
171268

@@ -174,6 +271,8 @@ class AttrThing extends Collection implements Validates
174271
{
175272
use AttributeValidatorTrait;
176273

274+
const SCENARIO_TEST = 'TEST';
275+
177276
/**
178277
* @var int
179278
* @rule required
@@ -190,18 +289,23 @@ class AttrThing extends Collection implements Validates
190289
/**
191290
* @var int
192291
* @rule required
292+
* @scenario
193293
*/
194294
public $default = 333;
195295

196296
/**
197297
* @var int
198298
* @rule range 10, 20
299+
* @scenario
300+
* @scenario TEST
199301
*/
200302
public $ten_twenty;
201303

202304
/**
203305
* @var int
306+
* @rule required
204307
* @rule range 20, 30
308+
* @scenario TEST
205309
*/
206310
public $twenty_thirty;
207311

@@ -219,6 +323,14 @@ class AttrThing extends Collection implements Validates
219323
#[Rule('matchDomain', 'example.com')]
220324
public $php8;
221325

326+
/**
327+
* @var string
328+
*/
329+
#[Rule('required')]
330+
#[Scenario()]
331+
#[Scenario(self::SCENARIO_TEST)]
332+
public $php8_scenario;
333+
222334

223335
public static function matchDomain($value, string $domain)
224336
{

0 commit comments

Comments
 (0)