Skip to content

Commit 3a9fa02

Browse files
authored
[12.x] Add Rule::contains (#55809)
* Add Rule::contains * Add tests
1 parent 8b9f434 commit 3a9fa02

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

src/Illuminate/Validation/Rule.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,21 @@ public static function anyOf($rules)
260260
return new AnyOf($rules);
261261
}
262262

263+
/**
264+
* Get a contains rule builder instance.
265+
*
266+
* @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|\UnitEnum|array|string $values
267+
* @return \Illuminate\Validation\Rules\Contains
268+
*/
269+
public static function contains($values)
270+
{
271+
if ($values instanceof Arrayable) {
272+
$values = $values->toArray();
273+
}
274+
275+
return new Rules\Contains(is_array($values) ? $values : func_get_args());
276+
}
277+
263278
/**
264279
* Compile a set of rules for an attribute.
265280
*
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Illuminate\Validation\Rules;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
use Stringable;
7+
8+
use function Illuminate\Support\enum_value;
9+
10+
class Contains implements Stringable
11+
{
12+
/**
13+
* The values that should be contained in the attribute.
14+
*
15+
* @var array
16+
*/
17+
protected $values;
18+
19+
/**
20+
* Create a new contains rule instance.
21+
*
22+
* @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|\UnitEnum|array|string $values
23+
* @return void
24+
*/
25+
public function __construct($values)
26+
{
27+
if ($values instanceof Arrayable) {
28+
$values = $values->toArray();
29+
}
30+
31+
$this->values = is_array($values) ? $values : func_get_args();
32+
}
33+
34+
/**
35+
* Convert the rule to a validation string.
36+
*
37+
* @return string
38+
*/
39+
public function __toString()
40+
{
41+
$values = array_map(function ($value) {
42+
$value = enum_value($value);
43+
44+
return '"'.str_replace('"', '""', $value).'"';
45+
}, $this->values);
46+
47+
return 'contains:'.implode(',', $values);
48+
}
49+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Validation;
4+
5+
use Illuminate\Translation\ArrayLoader;
6+
use Illuminate\Translation\Translator;
7+
use Illuminate\Validation\Rule;
8+
use Illuminate\Validation\Validator;
9+
use PHPUnit\Framework\TestCase;
10+
11+
include_once 'Enums.php';
12+
13+
class ValidationRuleContainsTest extends TestCase
14+
{
15+
public function testItCorrectlyFormatsAStringVersionOfTheRule()
16+
{
17+
$rule = Rule::contains('Taylor');
18+
$this->assertSame('contains:"Taylor"', (string) $rule);
19+
20+
$rule = Rule::contains('Taylor', 'Abigail');
21+
$this->assertSame('contains:"Taylor","Abigail"', (string) $rule);
22+
23+
$rule = Rule::contains(['Taylor', 'Abigail']);
24+
$this->assertSame('contains:"Taylor","Abigail"', (string) $rule);
25+
26+
$rule = Rule::contains(collect(['Taylor', 'Abigail']));
27+
$this->assertSame('contains:"Taylor","Abigail"', (string) $rule);
28+
29+
$rule = Rule::contains([ArrayKeys::key_1, ArrayKeys::key_2]);
30+
$this->assertSame('contains:"key_1","key_2"', (string) $rule);
31+
32+
$rule = Rule::contains([ArrayKeysBacked::key_1, ArrayKeysBacked::key_2]);
33+
$this->assertSame('contains:"key_1","key_2"', (string) $rule);
34+
35+
$rule = Rule::contains(['Taylor', 'Taylor']);
36+
$this->assertSame('contains:"Taylor","Taylor"', (string) $rule);
37+
38+
$rule = Rule::contains([1, 2, 3]);
39+
$this->assertSame('contains:"1","2","3"', (string) $rule);
40+
41+
$rule = Rule::contains(['"foo"', '"bar"', '"baz"']);
42+
$this->assertSame('contains:"""foo""","""bar""","""baz"""', (string) $rule);
43+
}
44+
45+
public function testContainsValidation()
46+
{
47+
$trans = new Translator(new ArrayLoader, 'en');
48+
49+
// Test fails when value is string
50+
$v = new Validator($trans, ['roles' => 'admin'], ['roles' => Rule::contains('editor')]);
51+
$this->assertTrue($v->fails());
52+
53+
// Test passes when array contains the value
54+
$v = new Validator($trans, ['roles' => ['admin', 'user']], ['roles' => Rule::contains('admin')]);
55+
$this->assertTrue($v->passes());
56+
57+
// Test fails when array doesn't contain all the values
58+
$v = new Validator($trans, ['roles' => ['admin', 'user']], ['roles' => Rule::contains(['admin', 'editor'])]);
59+
$this->assertTrue($v->fails());
60+
61+
// Test fails when array doesn't contain all the values (using multiple arguments)
62+
$v = new Validator($trans, ['roles' => ['admin', 'user']], ['roles' => Rule::contains('admin', 'editor')]);
63+
$this->assertTrue($v->fails());
64+
65+
// Test passes when array contains all the values
66+
$v = new Validator($trans, ['roles' => ['admin', 'user', 'editor']], ['roles' => Rule::contains(['admin', 'editor'])]);
67+
$this->assertTrue($v->passes());
68+
69+
// Test passes when array contains all the values (using multiple arguments)
70+
$v = new Validator($trans, ['roles' => ['admin', 'user', 'editor']], ['roles' => Rule::contains('admin', 'editor')]);
71+
$this->assertTrue($v->passes());
72+
73+
// Test fails when array doesn't contain the value
74+
$v = new Validator($trans, ['roles' => ['admin', 'user']], ['roles' => Rule::contains('editor')]);
75+
$this->assertTrue($v->fails());
76+
77+
// Test fails when array doesn't contain any of the values
78+
$v = new Validator($trans, ['roles' => ['admin', 'user']], ['roles' => Rule::contains(['editor', 'manager'])]);
79+
$this->assertTrue($v->fails());
80+
81+
// Test with empty array
82+
$v = new Validator($trans, ['roles' => []], ['roles' => Rule::contains('admin')]);
83+
$this->assertTrue($v->fails());
84+
85+
// Test with nullable field
86+
$v = new Validator($trans, ['roles' => null], ['roles' => ['nullable', Rule::contains('admin')]]);
87+
$this->assertTrue($v->passes());
88+
}
89+
}

0 commit comments

Comments
 (0)