Skip to content

Commit a44aa41

Browse files
committed
init
0 parents  commit a44aa41

10 files changed

+1620
-0
lines changed

.github/workflows/test.yml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: yii2-array-structure-validator
2+
on:
3+
push:
4+
branches: [ master, dev ]
5+
pull_request:
6+
branches: [ master ]
7+
paths-ignore:
8+
- 'docs/**'
9+
- '*.md'
10+
11+
jobs:
12+
test:
13+
if: "!contains(github.event.head_commit.message, 'skip ci') && !contains(github.event.head_commit.message, 'ci skip')"
14+
name: yii2-array-structure-validator (PHP ${{ matrix.php-versions }})
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: true
18+
matrix:
19+
php-versions: [ '7.1', '7.2', '7.3', '7.4']
20+
21+
steps:
22+
- uses: actions/checkout@v2
23+
24+
- name: Setup PHP, with composer and extensions
25+
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
26+
with:
27+
php-version: ${{ matrix.php-versions }}
28+
extensions: mbstring, intl, gd, imagick, zip, dom, pgsql
29+
30+
- name: Get composer cache directory
31+
id: composercache
32+
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
33+
34+
- name: Cache Composer packages
35+
id: composer-cache
36+
uses: actions/cache@v2
37+
with:
38+
path: ${{ steps.composercache.outputs.dir }}
39+
key: ${{ runner.os }}-php-${{ matrix.php-versions }}-${{ hashFiles('**/composer.json') }}
40+
restore-keys: |
41+
${{ runner.os }}-php-${{ matrix.php-versions }}
42+
43+
- name: Install deps
44+
run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader
45+
46+
- name: Unit tests
47+
run: php vendor/bin/phpunit .

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/.idea
2+
/vendor/
3+
/composer.lock
4+
/phpunit.xml
5+
/.php_cs.cache

.php_cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
$finder = PhpCsFixer\Finder::create()
3+
->in(['src']);
4+
return PhpCsFixer\Config::create()
5+
->setFinder($finder)
6+
->setRules([
7+
'@PSR2' => true,
8+
'array_syntax' => ['syntax' => 'short'],
9+
'general_phpdoc_annotation_remove' => ['annotations' => ['author']],
10+
'header_comment' => [
11+
'comment_type' => 'PHPDoc',
12+
'header' => <<<COMMENT
13+
@copyright Copyright (c) 2020 Insolita <[email protected]> and contributors
14+
@license https://github.com/insolita/yii2-array-structure-validator/blob/master/LICENSE
15+
COMMENT
16+
]
17+
])
18+
;
19+

README.md

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#### Yii2 validator for complex array structures
2+
Validator for array attributes, unlike builtin "each" validator, that support only one rule, this validator can
3+
* validate multiple array attributes and even nested data structures
4+
* All keys that should be present in array must be described, for optional keys default value should be set
5+
* When input array not contains key defined in rules, this key added automatically with null value
6+
* When input array contains key not defined in rules, "unexpected item" error will be defined
7+
8+
#### Installation
9+
10+
```composer require insolita/yii2-array-structure-validator ```
11+
12+
#### Usage
13+
14+
For a simple array with known keys like `['id'=>1, 'name'=>'John Doe']`;
15+
16+
```php
17+
18+
public function rules()
19+
{
20+
return [
21+
//...
22+
['simpleArray', ArrayStructureValidator::class,
23+
'rules'=>[
24+
'id'=>[['required'], ['integer','min'=>0]],
25+
'name'=>[['required'], ['string', 'max'=>100]],
26+
'sex'=>[['default', 'value'=>'male'], ['in','range'=>['male','female']]
27+
]]
28+
],
29+
];
30+
}
31+
```
32+
For multidimensional arrays like `
33+
[
34+
['id'=>1, 'name'=>'John Doe'],
35+
['id'=>2, 'name'=>'Jane Doe','sex'=>'female'],
36+
...
37+
]` set each = true
38+
39+
```php
40+
41+
public function rules()
42+
{
43+
return [
44+
//...
45+
[['multiArray', 'some', 'attrs'], 'required'],
46+
['multiArray', ArrayStructureValidator::class,
47+
'each'=>true,
48+
'rules'=>[
49+
'id'=>[['required'], ['integer','min'=>0]],
50+
'name'=>[['required'], ['string', 'max'=>100]],
51+
'sex'=>[['default', 'value'=>'male'], ['in','range'=>['male','female']]
52+
]]
53+
]
54+
];
55+
}
56+
```
57+
58+
For nested structures like
59+
```
60+
[
61+
'user'=>['id'=>1, 'name'=>'John Doe'],
62+
'coords'=>[['x'=>1, 'y'=>2],['x'=>3,'y'=>4]]
63+
]
64+
```
65+
```php
66+
67+
public function rules()
68+
{
69+
return [
70+
//...
71+
['complexArray', ArrayStructureValidator::class,
72+
'rules'=>[
73+
'user'=>[[ArrayStructureValidator::class,
74+
'rules'=>[
75+
'id'=>[['required'], ['integer','min'=>0]],
76+
'name'=>[['required'], ['string', 'max'=>100]],
77+
]]],
78+
'coords'=>[[ArrayStructureValidator::class,
79+
'each'=>true,
80+
'rules'=>[
81+
'x'=>[['required'], ['integer','min'=>0]],
82+
'y'=>[['required'], ['integer','min'=>0]],
83+
], 'min'=>1, 'max'=>5]],
84+
], 'min'=>2, 'max'=>2]
85+
];
86+
}
87+
```
88+
89+
Model scenarios supported
90+
91+
```php
92+
public function rules()
93+
{
94+
return [
95+
//...
96+
['conditional', ArrayStructureValidator::class,
97+
'rules'=>[
98+
'a'=>[['integer','min'=>0]], //will be checked on any scenario
99+
'b'=>[
100+
['default', 'value'=>1, 'on'=>['create']],
101+
['integer', 'max'=>10, 'except'=>['create']],
102+
['required', 'on'=>['update']],
103+
['integer', 'max'=>1000, 'on'=>['update']],
104+
]
105+
]
106+
]
107+
];
108+
}
109+
```
110+
111+
Closure and Inline validators supported, but with signature different from default
112+
113+
Inline method in model class
114+
115+
```php
116+
public function rules()
117+
{
118+
return [
119+
['array', ArrayStructureValidator::class, 'rules'=>[
120+
'item'=>[['required'], ['customValidator']]
121+
]]
122+
];
123+
}
124+
125+
public function customValidator($attribute, $model, $index, $baseModel, $baseAttribute){
126+
/**
127+
* $model - Dynamic model with attributes equals value data, or value row, if used with each=>true
128+
* $attribute - current keyName
129+
* $index - current array index for multidimensional arrays, or null
130+
* $baseModel - instance of initial model, where validator was attached
131+
* $baseAttribute - name of initial attributed, where validator was attached
132+
133+
* access to validated value - $model->$attribute
134+
* access to whole validated array $baseModel->$baseAttribute
135+
* $model->addError($attribute, '[{index}][{attribute}] Error message', ['index'=>$index]);
136+
*/
137+
}
138+
```
139+
140+
When conditions supported (But not whenClient!)
141+
142+
```php
143+
144+
public function rules()
145+
{
146+
return [
147+
['conditional', ArrayStructureValidator::class,
148+
'rules'=>[
149+
'x'=>[['safe']],
150+
'y'=>[
151+
['default', 'value'=>1, 'when'=>fn(DynamicModel $model) => $model->x < 10],
152+
[
153+
'default',
154+
'value'=>5,
155+
'when'=>function($model, $attribute, $index, $baseModel, $baseAttribute){
156+
return count($baseModel->$baseAttribute) > 5;
157+
}],
158+
]
159+
]]
160+
];
161+
}
162+
```
163+
164+
#### Note:

composer.json

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "insolita/yii2-array-structure-validator",
3+
"description": "Validate array with complex structure",
4+
"type": "library",
5+
"keywords": [
6+
"yii2",
7+
"validator"
8+
],
9+
"require": {
10+
"php": ">=7.1.0",
11+
"yiisoft/yii2": "~2.0.15",
12+
"cebe/indent": "*",
13+
"friendsofphp/php-cs-fixer": "~2.16"
14+
},
15+
"require-dev": {
16+
"phpunit/phpunit": "^6.5|^8.0|^9.0",
17+
"codeception/verify": "1.1.0"
18+
},
19+
"autoload": {
20+
"psr-4": {
21+
"insolita\\ArrayStructureValidator\\": "src/"
22+
}
23+
},
24+
"autoload-dev": {
25+
"psr-4": {
26+
"tests\\": "tests/"
27+
}
28+
},
29+
"license": "MIT",
30+
"authors": [
31+
{
32+
"name": "insolita",
33+
"email": "[email protected]"
34+
}
35+
],
36+
"config": {
37+
"platform": {
38+
"php": "7.1.3"
39+
}
40+
},
41+
"repositories": [
42+
{
43+
"type": "composer",
44+
"url": "https://asset-packagist.org"
45+
}
46+
]
47+
}

phpunit.xml.dist

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<phpunit bootstrap="./tests/bootstrap.php"
3+
colors="true"
4+
convertErrorsToExceptions="true"
5+
convertNoticesToExceptions="true"
6+
convertWarningsToExceptions="true"
7+
stopOnFailure="false">
8+
<testsuites>
9+
<testsuite name="Test Suite">
10+
<directory suffix="Test.php">./tests</directory>
11+
</testsuite>
12+
</testsuites>
13+
</phpunit>

0 commit comments

Comments
 (0)