Skip to content

Commit 71da8a8

Browse files
committed
# feat: Implement 'each' rule for array item validation and enhance documentation. Version 1.2.0
## Description This commit introduces the highly requested `each` validation rule, enabling granular validation of every item within an array against a specified set of sub-rules. The `each` rule supports both `AND` (`&`) and `OR` (`,`) operators, providing flexible control over how multiple sub-rules are applied to array elements. In addition to this new feature, the `README.md` has been substantially updated with comprehensive examples for all existing validation rules, significantly improving the clarity and usability of the documentation. This includes detailed examples for basic, string, length, data type, and advanced rules, as well as a refined error handling section. A critical bug has also been addressed where numeric `min` validation incorrectly checked the string length of a number instead of its actual value. Error messages for numeric `min` and `max` rules have been improved for better clarity and consistency. ## Changes in the codebase * **`src/Rules/Each.php`**: New rule class implementing the `each` validation logic, including support for `&` (AND) and `,` (OR) operators for sub-rules. * **`src/Rules/Lib/RulesIndex.php`**: Registered the new `Each` rule in the rules index. * **`src/Exceptions/ValidationError.php`**: Added a new error message for `attr` when rule attributes are undefined, primarily to support the `each` rule's attribute requirements. * **`src/Rules/Lib/Calculate.php`**: Fixed a bug in the `numaricLength` method where numeric `min` validation was comparing string length (`strlen($data)`) instead of the actual numeric value (`$data`). * **`src/Rules/MaxLength.php`**: Updated the error message for the numeric `max` rule to be more generic ("maximum X" instead of "maximum X digits"). * **`src/Rules/MinLength.php`**: Updated the error message for the numeric `min` rule to be more generic ("minimum X" instead of "minimum X digits"). * **`src/Rules/Lib/RulesParser.php`**: Modified `parseRuleName` to correctly handle attribute parsing for the `each` rule's sub-rules. * **`README.md`**: * Removed the outdated "Handling Errors" section. * Added the `each` rule to the "Available Rules" table. * Introduced a comprehensive "Examples" section with detailed usage for all validation rules, including basic, string, length, data type, advanced, and combining multiple rules. * Updated the "Error Handling Example" to reflect the `error()` method returning an array. ## Additional information The introduction of the `each` rule significantly enhances the validator's capability for handling complex array structures and nested data validation. The improved documentation will make it easier for users to understand and utilize the full range of validation rules effectively. The numeric `min`/`max` fix ensures correct behavior for number-based length checks, preventing unexpected validation failures.
1 parent 1143d90 commit 71da8a8

10 files changed

Lines changed: 457 additions & 26 deletions

File tree

README.md

Lines changed: 340 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,6 @@ $validator = Validator::validate(
4646
<br>
4747
<br>
4848

49-
## Handling Errors
50-
51-
If any data is invalid then `error` method will return error messages array. Otherwise it'll return false.
52-
<br>
53-
`getData` method will return validated data array.
54-
55-
```php
56-
$error = $validator->error();
57-
if ($error) {
58-
return $error;
59-
}
60-
$validator->getData();
61-
```
62-
63-
<br>
64-
<br>
65-
6649
## Available Rules
6750

6851
| Rule | Description |
@@ -84,3 +67,343 @@ $validator->getData();
8467
| integer | Check the value is integer. |
8568
| sameValue | Check the value is same as the given value. |
8669
| array | Check the value is an array. |
70+
| each | validate each item of an array. |
71+
72+
<br>
73+
<br>
74+
75+
## Examples
76+
77+
### Basic Validation Rules
78+
79+
#### Required Rule
80+
Ensures the field is present and not empty.
81+
82+
```php
83+
$validator = Validator::validate(
84+
['username' => 'required'],
85+
['username' => 'john_doe'] // ✅ Valid
86+
);
87+
88+
// Invalid examples:
89+
// ['username' => ''] // ❌ Empty string
90+
// ['username' => null] // ❌ Null value
91+
// [] // ❌ Missing field
92+
```
93+
94+
#### Email Rule
95+
Validates email address format.
96+
97+
```php
98+
$validator = Validator::validate(
99+
['email' => 'email'],
100+
['email' => 'user@example.com'] // ✅ Valid
101+
);
102+
103+
// Invalid examples:
104+
// ['email' => 'invalid-email'] // ❌ Invalid format
105+
// ['email' => '@example.com'] // ❌ Missing username
106+
// ['email' => 'user@'] // ❌ Missing domain
107+
```
108+
109+
#### URL Rule
110+
Validates URL format.
111+
112+
```php
113+
$validator = Validator::validate(
114+
['website' => 'url'],
115+
['website' => 'https://example.com'] // ✅ Valid
116+
);
117+
118+
// Also valid:
119+
// ['website' => 'http://example.com']
120+
// ['website' => 'ftp://files.example.com']
121+
122+
// Invalid examples:
123+
// ['website' => 'not-a-url'] // ❌ Invalid format
124+
// ['website' => 'example.com'] // ❌ Missing protocol
125+
```
126+
127+
### String Validation Rules
128+
129+
#### String Only (stringOnly)
130+
Validates that the value contains only alphabetic characters.
131+
132+
```php
133+
$validator = Validator::validate(
134+
['name' => 'stringOnly'],
135+
['name' => 'John'] // ✅ Valid
136+
);
137+
138+
// Invalid examples:
139+
// ['name' => 'John123'] // ❌ Contains numbers
140+
// ['name' => 'John Doe'] // ❌ Contains space
141+
// ['name' => 'John-Doe'] // ❌ Contains dash
142+
```
143+
144+
#### String with Spaces (stringWithSpace)
145+
Validates strings that can contain alphabetic characters and spaces.
146+
147+
```php
148+
$validator = Validator::validate(
149+
['full_name' => 'stringWithSpace'],
150+
['full_name' => 'John Doe'] // ✅ Valid
151+
);
152+
153+
// Also valid:
154+
// ['full_name' => 'Mary Jane Watson']
155+
156+
// Invalid examples:
157+
// ['full_name' => 'John123'] // ❌ Contains numbers
158+
// ['full_name' => 'John-Doe'] // ❌ Contains dash
159+
```
160+
161+
#### String with Numbers (stringWithNumber)
162+
Validates strings that can contain alphabetic characters and numbers.
163+
164+
```php
165+
$validator = Validator::validate(
166+
['username' => 'stringWithNumber'],
167+
['username' => 'user123'] // ✅ Valid
168+
);
169+
170+
// Also valid:
171+
// ['username' => 'JohnDoe456']
172+
173+
// Invalid examples:
174+
// ['username' => 'user 123'] // ❌ Contains space
175+
// ['username' => 'user-123'] // ❌ Contains dash
176+
```
177+
178+
#### String with Dash (stringWithDash)
179+
Validates strings that can contain alphabetic characters, dashes, and underscores.
180+
181+
```php
182+
$validator = Validator::validate(
183+
['slug' => 'stringWithDash'],
184+
['slug' => 'hello-world_page'] // ✅ Valid
185+
);
186+
187+
// Also valid:
188+
// ['slug' => 'my_awesome_post']
189+
// ['slug' => 'hello-world']
190+
191+
// Invalid examples:
192+
// ['slug' => 'hello world'] // ❌ Contains space
193+
// ['slug' => 'hello123'] // ❌ Contains numbers
194+
```
195+
196+
#### Case Validation Rules
197+
198+
```php
199+
// Uppercase only
200+
$validator = Validator::validate(
201+
['code' => 'uppercase'],
202+
['code' => 'HELLO'] // ✅ Valid
203+
);
204+
205+
// Lowercase only
206+
$validator = Validator::validate(
207+
['tag' => 'lowercase'],
208+
['tag' => 'hello'] // ✅ Valid
209+
);
210+
211+
// Mixed case (both upper and lower case required)
212+
$validator = Validator::validate(
213+
['password' => 'mixedCase'],
214+
['password' => 'HelloWorld'] // ✅ Valid
215+
);
216+
```
217+
218+
#### String with Symbols (stringWithSymbols)
219+
Validates strings that can contain symbols and special characters.
220+
221+
```php
222+
$validator = Validator::validate(
223+
['password' => 'stringWithSymbols'],
224+
['password' => 'Pass@123!'] // ✅ Valid
225+
);
226+
227+
// Also valid:
228+
// ['password' => 'My$ecur3#Pass']
229+
```
230+
231+
### Length Validation Rules
232+
233+
#### Minimum Length (min)
234+
Validates minimum length/size requirements.
235+
236+
```php
237+
// String minimum length
238+
$validator = Validator::validate(
239+
['password' => 'min:8'],
240+
['password' => 'mypassword'] // ✅ Valid (10 characters)
241+
);
242+
243+
// Number minimum value
244+
$validator = Validator::validate(
245+
['age' => 'min:18'],
246+
['age' => 25] // ✅ Valid
247+
);
248+
249+
// Array minimum items
250+
$validator = Validator::validate(
251+
['tags' => 'min:2'],
252+
['tags' => ['php', 'javascript', 'html']] // ✅ Valid (3 items)
253+
);
254+
```
255+
256+
#### Maximum Length (max)
257+
Validates maximum length/size requirements.
258+
259+
```php
260+
// String maximum length
261+
$validator = Validator::validate(
262+
['title' => 'max:100'],
263+
['title' => 'Short Title'] // ✅ Valid
264+
);
265+
266+
// Number maximum value
267+
$validator = Validator::validate(
268+
['score' => 'max:100'],
269+
['score' => 85] // ✅ Valid
270+
);
271+
272+
// Array maximum items
273+
$validator = Validator::validate(
274+
['categories' => 'max:5'],
275+
['categories' => ['tech', 'news']] // ✅ Valid (2 items)
276+
);
277+
```
278+
279+
### Data Type Rules
280+
281+
#### Integer Rule
282+
Validates that the value is an integer.
283+
284+
```php
285+
$validator = Validator::validate(
286+
['age' => 'integer'],
287+
['age' => 25] // ✅ Valid
288+
);
289+
290+
// Also valid:
291+
// ['age' => '30'] // ✅ String numbers are valid
292+
293+
// Invalid examples:
294+
// ['age' => 25.5] // ❌ Float value
295+
// ['age' => 'twenty'] // ❌ Text value
296+
```
297+
298+
#### Array Rule
299+
Validates that the value is an array.
300+
301+
```php
302+
$validator = Validator::validate(
303+
['tags' => 'array'],
304+
['tags' => ['php', 'javascript']] // ✅ Valid
305+
);
306+
307+
// Invalid examples:
308+
// ['tags' => 'php,javascript'] // ❌ String value
309+
// ['tags' => 123] // ❌ Number value
310+
```
311+
312+
### Advanced Rules
313+
314+
#### Same Value (sameValue)
315+
Validates that the field value matches a specific value.
316+
317+
```php
318+
$validator = Validator::validate(
319+
['confirmation' => 'sameValue:yes'],
320+
['confirmation' => 'yes'] // ✅ Valid
321+
);
322+
323+
// For password confirmation:
324+
$validator = Validator::validate(
325+
[
326+
'password' => 'required|min:8',
327+
'password_confirmation' => 'sameValue:' . $_POST['password']
328+
],
329+
$_POST
330+
);
331+
```
332+
333+
#### Each Rule
334+
Validates each item in an array against specified rules.
335+
336+
```php
337+
// Validate each email in an array
338+
$validator = Validator::validate(
339+
['emails' => 'each:email'],
340+
['emails' => ['user1@example.com', 'user2@example.com']] // ✅ Valid
341+
);
342+
343+
// Validate each item with multiple rules (`&` [AND] operator)
344+
$validator = Validator::validate(
345+
['usernames' => 'each:required&stringOnly&min:3'],
346+
['usernames' => ['john', 'jane', 'mike']] // ✅ Valid
347+
);
348+
349+
// Validate each item with OR operator
350+
$validator = Validator::validate(
351+
['identifiers' => 'each:email,integer'],
352+
['identifiers' => ['user@example.com', 12345]] // ✅ Valid
353+
);
354+
```
355+
356+
### Combining Multiple Rules
357+
358+
You can combine multiple rules using the pipe (`|`) separator:
359+
360+
```php
361+
$validator = Validator::validate(
362+
[
363+
'username' => 'required|stringOnly|min:3|max:20',
364+
'email' => 'required|email',
365+
'password' => 'required|min:8|mixedCase',
366+
'age' => 'required|integer|min:18|max:100',
367+
'tags' => 'array|min:1|max:10',
368+
'skills' => 'each:stringOnly&min:2'
369+
],
370+
[
371+
'username' => 'johndoe',
372+
'email' => 'john@example.com',
373+
'password' => 'MySecure123',
374+
'age' => 25,
375+
'tags' => ['php', 'javascript'],
376+
'skills' => ['programming', 'design']
377+
]
378+
);
379+
380+
$data = $validator->getData();
381+
382+
```
383+
384+
### Error Handling Example
385+
386+
If any data is invalid then `error` method will return error messages array. Otherwise it'll return empty array.
387+
388+
```php
389+
$validator = Validator::validate(
390+
[
391+
'username' => 'required|stringOnly|min:3',
392+
'email' => 'required|email'
393+
],
394+
[
395+
'username' => 'ab', // Too short
396+
'email' => 'invalid-email' // Invalid format
397+
]
398+
);
399+
400+
$errors = $validator->error();
401+
if ($errors) {
402+
// Handle validation errors
403+
foreach ($errors as $field => $message) {
404+
echo "Error in {$field}: {$message[0]}\n";
405+
}
406+
}
407+
408+
$data = $validator->getData();
409+
```

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "codesvault/validator",
33
"description": "Data validation library",
4-
"version": "1.1.2",
4+
"version": "1.2.0",
55
"type": "library",
66
"license": "MIT",
77
"autoload": {

src/Exceptions/ValidationError.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ public function errorMessage()
4242
'url' => "`{$this->dataIdentifier}` only allows valid URL",
4343
'sameValue' => "`{$this->dataIdentifier}` only allows same value as {$this->attribute}",
4444

45-
'array' => "`{$this->dataIdentifier}` only allows array",
45+
'array' => "`{$this->dataIdentifier}` only allows array",
46+
47+
'attr' => "`{$this->dataIdentifier}` rule attributes not defined",
4648
];
4749
}
4850

0 commit comments

Comments
 (0)