Skip to content

Commit f5e22f1

Browse files
committed
Introduce ContainsCount validator
This validator is similar to Contains, but also checks how many times the needle appears. Additionally, the Domain validator was changed to use it instead of relying on an unserializable callback, thus, making it serializable.
1 parent 4618996 commit f5e22f1

23 files changed

Lines changed: 338 additions & 4 deletions

docs/validators/Contains.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Message template for this validator includes `{{containsValue}}`.
5656
See also:
5757

5858
- [ContainsAny](ContainsAny.md)
59+
- [ContainsCount](ContainsCount.md)
5960
- [EndsWith](EndsWith.md)
6061
- [Equals](Equals.md)
6162
- [Equivalent](Equivalent.md)

docs/validators/ContainsAny.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,6 @@ See also:
5757

5858
- [AnyOf](AnyOf.md)
5959
- [Contains](Contains.md)
60+
- [ContainsCount](ContainsCount.md)
6061
- [Equivalent](Equivalent.md)
6162
- [In](In.md)

docs/validators/ContainsCount.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# ContainsCount
2+
3+
- `ContainsCount(mixed $containsValue, int $count)`
4+
- `ContainsCount(mixed $containsValue, int $count, bool $identical)`
5+
6+
Validates if the input contains a value a specific number of times.
7+
8+
For strings:
9+
10+
```php
11+
v::containsCount('ipsum', 2)->assert('ipsum lorem ipsum');
12+
// Validation passes successfully
13+
```
14+
15+
For arrays:
16+
17+
```php
18+
v::containsCount('ipsum', 2)->assert(['ipsum', 'lorem', 'ipsum']);
19+
// Validation passes successfully
20+
```
21+
22+
A third parameter may be passed for identical comparison instead of equal comparison.
23+
24+
```php
25+
v::containsCount(1, 1, true)->assert([1, 2, 3]);
26+
// Validation passes successfully
27+
28+
v::containsCount('1', 1, true)->assert([1, 2, 3]);
29+
// → `[1, 2, 3]` must contain "1" only once
30+
```
31+
32+
## Templates
33+
34+
### `ContainsCount::TEMPLATE_TIMES`
35+
36+
| Mode | Template |
37+
| ---------- | ---------------------------------------------------------------- |
38+
| `default` | {{subject}} must contain {{containsValue}} {{count}} time(s) |
39+
| `inverted` | {{subject}} must not contain {{containsValue}} {{count}} time(s) |
40+
41+
### `ContainsCount::TEMPLATE_ONCE`
42+
43+
| Mode | Template |
44+
| ---------- | -------------------------------------------------------- |
45+
| `default` | {{subject}} must contain {{containsValue}} only once |
46+
| `inverted` | {{subject}} must not contain {{containsValue}} only once |
47+
48+
## Template placeholders
49+
50+
| Placeholder | Description |
51+
| --------------- | ---------------------------------------------------------------- |
52+
| `containsValue` | The value to search for in the input. |
53+
| `subject` | The validated input or the custom validator name (if specified). |
54+
| `count` | Number of times that the needle might appear in the haystack. |
55+
56+
## Categorization
57+
58+
- Arrays
59+
- Strings
60+
61+
## Changelog
62+
63+
| Version | Description |
64+
| ------: | ----------- |
65+
| 3.0.0 | Created |
66+
67+
---
68+
69+
See also:
70+
71+
- [Contains](Contains.md)
72+
- [ContainsAny](ContainsAny.md)
73+
- [EndsWith](EndsWith.md)
74+
- [Equals](Equals.md)
75+
- [Equivalent](Equivalent.md)
76+
- [Identical](Identical.md)
77+
- [In](In.md)
78+
- [Regex](Regex.md)
79+
- [StartsWith](StartsWith.md)
80+
- [Unique](Unique.md)

docs/validators/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ In this page you will find a list of validators by their category.
88
- [ArrayVal](validators/ArrayVal.md)
99
- [Contains](validators/Contains.md)
1010
- [ContainsAny](validators/ContainsAny.md)
11+
- [ContainsCount](validators/ContainsCount.md)
1112
- [Each](validators/Each.md)
1213
- [EndsWith](validators/EndsWith.md)
1314
- [In](validators/In.md)
@@ -228,6 +229,7 @@ In this page you will find a list of validators by their category.
228229
- [Consonant](validators/Consonant.md)
229230
- [Contains](validators/Contains.md)
230231
- [ContainsAny](validators/ContainsAny.md)
232+
- [ContainsCount](validators/ContainsCount.md)
231233
- [Control](validators/Control.md)
232234
- [Digit](validators/Digit.md)
233235
- [Emoji](validators/Emoji.md)
@@ -331,6 +333,7 @@ In this page you will find a list of validators by their category.
331333
- [Consonant](validators/Consonant.md)
332334
- [Contains](validators/Contains.md)
333335
- [ContainsAny](validators/ContainsAny.md)
336+
- [ContainsCount](validators/ContainsCount.md)
334337
- [Control](validators/Control.md)
335338
- [Countable](validators/Countable.md)
336339
- [CountryCode](validators/CountryCode.md)

library/Mixins/AllBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public static function allContains(mixed $containsValue, bool $identical = false
7070
/** @param non-empty-array<mixed> $needles */
7171
public static function allContainsAny(array $needles, bool $identical = false): Chain;
7272

73+
public static function allContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
74+
7375
public static function allControl(string ...$additionalChars): Chain;
7476

7577
public static function allCountable(): Chain;

library/Mixins/AllChain.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public function allContains(mixed $containsValue, bool $identical = false): Chai
7070
/** @param non-empty-array<mixed> $needles */
7171
public function allContainsAny(array $needles, bool $identical = false): Chain;
7272

73+
public function allContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
74+
7375
public function allControl(string ...$additionalChars): Chain;
7476

7577
public function allCountable(): Chain;

library/Mixins/Builder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ public static function contains(mixed $containsValue, bool $identical = false):
8484
/** @param non-empty-array<mixed> $needles */
8585
public static function containsAny(array $needles, bool $identical = false): Chain;
8686

87+
public static function containsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
88+
8789
public static function control(string ...$additionalChars): Chain;
8890

8991
public static function countable(): Chain;

library/Mixins/Chain.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public function contains(mixed $containsValue, bool $identical = false): Chain;
8787
/** @param non-empty-array<mixed> $needles */
8888
public function containsAny(array $needles, bool $identical = false): Chain;
8989

90+
public function containsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
91+
9092
public function control(string ...$additionalChars): Chain;
9193

9294
public function countable(): Chain;

library/Mixins/KeyBuilder.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ public static function keyContains(int|string $key, mixed $containsValue, bool $
8888
/** @param non-empty-array<mixed> $needles */
8989
public static function keyContainsAny(int|string $key, array $needles, bool $identical = false): Chain;
9090

91+
public static function keyContainsCount(
92+
int|string $key,
93+
mixed $containsValue,
94+
int $count,
95+
bool $identical = false,
96+
): Chain;
97+
9198
public static function keyControl(int|string $key, string ...$additionalChars): Chain;
9299

93100
public static function keyCountable(int|string $key): Chain;

library/Mixins/KeyChain.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ public function keyContains(int|string $key, mixed $containsValue, bool $identic
8888
/** @param non-empty-array<mixed> $needles */
8989
public function keyContainsAny(int|string $key, array $needles, bool $identical = false): Chain;
9090

91+
public function keyContainsCount(
92+
int|string $key,
93+
mixed $containsValue,
94+
int $count,
95+
bool $identical = false,
96+
): Chain;
97+
9198
public function keyControl(int|string $key, string ...$additionalChars): Chain;
9299

93100
public function keyCountable(int|string $key): Chain;

0 commit comments

Comments
 (0)