├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── phpstan.neon ├── phpunit.xml ├── src ├── AbstractValidation.php ├── Exception │ ├── ArrayValidationExceptionInterface.php │ ├── InvalidStructureException.php │ └── InvalidTypeException.php ├── Schema.php ├── SchemaCompiler.php ├── SchemaCompilerInterface.php ├── SchemaInterface.php ├── StrictValidation.php ├── StrictValidationFromDefinition.php ├── StrictValidationFromSchema.php ├── Validation.php ├── ValidationBuilder.php ├── ValidationDefinition.php ├── ValidationDefinitionExecutor.php ├── ValidationFromDefinition.php ├── ValidationFromSchema.php ├── ValidationInterface.php ├── Validator.php └── ValidatorInterface.php └── tests ├── SchemaCompilerTest.php ├── SchemaTest.php ├── StrictValidationTest.php ├── ValidationBuilderTest.php ├── ValidationDefinitionTest.php ├── ValidationFromDefinitionTest.php ├── ValidationFromSchemaTest.php ├── ValidationTest.php └── ValidatorTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore packaged files 2 | *.7z 3 | *.dmg 4 | *.gz 5 | *.iso 6 | *.jar 7 | *.rar 8 | *.tar 9 | *.zip 10 | .phpunit.result.cache 11 | composer.lock 12 | 13 | # ignore app environment files 14 | .prod 15 | .staging 16 | .testing 17 | .dev 18 | .env 19 | 20 | # docker 21 | docker-compose.yml 22 | Dockerfile 23 | DockerfileShell 24 | 25 | # folders to ignore 26 | /.idea 27 | /_temp 28 | /vendor 29 | /tests/_reports 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | VERSION 3.2.0 2 | ------------- 3 | Release date: 2020-04-02 4 | 5 | - added ValidationBuilder 6 | 7 | VERSION 3.1.1 8 | ------------- 9 | Release date: 2020-03-27 10 | 11 | - added "autoload-dev" to composer.json (thank you @ordago) 12 | - added missing extension "ext-json" to composer.json (thank you @ordago) 13 | 14 | VERSION 3.1.0 15 | ------------- 16 | Release date: 2020-03-26 17 | 18 | - use SchemaInterface instead of Schema in StrictValidationFromSchema and ValidationFromSchema 19 | - added validator expectKeyToBeObject() and expectKeysToBeObject() 20 | 21 | VERSION 3.0.0 22 | ------------- 23 | Release date: 2020-03-21 24 | 25 | - introducing schema which add a new way to define your validations structure 26 | - added Schema, SchemaInterface, SchemaCompiler and SchemaCompilerInterface 27 | - added ArrayValidationExceptionInterface to help catching any validation exceptions 28 | - added StrictValidationFromSchema 29 | - rewritten StrictValidation and added AbstractValidation 30 | - added Validation, ValidationFromDefinition and ValidationFromSchema 31 | which act almost like as Strict* classes but without exceptions 32 | - fixed bug with ValidationDefinition where same method validation were not stacked but overwritten 33 | - added ValidationDefinitionExecutor 34 | 35 | VERSION 2.0.0 36 | ------------- 37 | Release date: 2020-02-24 38 | 39 | - [BC] renamed method expectNElement() to expectNKeys() in ArrayValidation 40 | - added expectNKeys() and expectOnlyOneFromKeys() to StrictArrayValidator 41 | - added interfaces ArrayValidationInterface and ArrayValidatorInterface 42 | - [BC] renamed all classes and interfaces with better name 43 | - added ValidationDefinition and StrictValidationFromDefinition 44 | 45 | VERSION 1.1.0 46 | ------------- 47 | Release date: 2020-02-20 48 | 49 | - added methods expectKeysToBeArray(), expectKeysToBeBoolean() and expectKeysToBeFloat() to StrictArrayValidator 50 | - transformed ArrayValidationException to 2 more specific exceptions: InvalidStructureException and InvalidTypeException 51 | - [BC] simplified and reordered constructor params of StrictArrayValidator 52 | 53 | VERSION 1.0.0 54 | ------------- 55 | Release date: 2020-02-07 56 | 57 | - Initial release -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) François Lajoie 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Peak/ArrayValidation 2 | 3 | version 4 | Total Downloads 5 | License 6 | 7 | ## Installation 8 | 9 | composer require peak/array-validation 10 | 11 | ## What is this? 12 | 13 | This component help you to validate array structure by: 14 | 15 | - validating the type of any key values 16 | - ensuring a data structure with expected keys requirements 17 | - preventing structure pollution by allowing only a set of keys 18 | 19 | This is especially useful when dealing with json data request, before using the data, you must validate his content so 20 | you can afterward check the value of those keys with your business logic without worrying about the type or presence of any key value. 21 | 22 | # How to use 23 | ##### 8 Usages 24 | 25 | ## 1- General validation "à la carte" (stateless) 26 | 27 | ```php 28 | $validator = new Validator(); 29 | 30 | if ($validator->expectExactlyKeys($data, $keys) === true) { 31 | // ... 32 | } 33 | ``` 34 | 35 | ## 2- Validation with fluent interface (stateful) 36 | 37 | ```php 38 | $data = [ // data 39 | 'tags' => [], 40 | 'name' => 'foobar' 41 | ]; 42 | $validation = new Validation($data); 43 | 44 | $validation 45 | ->expectExactlyKeys(['tags', 'name']) 46 | ->expectKeyToBeArray('tags'); 47 | ->expectKeyToBeString('name'); 48 | 49 | if ($validation->hasErrors()) { 50 | // $lastError = $validation->getLastError(); 51 | // $errors = $validation->getErrors(); 52 | } 53 | ``` 54 | 55 | ## 3- Strict validation with fluent interface (stateful) 56 | 57 | ```php 58 | 59 | $validation = new StrictValidation($data); 60 | 61 | // will throw an exception if any of tests below fail 62 | $validation 63 | ->expectOnlyKeys(['id', 'title', 'description', 'isPrivate', 'tags']) 64 | ->expectAtLeastKeys(['id', 'title', 'description']) 65 | ->expectKeyToBeInteger('id') 66 | ->expectKeysToBeString(['title', 'description']) 67 | ->expectKeyToBeBoolean('isPrivate') 68 | ->expectKeyToBeArray('tags'); 69 | 70 | // if we reach this point, it means the array structure is 71 | // valid according to the validation rules above. 72 | 73 | ``` 74 | 75 | ## 4- Create a ValidationDefinition for later usage 76 | 77 | ```php 78 | $vDef = new ValidationDefinition(); 79 | $vDef 80 | ->expectOnlyKeys(['title', 'content', 'description']) 81 | ->expectAtLeastKeys(['title', 'content']) 82 | ->expectKeysToBeString(['title', 'content', 'description']); 83 | 84 | $validation = new ValidationFromDefinition($vDef, $data); 85 | 86 | if ($validation->hasErrors()) { 87 | // $validation->getErrors(); 88 | } 89 | 90 | ``` 91 | 92 | ## 5- Create a validation Schema for later usage 93 | 94 | Schema is just another way to write validation definitions. This format is ideal when you want to store schemas in file (ex: json, php array file, yml, etc.) 95 | 96 | ```php 97 | 98 | $mySchema = [ 99 | 'title' => [ 100 | 'type' => 'string', 101 | 'required' => true 102 | ], 103 | 'content' => [ 104 | 'type' => 'string', 105 | 'nullable' => true, 106 | ], 107 | ]; 108 | 109 | $schema = new Schema(new SchemaCompiler(), $mySchema, 'mySchemaName'); 110 | 111 | $validation = new ValidationFromSchema($schema, $data); 112 | 113 | if ($validation->hasErrors()) { 114 | // $validation->getErrors(); 115 | } 116 | ``` 117 | 118 | 119 | 120 | ## 6- Strict validation using ValidationDefinition 121 | 122 | ```php 123 | // all validation definitions are executed at object creation and an exception is thrown if any of tests failed 124 | new StrictValidationFromDefinition($validationDefinition, $arrayToValidate); 125 | ``` 126 | 127 | ## 7- Strict validation using Schema 128 | 129 | ```php 130 | // all validation definitions are executed at object creation and an exception is thrown if any of tests failed 131 | new StrictValidationFromSchema($schema, $arrayToValidate); 132 | ``` 133 | 134 | ## 8- Validation and Strict Validation with ValidationBuilder 135 | 136 | ```php 137 | $validation = new ValidationBuilder(); 138 | $validation 139 | ->expectOnlyKeys(['title', 'content', 'description']) 140 | ->expectAtLeastKeys(['title', 'content']) 141 | ->expectKeysToBeString(['title', 'content', 'description']); 142 | 143 | if ($validation->validate($data) === false) { 144 | // $validation->getErrors(); 145 | // $validation->getLastError(); 146 | } 147 | ``` 148 | 149 | and with strict validation: 150 | 151 | ```php 152 | // will throw an exception if any of tests fail 153 | $validation->strictValidate($data); 154 | ``` 155 | 156 | # Validation methods 157 | ```php 158 | 159 | interface ValidationInterface 160 | { 161 | public function expectExactlyKeys(array $keys); 162 | public function expectOnlyOneFromKeys( array $keys); 163 | public function expectAtLeastKeys(array $keys); 164 | public function expectOnlyKeys(array $keys); 165 | public function expectNKeys(int $n); 166 | public function expectKeyToBeArray(string $key, bool $acceptNull = false); 167 | public function expectKeysToBeArray(array $keys, bool $acceptNull = false); 168 | public function expectKeyToBeInteger(string $key, bool $acceptNull = false); 169 | public function expectKeysToBeInteger(array $keys, bool $acceptNull = false); 170 | public function expectKeyToBeFloat(string $key, bool $acceptNull = false); 171 | public function expectKeysToBeFloat(array $keys, bool $acceptNull = false); 172 | public function expectKeyToBeString(string $key, bool $acceptNull = false); 173 | public function expectKeysToBeString(array $keys, bool $acceptNull = false); 174 | public function expectKeyToBeBoolean(string $key, bool $acceptNull = false); 175 | public function expectKeysToBeBoolean(array $keys, bool $acceptNull = false); 176 | public function expectKeyToBeObject(string $key, bool $acceptNull = false); 177 | public function expectKeysToBeObject(array $keys, bool $acceptNull = false); 178 | } 179 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "peak/array-validation", 3 | "description": "Validation utilities for array structure", 4 | "keywords": ["peak", "array", "validation"], 5 | "license": "MIT", 6 | "type": "library", 7 | "require": { 8 | "php": ">=7.2", 9 | "symfony/polyfill-php73": "^1.14", 10 | "ext-json": "*" 11 | }, 12 | "require-dev": { 13 | "phpunit/phpunit": "^9.0", 14 | "phpstan/phpstan": "^0.12" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "Peak\\ArrayValidation\\": "src/" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Tests\\": "tests/" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: max 3 | checkMissingIterableValueType: false 4 | paths: 5 | - src 6 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | ./tests 11 | 12 | 13 | 14 | 15 | 16 | src 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/AbstractValidation.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | protected $errors = []; 13 | 14 | /** 15 | * @var array 16 | */ 17 | protected $errorMessages = [ 18 | 'expectedN' => '{dataName}invalid data, expected {nExpected} element{nExpectedPlural}, received {nReceived} element{nReceivedPlural}', 19 | 'expected' => '{dataName}invalid data, expected {expectedType} [{keysExpected}], received [{keysReceived}]', 20 | 'type' => '{dataName}invalid type for key [{key}], type {expectedType} is expected', 21 | ]; 22 | 23 | /** 24 | * @param string $type 25 | * @param array $context 26 | * @return string 27 | */ 28 | protected function getErrorMessage(string $type, array $context): string 29 | { 30 | $message = $this->errorMessages[$type]; 31 | $replace = []; 32 | 33 | foreach ($context as $key => $val) { 34 | // check that the value can be casted to string 35 | if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { 36 | $replace['{' . $key . '}'] = $val; 37 | } 38 | } 39 | return strtr($message, $replace); 40 | } 41 | 42 | /** 43 | * @return string|null 44 | */ 45 | public function getLastError(): ?string 46 | { 47 | $lastKey = array_key_last($this->errors); 48 | if ($lastKey === null) { 49 | return $lastKey; 50 | } 51 | return $this->errors[$lastKey]; 52 | } 53 | 54 | /** 55 | * @return bool 56 | */ 57 | public function hasErrors(): bool 58 | { 59 | return !empty($this->errors); 60 | } 61 | 62 | /** 63 | * @return array 64 | */ 65 | public function getErrors(): array 66 | { 67 | return $this->errors; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Exception/ArrayValidationExceptionInterface.php: -------------------------------------------------------------------------------- 1 | compiler = $compiler; 38 | $this->schema = $schema; 39 | $this->schemaName = $schemaName; 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function getName(): string 46 | { 47 | return $this->schemaName; 48 | } 49 | 50 | /** 51 | * @return ValidationDefinition 52 | * @throws Exception\InvalidStructureException 53 | * @throws Exception\InvalidTypeException 54 | */ 55 | public function compile(): ValidationDefinition 56 | { 57 | return $this->compiler->compileSchema($this->schema); 58 | } 59 | 60 | /** 61 | * @inheritDoc 62 | * @return array 63 | */ 64 | public function jsonSerialize() 65 | { 66 | return $this->schema; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/SchemaCompiler.php: -------------------------------------------------------------------------------- 1 | $fieldDefinition) { 20 | if (is_string($fieldName) && is_array($fieldDefinition)) { 21 | $this->handleFieldDefinition($fieldName, $fieldDefinition, $definition); 22 | } 23 | } 24 | 25 | // handle "required" 26 | $this->handleRequiredFields($schema, $definition); 27 | 28 | return $definition; 29 | } 30 | 31 | /** 32 | * @param string $fieldName 33 | * @param array $fieldDefinition 34 | * @param ValidationDefinition $definition 35 | * @throws Exception\InvalidStructureException 36 | * @throws Exception\InvalidTypeException 37 | */ 38 | private function handleFieldDefinition(string $fieldName, array $fieldDefinition, ValidationDefinition $definition): void 39 | { 40 | (new StrictValidation($fieldDefinition, 'compile.schema.field.' . $fieldName)) 41 | ->expectOnlyKeys([ 42 | 'comment', 'type', 'nullable', 'required', 'default', 'values' 43 | ]) 44 | ->expectKeysToBeBoolean([ 45 | 'nullable', 'required' 46 | ]); 47 | 48 | // handle "type" and "nullable" 49 | if (isset($fieldDefinition['type'])) { 50 | $method = 'expectKeyToBe' . ucfirst($fieldDefinition['type']); 51 | $definition->$method($fieldName, $fieldDefinition['nullable'] ?? false); 52 | } 53 | } 54 | 55 | /** 56 | * @param array $schema 57 | * @param ValidationDefinition $definition 58 | */ 59 | private function handleRequiredFields(array $schema, ValidationDefinition $definition): void 60 | { 61 | $definition->expectOnlyKeys(array_keys($schema)); 62 | $atLeastKeys = []; 63 | $fieldCount = 0; 64 | $requiredFieldCount = 0; 65 | foreach ($schema as $field => $fieldDef) { 66 | if (is_array($fieldDef)) { 67 | ++$fieldCount; 68 | if (isset($fieldDef['required']) && $fieldDef['required'] === true) { 69 | $atLeastKeys[] = $field; 70 | ++$requiredFieldCount; 71 | } 72 | } 73 | } 74 | 75 | if ($requiredFieldCount == $fieldCount) { 76 | $definition->expectExactlyKeys($atLeastKeys); 77 | } else { 78 | $definition->expectAtLeastKeys($atLeastKeys); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/SchemaCompilerInterface.php: -------------------------------------------------------------------------------- 1 | checkStructureErrors(); 21 | } 22 | 23 | /** 24 | * @param array $keys 25 | * @return $this 26 | * @throws InvalidStructureException 27 | */ 28 | public function expectAtLeastKeys(array $keys) 29 | { 30 | parent::expectAtLeastKeys($keys); 31 | return $this->checkStructureErrors(); 32 | } 33 | 34 | /** 35 | * @param array $keys 36 | * @return $this 37 | * @throws InvalidStructureException 38 | */ 39 | public function expectOnlyKeys(array $keys) 40 | { 41 | parent::expectOnlyKeys($keys); 42 | return $this->checkStructureErrors(); 43 | } 44 | 45 | /** 46 | * @param array $keys 47 | * @return $this 48 | * @throws InvalidStructureException 49 | */ 50 | public function expectOnlyOneFromKeys(array $keys) 51 | { 52 | parent::expectOnlyOneFromKeys($keys); 53 | return $this->checkStructureErrors(); 54 | } 55 | 56 | /** 57 | * @param int $n 58 | * @return $this 59 | * @throws InvalidStructureException 60 | */ 61 | public function expectNKeys(int $n) 62 | { 63 | parent::expectNKeys($n); 64 | return $this->checkStructureErrors(); 65 | } 66 | 67 | /** 68 | * @param string $key 69 | * @param bool $acceptNull 70 | * @return $this 71 | * @throws InvalidTypeException 72 | */ 73 | public function expectKeyToBeArray(string $key, bool $acceptNull = false) 74 | { 75 | parent::expectKeyToBeArray($key, $acceptNull); 76 | return $this->checkTypeErrors(); 77 | } 78 | 79 | /** 80 | * @param string $key 81 | * @param bool $acceptNull 82 | * @return $this 83 | * @throws InvalidTypeException 84 | */ 85 | public function expectKeyToBeInteger(string $key, bool $acceptNull = false) 86 | { 87 | parent::expectKeyToBeInteger($key, $acceptNull); 88 | return $this->checkTypeErrors(); 89 | } 90 | 91 | /** 92 | * @param string $key 93 | * @param bool $acceptNull 94 | * @return $this 95 | * @throws InvalidTypeException 96 | */ 97 | public function expectKeyToBeFloat(string $key, bool $acceptNull = false) 98 | { 99 | parent::expectKeyToBeFloat($key, $acceptNull); 100 | return $this->checkTypeErrors(); 101 | } 102 | 103 | /** 104 | * @param string $key 105 | * @param bool $acceptNull 106 | * @return $this 107 | * @throws InvalidTypeException 108 | */ 109 | public function expectKeyToBeString(string $key, bool $acceptNull = false) 110 | { 111 | parent::expectKeyToBeString($key, $acceptNull); 112 | return $this->checkTypeErrors(); 113 | } 114 | 115 | /** 116 | * @param string $key 117 | * @param bool $acceptNull 118 | * @return $this 119 | * @throws InvalidTypeException 120 | */ 121 | public function expectKeyToBeBoolean(string $key, bool $acceptNull = false) 122 | { 123 | parent::expectKeyToBeBoolean($key, $acceptNull); 124 | return $this->checkTypeErrors(); 125 | } 126 | 127 | /** 128 | * @param array $keys 129 | * @param bool $acceptNull 130 | * @return $this|Validation 131 | * @throws InvalidTypeException 132 | */ 133 | public function expectKeysToBeString(array $keys, bool $acceptNull = false) 134 | { 135 | foreach ($keys as $key) { 136 | $this->expectKeyToBeString($key, $acceptNull); 137 | } 138 | return $this; 139 | } 140 | 141 | /** 142 | * @param array $keys 143 | * @param bool $acceptNull 144 | * @return $this|Validation 145 | * @throws InvalidTypeException 146 | */ 147 | public function expectKeysToBeInteger(array $keys, bool $acceptNull = false) 148 | { 149 | foreach ($keys as $key) { 150 | $this->expectKeyToBeInteger($key, $acceptNull); 151 | } 152 | return $this; 153 | } 154 | 155 | /** 156 | * @param array $keys 157 | * @param bool $acceptNull 158 | * @return $this|Validation 159 | * @throws InvalidTypeException 160 | */ 161 | public function expectKeysToBeFloat(array $keys, bool $acceptNull = false) 162 | { 163 | foreach ($keys as $key) { 164 | $this->expectKeyToBeFloat($key, $acceptNull); 165 | } 166 | return $this; 167 | } 168 | 169 | /** 170 | * @param array $keys 171 | * @param bool $acceptNull 172 | * @return $this|Validation 173 | * @throws InvalidTypeException 174 | */ 175 | public function expectKeysToBeBoolean(array $keys, bool $acceptNull = false) 176 | { 177 | foreach ($keys as $key) { 178 | $this->expectKeyToBeBoolean($key, $acceptNull); 179 | } 180 | return $this; 181 | } 182 | 183 | /** 184 | * @param array $keys 185 | * @param bool $acceptNull 186 | * @return $this|Validation 187 | * @throws InvalidTypeException 188 | */ 189 | public function expectKeysToBeArray(array $keys, bool $acceptNull = false) 190 | { 191 | foreach ($keys as $key) { 192 | $this->expectKeyToBeArray($key, $acceptNull); 193 | } 194 | return $this; 195 | } 196 | 197 | /** 198 | * @return $this 199 | * @throws InvalidStructureException 200 | */ 201 | protected function checkStructureErrors() 202 | { 203 | if ($this->hasErrors()) { 204 | throw new InvalidStructureException($this->getLastError() ?? ''); 205 | } 206 | return $this; 207 | } 208 | 209 | /** 210 | * @return $this 211 | * @throws InvalidTypeException 212 | */ 213 | protected function checkTypeErrors() 214 | { 215 | if ($this->hasErrors()) { 216 | throw new InvalidTypeException($this->getLastError() ?? ''); 217 | } 218 | return $this; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/StrictValidationFromDefinition.php: -------------------------------------------------------------------------------- 1 | validationDefinition = $validationDefinition; 29 | parent::__construct($data, $dataName, $arrayValidation); 30 | 31 | (new ValidationDefinitionExecutor())->execute( 32 | $validationDefinition, 33 | $this 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/StrictValidationFromSchema.php: -------------------------------------------------------------------------------- 1 | getName(), $arrayValidation); 23 | 24 | $validationDefinition = $schema->compile(); 25 | 26 | (new ValidationDefinitionExecutor())->execute( 27 | $validationDefinition, 28 | $this 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Validation.php: -------------------------------------------------------------------------------- 1 | data = $data; 33 | $this->dataName = $dataName; 34 | if (!isset($validator)) { 35 | $validator = new Validator(); 36 | } 37 | $this->validator = $validator; 38 | } 39 | 40 | /** 41 | * @param array $keys 42 | * @return $this 43 | */ 44 | public function expectExactlyKeys(array $keys) 45 | { 46 | if ($this->validator->expectExactlyKeys($this->data, $keys) === false) { 47 | $keysReceived = array_keys($this->data); 48 | natsort($keys); 49 | natsort($keysReceived); 50 | $this->errors[] = $this->getErrorMessage('expected', [ 51 | 'expectedType' => 'exactly keys', 52 | 'keysExpected' => implode(', ', $keys), 53 | 'keysReceived' => implode(', ', $keysReceived) 54 | ]); 55 | } 56 | return $this; 57 | } 58 | 59 | /** 60 | * @param array $keys 61 | * @return $this 62 | */ 63 | public function expectAtLeastKeys(array $keys) 64 | { 65 | if ($this->validator->expectAtLeastKeys($this->data, $keys) === false) { 66 | $keysReceived = array_keys($this->data); 67 | natsort($keys); 68 | natsort($keysReceived); 69 | $this->errors[] = $this->getErrorMessage('expected', [ 70 | 'expectedType' => 'at least keys', 71 | 'keysExpected' => implode(', ', $keys), 72 | 'keysReceived' => implode(', ', $keysReceived) 73 | ]); 74 | } 75 | return $this; 76 | } 77 | 78 | /** 79 | * @param array $keys 80 | * @return $this 81 | */ 82 | public function expectOnlyKeys(array $keys) 83 | { 84 | if ($this->validator->expectOnlyKeys($this->data, $keys) === false) { 85 | $keysReceived = array_keys($this->data); 86 | natsort($keys); 87 | natsort($keysReceived); 88 | $this->errors[] = $this->getErrorMessage('expected', [ 89 | 'expectedType' => 'only keys', 90 | 'keysExpected' => implode(', ', $keys), 91 | 'keysReceived' => implode(', ', $keysReceived) 92 | ]); 93 | } 94 | return $this; 95 | } 96 | 97 | /** 98 | * @param array $keys 99 | * @return $this 100 | */ 101 | public function expectOnlyOneFromKeys(array $keys) 102 | { 103 | if ($this->validator->expectOnlyOneFromKeys($this->data, $keys) === false) { 104 | $keysReceived = array_keys($this->data); 105 | natsort($keys); 106 | natsort($keysReceived); 107 | $this->errors[] = $this->getErrorMessage('expected', [ 108 | 'expectedType' => 'only one of keys', 109 | 'keysExpected' => implode(', ', $keys), 110 | 'keysReceived' => implode(', ', $keysReceived) 111 | ]); 112 | } 113 | return $this; 114 | } 115 | 116 | /** 117 | * @param int $n 118 | * @return $this 119 | */ 120 | public function expectNKeys(int $n) 121 | { 122 | if ($this->validator->expectNKeys($this->data, $n) === false) { 123 | $keysReceived = array_keys($this->data); 124 | natsort($keysReceived); 125 | $this->errors[] = $this->getErrorMessage('expectedN', [ 126 | 'expectedType' => 'only N keys', 127 | 'nExpected' => $n, 128 | 'nExpectedPlural' => $n > 1 ? 's' : '', 129 | 'nReceivedPlural' => count($keysReceived) > 1 ? 's' : '', 130 | 'nReceived' => count($keysReceived) 131 | ]); 132 | } 133 | return $this; 134 | } 135 | 136 | /** 137 | * @param string $key 138 | * @param bool $acceptNull 139 | * @return $this 140 | */ 141 | public function expectKeyToBeArray(string $key, bool $acceptNull = false) 142 | { 143 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeArray($this->data, $key, $acceptNull) === false) { 144 | $this->errors[] = $this->getErrorMessage('type', [ 145 | 'key' => $key, 146 | 'expectedType' => 'array', 147 | ]); 148 | } 149 | return $this; 150 | } 151 | 152 | /** 153 | * @param string $key 154 | * @param bool $acceptNull 155 | * @return $this 156 | */ 157 | public function expectKeyToBeInteger(string $key, bool $acceptNull = false) 158 | { 159 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeInteger($this->data, $key, $acceptNull) === false) { 160 | $this->errors[] = $this->getErrorMessage('type', [ 161 | 'key' => $key, 162 | 'expectedType' => 'integer', 163 | ]); 164 | } 165 | return $this; 166 | } 167 | 168 | /** 169 | * @param string $key 170 | * @param bool $acceptNull 171 | * @return $this 172 | */ 173 | public function expectKeyToBeFloat(string $key, bool $acceptNull = false) 174 | { 175 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeFloat($this->data, $key, $acceptNull) === false) { 176 | $this->errors[] = $this->getErrorMessage('type', [ 177 | 'key' => $key, 178 | 'expectedType' => 'float', 179 | ]); 180 | } 181 | return $this; 182 | } 183 | 184 | /** 185 | * @param string $key 186 | * @param bool $acceptNull 187 | * @return $this 188 | */ 189 | public function expectKeyToBeString(string $key, bool $acceptNull = false) 190 | { 191 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeString($this->data, $key, $acceptNull) === false) { 192 | $this->errors[] = $this->getErrorMessage('type', [ 193 | 'key' => $key, 194 | 'expectedType' => 'string', 195 | ]); 196 | } 197 | return $this; 198 | } 199 | 200 | /** 201 | * @param string $key 202 | * @param bool $acceptNull 203 | * @return $this 204 | */ 205 | public function expectKeyToBeBoolean(string $key, bool $acceptNull = false) 206 | { 207 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeBoolean($this->data, $key, $acceptNull) === false) { 208 | $this->errors[] = $this->getErrorMessage('type', [ 209 | 'key' => $key, 210 | 'expectedType' => 'boolean', 211 | ]); 212 | } 213 | return $this; 214 | } 215 | 216 | /** 217 | * @param string $key 218 | * @param bool $acceptNull 219 | * @return $this 220 | */ 221 | public function expectKeyToBeObject(string $key, bool $acceptNull = false) 222 | { 223 | if (array_key_exists($key, $this->data) && $this->validator->expectKeyToBeObject($this->data, $key, $acceptNull) === false) { 224 | $this->errors[] = $this->getErrorMessage('type', [ 225 | 'key' => $key, 226 | 'expectedType' => 'object', 227 | ]); 228 | } 229 | return $this; 230 | } 231 | 232 | /** 233 | * @param array $keys 234 | * @param bool $acceptNull 235 | * @return $this 236 | */ 237 | public function expectKeysToBeString(array $keys, bool $acceptNull = false) 238 | { 239 | foreach ($keys as $key) { 240 | $this->expectKeyToBeString($key, $acceptNull); 241 | } 242 | return $this; 243 | } 244 | 245 | /** 246 | * @param array $keys 247 | * @param bool $acceptNull 248 | * @return $this 249 | */ 250 | public function expectKeysToBeInteger(array $keys, bool $acceptNull = false) 251 | { 252 | foreach ($keys as $key) { 253 | $this->expectKeyToBeInteger($key, $acceptNull); 254 | } 255 | return $this; 256 | } 257 | 258 | /** 259 | * @param array $keys 260 | * @param bool $acceptNull 261 | * @return $this 262 | */ 263 | public function expectKeysToBeFloat(array $keys, bool $acceptNull = false) 264 | { 265 | foreach ($keys as $key) { 266 | $this->expectKeyToBeFloat($key, $acceptNull); 267 | } 268 | return $this; 269 | } 270 | 271 | /** 272 | * @param array $keys 273 | * @param bool $acceptNull 274 | * @return $this 275 | */ 276 | public function expectKeysToBeBoolean(array $keys, bool $acceptNull = false) 277 | { 278 | foreach ($keys as $key) { 279 | $this->expectKeyToBeBoolean($key, $acceptNull); 280 | } 281 | return $this; 282 | } 283 | 284 | /** 285 | * @param array $keys 286 | * @param bool $acceptNull 287 | * @return $this 288 | */ 289 | public function expectKeysToBeArray(array $keys, bool $acceptNull = false) 290 | { 291 | foreach ($keys as $key) { 292 | $this->expectKeyToBeArray($key, $acceptNull); 293 | } 294 | return $this; 295 | } 296 | 297 | /** 298 | * @param array $keys 299 | * @param bool $acceptNull 300 | * @return $this 301 | */ 302 | public function expectKeysToBeObject(array $keys, bool $acceptNull = false) 303 | { 304 | foreach ($keys as $key) { 305 | $this->expectKeyToBeObject($key, $acceptNull); 306 | } 307 | return $this; 308 | } 309 | 310 | /** 311 | * @return string|null 312 | */ 313 | protected function getExceptionDataName(): ?string 314 | { 315 | if (isset($this->dataName)) { 316 | return '['. $this->dataName.'] '; 317 | } 318 | return null; 319 | } 320 | 321 | /** 322 | * @param string $type 323 | * @param array $context 324 | * @return string 325 | */ 326 | protected function getErrorMessage(string $type, array $context): string 327 | { 328 | $context = array_merge(['dataName' => $this->getExceptionDataName()], $context); 329 | return parent::getErrorMessage($type, $context); 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /src/ValidationBuilder.php: -------------------------------------------------------------------------------- 1 | errors = $validation->getErrors(); 27 | $this->lastError = $validation->getLastError(); 28 | return !$validation->hasErrors(); 29 | } 30 | 31 | /** 32 | * @param array $data 33 | * @throw InvalidStructureException 34 | * @throw InvalidTypeException 35 | */ 36 | public function strictValidate(array $data): void 37 | { 38 | new StrictValidationFromDefinition($this, $data); 39 | } 40 | 41 | /** 42 | * @return array 43 | */ 44 | public function getErrors(): array 45 | { 46 | return $this->errors; 47 | } 48 | 49 | /** 50 | * @return string|null 51 | */ 52 | public function getLastError(): ?string 53 | { 54 | return $this->lastError; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ValidationDefinition.php: -------------------------------------------------------------------------------- 1 | [], 16 | 'expectOnlyOneFromKeys' => [], 17 | 'expectAtLeastKeys' => [], 18 | 'expectOnlyKeys' => [], 19 | 'expectNKeys' => [], 20 | 'expectKeyToBeArray' => [], 21 | 'expectKeysToBeArray' => [], 22 | 'expectKeyToBeInteger' => [], 23 | 'expectKeysToBeInteger' => [], 24 | 'expectKeyToBeFloat' => [], 25 | 'expectKeysToBeFloat' => [], 26 | 'expectKeyToBeString' => [], 27 | 'expectKeysToBeString' => [], 28 | 'expectKeyToBeBoolean' => [], 29 | 'expectKeysToBeBoolean' => [], 30 | 'expectKeyToBeObject' => [], 31 | 'expectKeysToBeObject' => [], 32 | ]; 33 | 34 | /** 35 | * @return array 36 | */ 37 | public function getValidations(): array 38 | { 39 | $validations = []; 40 | foreach ($this->validations as $name => $args) { 41 | if (!empty($args)) { 42 | $validations[$name] = $args; 43 | } 44 | } 45 | return $validations; 46 | } 47 | 48 | /** 49 | * @param array $keys 50 | * @return $this 51 | */ 52 | public function expectExactlyKeys(array $keys) 53 | { 54 | return $this->addValidation(__FUNCTION__, func_get_args()); 55 | } 56 | 57 | /** 58 | * @param array $keys 59 | * @return $this 60 | */ 61 | public function expectOnlyOneFromKeys(array $keys) 62 | { 63 | return $this->addValidation(__FUNCTION__, func_get_args()); 64 | } 65 | 66 | /** 67 | * @param array $keys 68 | * @return $this 69 | */ 70 | public function expectAtLeastKeys(array $keys) 71 | { 72 | return $this->addValidation(__FUNCTION__, func_get_args()); 73 | } 74 | 75 | /** 76 | * @param array $keys 77 | * @return $this 78 | */ 79 | public function expectOnlyKeys(array $keys) 80 | { 81 | return $this->addValidation(__FUNCTION__, func_get_args()); 82 | } 83 | 84 | /** 85 | * @param int $n 86 | * @return $this 87 | */ 88 | public function expectNKeys(int $n) 89 | { 90 | return $this->addValidation(__FUNCTION__, func_get_args()); 91 | } 92 | 93 | /** 94 | * @param string $key 95 | * @param bool $acceptNull 96 | * @return $this 97 | */ 98 | public function expectKeyToBeArray(string $key, bool $acceptNull = false) 99 | { 100 | return $this->addValidation(__FUNCTION__, func_get_args()); 101 | } 102 | 103 | /** 104 | * @param array $keys 105 | * @param bool $acceptNull 106 | * @return $this 107 | */ 108 | public function expectKeysToBeArray(array $keys, bool $acceptNull = false) 109 | { 110 | return $this->addValidation(__FUNCTION__, func_get_args()); 111 | } 112 | 113 | /** 114 | * @param string $key 115 | * @param bool $acceptNull 116 | * @return $this 117 | */ 118 | public function expectKeyToBeInteger(string $key, bool $acceptNull = false) 119 | { 120 | return $this->addValidation(__FUNCTION__, func_get_args()); 121 | } 122 | 123 | /** 124 | * @param array $keys 125 | * @param bool $acceptNull 126 | * @return $this 127 | */ 128 | public function expectKeysToBeInteger(array $keys, bool $acceptNull = false) 129 | { 130 | return $this->addValidation(__FUNCTION__, func_get_args()); 131 | } 132 | 133 | /** 134 | * @param string $key 135 | * @param bool $acceptNull 136 | * @return $this 137 | */ 138 | public function expectKeyToBeFloat(string $key, bool $acceptNull = false) 139 | { 140 | return $this->addValidation(__FUNCTION__, func_get_args()); 141 | } 142 | 143 | /** 144 | * @param array $keys 145 | * @param bool $acceptNull 146 | * @return $this 147 | */ 148 | public function expectKeysToBeFloat(array $keys, bool $acceptNull = false) 149 | { 150 | return $this->addValidation(__FUNCTION__, func_get_args()); 151 | } 152 | 153 | /** 154 | * @param string $key 155 | * @param bool $acceptNull 156 | * @return $this 157 | */ 158 | public function expectKeyToBeString(string $key, bool $acceptNull = false) 159 | { 160 | return $this->addValidation(__FUNCTION__, func_get_args()); 161 | } 162 | 163 | /** 164 | * @param array $keys 165 | * @param bool $acceptNull 166 | * @return $this 167 | */ 168 | public function expectKeysToBeString(array $keys, bool $acceptNull = false) 169 | { 170 | return $this->addValidation(__FUNCTION__, func_get_args()); 171 | } 172 | 173 | /** 174 | * @param string $key 175 | * @param bool $acceptNull 176 | * @return $this 177 | */ 178 | public function expectKeyToBeBoolean(string $key, bool $acceptNull = false) 179 | { 180 | return $this->addValidation(__FUNCTION__, func_get_args()); 181 | } 182 | 183 | /** 184 | * @param array $keys 185 | * @param bool $acceptNull 186 | * @return $this 187 | */ 188 | public function expectKeysToBeBoolean(array $keys, bool $acceptNull = false) 189 | { 190 | return $this->addValidation(__FUNCTION__, func_get_args()); 191 | } 192 | 193 | /** 194 | * @param string $key 195 | * @param bool $acceptNull 196 | * @return $this 197 | */ 198 | public function expectKeyToBeObject(string $key, bool $acceptNull = false) 199 | { 200 | return $this->addValidation(__FUNCTION__, func_get_args()); 201 | } 202 | 203 | /** 204 | * @param array $keys 205 | * @param bool $acceptNull 206 | * @return $this 207 | */ 208 | public function expectKeysToBeObject(array $keys, bool $acceptNull = false) 209 | { 210 | return $this->addValidation(__FUNCTION__, func_get_args()); 211 | } 212 | 213 | /** 214 | * @inheritDoc 215 | * @return array 216 | */ 217 | public function jsonSerialize() 218 | { 219 | return $this->getValidations(); 220 | } 221 | 222 | /** 223 | * @param string $validationName 224 | * @param array $validationArgs 225 | * @return $this 226 | */ 227 | protected function addValidation(string $validationName, array $validationArgs) 228 | { 229 | $this->validations[$validationName][] = $validationArgs; 230 | return $this; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/ValidationDefinitionExecutor.php: -------------------------------------------------------------------------------- 1 | getValidations(); 14 | foreach ($validations as $name => $multipleArgs) { 15 | foreach ($multipleArgs as $args) { 16 | $callable = [$validation, $name]; 17 | if (is_callable($callable)) { 18 | call_user_func_array($callable, $args); 19 | } 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ValidationFromDefinition.php: -------------------------------------------------------------------------------- 1 | validationDefinition = $validationDefinition; 28 | parent::__construct($data, $dataName, $arrayValidation); 29 | 30 | (new ValidationDefinitionExecutor())->execute( 31 | $validationDefinition, 32 | $this 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ValidationFromSchema.php: -------------------------------------------------------------------------------- 1 | getName(), $arrayValidation); 23 | 24 | $validationDefinition = $schema->compile(); 25 | (new ValidationDefinitionExecutor())->execute( 26 | $validationDefinition, 27 | $this 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ValidationInterface.php: -------------------------------------------------------------------------------- 1 | $expectedCount) { 19 | return false; 20 | } 21 | $actuallyCount = 0; 22 | foreach ($keysName as $key) { 23 | if (array_key_exists($key, $array)) { 24 | ++$actuallyCount; 25 | } 26 | } 27 | return ($actuallyCount === $expectedCount); 28 | } 29 | 30 | /** 31 | * The array should be length of 1 and have a key from expected keys 32 | * @param array $array 33 | * @param array $keysName 34 | * @return bool 35 | */ 36 | public function expectOnlyOneFromKeys(array $array, array $keysName): bool 37 | { 38 | if (count($array) <> 1) { 39 | return false; 40 | } 41 | $keys = array_keys($array); 42 | return in_array($keys[0], $keysName); 43 | } 44 | 45 | /** 46 | * The array should have at least expected keys 47 | * @param array $array 48 | * @param array $keysName 49 | * @return bool 50 | */ 51 | public function expectAtLeastKeys(array $array, array $keysName): bool 52 | { 53 | foreach ($keysName as $key) { 54 | if (!array_key_exists($key, $array)) { 55 | return false; 56 | } 57 | } 58 | return true; 59 | } 60 | 61 | /** 62 | * The array keys must be in keys name. 63 | * @param array $array 64 | * @param array $keysName 65 | * @return bool 66 | */ 67 | public function expectOnlyKeys(array $array, array $keysName): bool 68 | { 69 | foreach (array_keys($array) as $key) { 70 | if (!in_array($key, $keysName)) { 71 | return false; 72 | } 73 | } 74 | return true; 75 | } 76 | 77 | /** 78 | * The array should be exactly the length of X 79 | * @param array $array 80 | * @param int $n 81 | * @return bool 82 | */ 83 | public function expectNKeys(array $array, int $n): bool 84 | { 85 | return ($n == count($array)); 86 | } 87 | 88 | /** 89 | * @param array $array 90 | * @param string $key 91 | * @param bool $acceptNull 92 | * @return bool 93 | */ 94 | public function expectKeyToBeArray(array $array, string $key, bool $acceptNull = false): bool 95 | { 96 | return $this->internalTypeValidation('is_array', $array, $key, $acceptNull); 97 | } 98 | 99 | /** 100 | * @param array $array 101 | * @param array $keys 102 | * @param bool $acceptNull 103 | * @return bool 104 | */ 105 | public function expectKeysToBeArray(array $array, array $keys, bool $acceptNull = false): bool 106 | { 107 | foreach ($keys as $key) { 108 | if ($this->expectKeyToBeArray($array, $key, $acceptNull) === false) { 109 | return false; 110 | } 111 | } 112 | return true; 113 | } 114 | 115 | /** 116 | * @param array $array 117 | * @param string $key 118 | * @param bool $acceptNull 119 | * @return bool 120 | */ 121 | public function expectKeyToBeInteger(array $array, string $key, bool $acceptNull = false): bool 122 | { 123 | return $this->internalTypeValidation('is_integer', $array, $key, $acceptNull); 124 | } 125 | 126 | /** 127 | * @param array $array 128 | * @param array $keys 129 | * @param bool $acceptNull 130 | * @return bool 131 | */ 132 | public function expectKeysToBeInteger(array $array, array $keys, bool $acceptNull = false): bool 133 | { 134 | foreach ($keys as $key) { 135 | if ($this->expectKeyToBeInteger($array, $key, $acceptNull) === false) { 136 | return false; 137 | } 138 | } 139 | return true; 140 | } 141 | 142 | /** 143 | * @param array $array 144 | * @param string $key 145 | * @param bool $acceptNull 146 | * @return bool 147 | */ 148 | public function expectKeyToBeString(array $array, string $key, bool $acceptNull = false): bool 149 | { 150 | return $this->internalTypeValidation('is_string', $array, $key, $acceptNull); 151 | } 152 | 153 | /** 154 | * @param array $array 155 | * @param array $keys 156 | * @param bool $acceptNull 157 | * @return bool 158 | */ 159 | public function expectKeysToBeString(array $array, array $keys, bool $acceptNull = false): bool 160 | { 161 | foreach ($keys as $key) { 162 | if ($this->expectKeyToBeString($array, $key, $acceptNull) === false) { 163 | return false; 164 | } 165 | } 166 | return true; 167 | } 168 | 169 | /** 170 | * @param array $array 171 | * @param string $key 172 | * @param bool $acceptNull 173 | * @return bool 174 | */ 175 | public function expectKeyToBeFloat(array $array, string $key, bool $acceptNull = false): bool 176 | { 177 | return $this->internalTypeValidation('is_float', $array, $key, $acceptNull); 178 | } 179 | 180 | /** 181 | * @param array $array 182 | * @param array $keys 183 | * @param bool $acceptNull 184 | * @return bool 185 | */ 186 | public function expectKeysToBeFloat(array $array, array $keys, bool $acceptNull = false): bool 187 | { 188 | foreach ($keys as $key) { 189 | if ($this->expectKeyToBeFloat($array, $key, $acceptNull) === false) { 190 | return false; 191 | } 192 | } 193 | return true; 194 | } 195 | 196 | /** 197 | * @param array $array 198 | * @param string $key 199 | * @param bool $acceptNull 200 | * @return bool 201 | */ 202 | public function expectKeyToBeBoolean(array $array, string $key, bool $acceptNull = false): bool 203 | { 204 | return $this->internalTypeValidation('is_bool', $array, $key, $acceptNull); 205 | } 206 | 207 | /** 208 | * @param array $array 209 | * @param array $keys 210 | * @param bool $acceptNull 211 | * @return bool 212 | */ 213 | public function expectKeysToBeBoolean(array $array, array $keys, bool $acceptNull = false): bool 214 | { 215 | foreach ($keys as $key) { 216 | if ($this->expectKeyToBeBoolean($array, $key, $acceptNull) === false) { 217 | return false; 218 | } 219 | } 220 | return true; 221 | } 222 | 223 | /** 224 | * @param array $array 225 | * @param string $key 226 | * @param bool $acceptNull 227 | * @return bool 228 | */ 229 | public function expectKeyToBeObject(array $array, string $key, bool $acceptNull = false): bool 230 | { 231 | return $this->internalTypeValidation('is_object', $array, $key, $acceptNull); 232 | } 233 | 234 | /** 235 | * @param array $array 236 | * @param array $keys 237 | * @param bool $acceptNull 238 | * @return bool 239 | */ 240 | public function expectKeysToBeObject(array $array, array $keys, bool $acceptNull = false): bool 241 | { 242 | foreach ($keys as $key) { 243 | if ($this->expectKeyToBeObject($array, $key, $acceptNull) === false) { 244 | return false; 245 | } 246 | } 247 | return true; 248 | } 249 | 250 | /** 251 | * @param string $method 252 | * @param array $array 253 | * @param string $key 254 | * @param bool $acceptNull 255 | * @return bool 256 | */ 257 | private function internalTypeValidation(string $method, array $array, string $key, bool $acceptNull = false): bool 258 | { 259 | return !( 260 | (!array_key_exists($key, $array)) || 261 | (!$acceptNull && !$method($array[$key])) || 262 | ($acceptNull && ($array[$key] !== null && !$method($array[$key]))) 263 | ); 264 | } 265 | 266 | 267 | 268 | } 269 | -------------------------------------------------------------------------------- /src/ValidatorInterface.php: -------------------------------------------------------------------------------- 1 | 'category.schema', 23 | 'field1' => [ 24 | 'type' => 'array', 25 | 'required' => true 26 | ], 27 | 'field2' => [ 28 | 'type' => 'string', 29 | 'required' => true 30 | ], 31 | ], 32 | [ // data 33 | 'field1' => [], 34 | 'field2' => 'strong' 35 | ] 36 | ], 37 | [ 38 | [ // schema 39 | 'name' => 'post.schema', 40 | 'field1' => [ 41 | 'type' => 'array', 42 | 'required' => true 43 | ], 44 | 'field2' => [ 45 | 'type' => 'string', 46 | 'required' => false, 47 | 'nullable' => true, 48 | ], 49 | ], 50 | [ // data 51 | 'field1' => [], 52 | 'field2' => null 53 | ] 54 | ], 55 | ]; 56 | } 57 | 58 | /** 59 | * @dataProvider dataProvider 60 | * @param $schema 61 | * @param $data 62 | * @throws InvalidStructureException 63 | * @throws InvalidTypeException 64 | */ 65 | public function testExpectExactlyKeys($schema, $data) 66 | { 67 | $def = new SchemaCompiler(); 68 | $validationDefinition = $def->compileSchema($schema); 69 | $this->assertInstanceOf(ValidationInterface::class, $validationDefinition); 70 | new StrictValidationFromDefinition($validationDefinition, $data); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/SchemaTest.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'type' => 'array', 25 | 'required' => true 26 | ], 27 | 'field2' => [ 28 | 'type' => 'string', 29 | 'required' => true 30 | ], 31 | ], 32 | [ // data 33 | 'field1' => [], 34 | 'field2' => 'strong' 35 | ] 36 | ], 37 | [ 38 | [ // schema 39 | 'field1' => [ 40 | 'type' => 'array', 41 | 'required' => true 42 | ], 43 | 'field2' => [ 44 | 'type' => 'string', 45 | 'required' => false, 46 | 'nullable' => true, 47 | ], 48 | ], 49 | [ // data 50 | 'field1' => [], 51 | 'field2' => null 52 | ] 53 | ], 54 | ]; 55 | } 56 | 57 | /** 58 | * @dataProvider dataProvider 59 | * @param $schema 60 | * @param $data 61 | * @throws InvalidStructureException 62 | * @throws InvalidTypeException 63 | */ 64 | public function testExpectExactlyKeys($schema, $data) 65 | { 66 | $compiler = new SchemaCompiler(); 67 | $schema = new Schema($compiler, $schema, 'myName'); 68 | $validationDefinition = $schema->compile(); 69 | $this->assertInstanceOf(ValidationInterface::class, $validationDefinition); 70 | $this->assertTrue($schema->getName() === 'myName'); 71 | new StrictValidationFromDefinition($validationDefinition, $data); 72 | } 73 | 74 | public function testJsonSerialize() 75 | { 76 | $compiler = new SchemaCompiler(); 77 | $schema = new Schema($compiler, ['schema'], 'myName'); 78 | $this->assertTrue(json_encode($schema) === '["schema"]'); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/StrictValidationTest.php: -------------------------------------------------------------------------------- 1 | 'foo', 16 | 'content' => 'foobar', 17 | ]; 18 | 19 | private $data2 = [ 20 | 'id' => 1, 21 | 'title' => 'foo', 22 | 'isPrivate' => true, 23 | 'tags' => ['tag1', ''], 24 | 'money' => 15.55 25 | ]; 26 | 27 | private $data3 = [ 28 | 'title' => null, 29 | 'views' => 45, 30 | 'comments' => [] 31 | ]; 32 | 33 | /** 34 | * @throws InvalidStructureException 35 | * @throws InvalidTypeException 36 | */ 37 | public function testNoException1() 38 | { 39 | $strictValidator = new StrictValidation($this->data1); 40 | 41 | $strictValidator 42 | ->expectAtLeastKeys(['title', 'content']) 43 | ->expectExactlyKeys(['title', 'content']) 44 | ->expectOnlyKeys(['title', 'content']) 45 | ->expectKeysToBeString(['title', 'content']); 46 | 47 | $this->assertTrue(true); 48 | } 49 | 50 | /** 51 | * @throws InvalidStructureException 52 | * @throws InvalidTypeException 53 | */ 54 | public function testNoException2() 55 | { 56 | $strictValidator = new StrictValidation($this->data2); 57 | 58 | $strictValidator 59 | ->expectOnlyKeys(['id', 'title', 'isPrivate', 'tags', 'money']) 60 | ->expectKeysToBeInteger(['id']) 61 | ->expectKeysToBeString(['title']) 62 | ->expectKeysToBeBoolean(['isPrivate']) 63 | ->expectKeysToBeArray(['tags']) 64 | ->expectKeysToBeFloat(['money']); 65 | 66 | $this->assertTrue(true); 67 | } 68 | 69 | /** 70 | * @throws InvalidStructureException 71 | */ 72 | public function testOnlyKeysException() 73 | { 74 | $this->expectException(InvalidStructureException::class); 75 | $strictValidator = new StrictValidation(['title' => 1]); 76 | $strictValidator->expectOnlyKeys(['name']); 77 | } 78 | 79 | /** 80 | * @throws InvalidStructureException 81 | */ 82 | public function testNKeysException() 83 | { 84 | $this->expectException(InvalidStructureException::class); 85 | $strictValidator = new StrictValidation(['title' => 1, 'description' => 'foo']); 86 | $strictValidator->expectNKeys(1); 87 | } 88 | 89 | /** 90 | * @throws InvalidStructureException 91 | */ 92 | public function testNKeysNoException() 93 | { 94 | $strictValidator = new StrictValidation(['title' => 1]); 95 | $strictValidator->expectNKeys(1); 96 | $this->assertTrue(true); 97 | } 98 | 99 | /** 100 | * @throws InvalidStructureException 101 | */ 102 | public function testOnlyOneFromKeysException() 103 | { 104 | $this->expectException(InvalidStructureException::class); 105 | $strictValidator = new StrictValidation(['title' => 'x', 'description' => 'foo']); 106 | $strictValidator->expectOnlyOneFromKeys(['title', 'description']); 107 | } 108 | 109 | /** 110 | * @throws InvalidStructureException 111 | */ 112 | public function testExactlyKeysException() 113 | { 114 | $this->expectException(InvalidStructureException::class); 115 | $strictValidator = new StrictValidation(['title' => 1]); 116 | $strictValidator->expectExactlyKeys(['name']); 117 | } 118 | 119 | /** 120 | * @throws InvalidStructureException 121 | */ 122 | public function testOnlyOneFromKeysNoException() 123 | { 124 | $strictValidator = new StrictValidation(['title' => 1]); 125 | $strictValidator->expectOnlyOneFromKeys(['name', 'title']); 126 | $this->assertTrue(true); 127 | } 128 | 129 | /** 130 | * @throws InvalidTypeException 131 | */ 132 | public function testInvalidStringException() 133 | { 134 | $this->expectException(InvalidTypeException::class); 135 | $strictValidator = new StrictValidation(['title' => 1]); 136 | $strictValidator->expectKeyToBeString('title'); 137 | } 138 | 139 | /** 140 | * @throws InvalidTypeException 141 | */ 142 | public function testInvalidArrayException() 143 | { 144 | $this->expectException(InvalidTypeException::class); 145 | $strictValidator = new StrictValidation(['tags' => 1]); 146 | $strictValidator->expectKeyToBeArray('tags'); 147 | } 148 | /** 149 | * @throws InvalidTypeException 150 | */ 151 | public function testInvalidBooleanException() 152 | { 153 | $this->expectException(InvalidTypeException::class); 154 | $strictValidator = new StrictValidation(['isPrivate' => 1]); 155 | $strictValidator->expectKeyToBeBoolean('isPrivate'); 156 | } 157 | 158 | /** 159 | * @throws InvalidTypeException 160 | */ 161 | public function testInvalidFloatException() 162 | { 163 | $this->expectException(InvalidTypeException::class); 164 | $strictValidator = new StrictValidation(['money' => 1]); 165 | $strictValidator->expectKeyToBeFloat('money'); 166 | } 167 | 168 | /** 169 | * @throws InvalidStructureException 170 | * @throws InvalidTypeException 171 | */ 172 | public function testWithInvalidTypeException() 173 | { 174 | $this->expectException(InvalidTypeException::class); 175 | 176 | $strictValidator = new StrictValidation($this->data1); 177 | 178 | $strictValidator 179 | ->expectAtLeastKeys(['title', 'content']) 180 | ->expectExactlyKeys(['title', 'content']) 181 | ->expectOnlyKeys(['title', 'content']) 182 | ->expectKeysToBeInteger(['title', 'content']); 183 | 184 | $this->assertTrue(true); 185 | } 186 | 187 | /** 188 | * @throws InvalidStructureException 189 | * @throws InvalidTypeException 190 | */ 191 | public function testWithInvalidStructureException() 192 | { 193 | $this->expectException(InvalidStructureException::class); 194 | 195 | $strictValidator = new StrictValidation($this->data3, 'my data'); 196 | 197 | $strictValidator 198 | ->expectAtLeastKeys(['title', 'content']) 199 | ->expectExactlyKeys(['title', 'content']) 200 | ->expectOnlyKeys(['title', 'content']) 201 | ->expectKeysToBeInteger(['title', 'content']); 202 | 203 | $this->assertTrue(true); 204 | } 205 | } -------------------------------------------------------------------------------- /tests/ValidationBuilderTest.php: -------------------------------------------------------------------------------- 1 | expectNKeys(2) 18 | ->expectAtLeastKeys(['title', 'content']) 19 | ->expectExactlyKeys(['title', 'content']) 20 | ->expectOnlyKeys(['title', 'content']) 21 | ->expectKeysToBeString(['title', 'content'], true); 22 | 23 | $data = [ 24 | 'title' => 'test', 25 | 'content' => 'test', 26 | ]; 27 | 28 | $validationPass = $validation->validate($data); 29 | $this->assertTrue($validationPass); 30 | $this->assertTrue($validation->getErrors() === []); 31 | $this->assertTrue($validation->getLastError() === null); 32 | } 33 | 34 | public function testStrictValidate() 35 | { 36 | $validation = new ValidationBuilder(); 37 | $validation 38 | ->expectNKeys(2) 39 | ->expectAtLeastKeys(['title', 'content']) 40 | ->expectExactlyKeys(['title', 'content']) 41 | ->expectOnlyKeys(['title', 'content']) 42 | ->expectKeysToBeString(['title', 'content'], true); 43 | 44 | $data = [ 45 | 'title' => 'test', 46 | 'content' => 'test', 47 | ]; 48 | 49 | $validation->strictValidate($data); 50 | $this->assertTrue(true); 51 | } 52 | 53 | public function testStrictValidateException() 54 | { 55 | $validation = new ValidationBuilder(); 56 | $validation 57 | ->expectNKeys(2) 58 | ->expectAtLeastKeys(['title', 'content']) 59 | ->expectExactlyKeys(['title', 'content']) 60 | ->expectOnlyKeys(['title', 'content']) 61 | ->expectKeysToBeString(['title', 'content'], true); 62 | 63 | $data = [ 64 | 'title' => 1, 65 | 'content' => 'test', 66 | ]; 67 | 68 | $this->expectException(ArrayValidationExceptionInterface::class); 69 | $validation->strictValidate($data); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /tests/ValidationDefinitionTest.php: -------------------------------------------------------------------------------- 1 | expectAtLeastKeys(['title', 'content']) 24 | ->expectExactlyKeys(['title', 'content']) 25 | ->expectOnlyKeys(['title', 'content']) 26 | ->expectKeysToBeString(['title', 'content'], true); 27 | 28 | $validations = $arrayDefinition->getValidations(); 29 | $this->assertTrue(is_array($validations)); 30 | $this->assertTrue(count($validations) === 4); 31 | } 32 | 33 | public function testGetDefinition2() 34 | { 35 | $arrayDefinition = new ValidationDefinition(); 36 | 37 | $arrayDefinition 38 | ->expectOnlyKeys(['title', 'content', 'description', 'id', 'number', 'amount', 'fields', 'isPrivate', 'person']) 39 | ->expectOnlyOneFromKeys(['title']) 40 | ->expectKeysToBeInteger(['id']) 41 | ->expectKeyToBeInteger('number') 42 | ->expectKeyToBeFloat('amount') 43 | ->expectKeysToBeFloat(['amount']) 44 | ->expectKeysToBeArray(['fields']) 45 | ->expectKeyToBeArray('fields') 46 | ->expectKeyToBeBoolean('isPrivate') 47 | ->expectKeysToBeBoolean(['isPrivate']) 48 | ->expectKeysToBeString(['title', 'content'], true) 49 | ->expectKeyToBeString('title', true) 50 | ->expectKeyToBeString('content', true) 51 | ->expectKeyToBeString('description', false) 52 | ->expectKeyToBeObject('person', true) 53 | ->expectKeysToBeObject(['person']); 54 | 55 | $validations = $arrayDefinition->getValidations(); 56 | 57 | $this->assertTrue(is_array($validations)); 58 | $this->assertTrue(isset($validations['expectKeyToBeString'][0][0])); 59 | $this->assertTrue($validations['expectKeyToBeString'][0][0] === 'title'); 60 | $this->assertTrue($validations['expectKeyToBeString'][0][1]); 61 | 62 | $this->assertTrue(isset($validations['expectKeyToBeString'][1][0])); 63 | $this->assertTrue($validations['expectKeyToBeString'][1][0] === 'content'); 64 | $this->assertTrue($validations['expectKeyToBeString'][1][1]); 65 | 66 | $this->assertTrue(isset($validations['expectKeyToBeString'][2][0])); 67 | $this->assertTrue($validations['expectKeyToBeString'][2][0] === 'description'); 68 | $this->assertFalse($validations['expectKeyToBeString'][2][1]); 69 | 70 | $this->assertTrue(isset($validations['expectKeyToBeObject'][0][0])); 71 | $this->assertTrue($validations['expectKeyToBeObject'][0][0] === 'person'); 72 | $this->assertTrue($validations['expectKeyToBeObject'][0][1]); 73 | } 74 | 75 | public function testStrictArrayValidatorFromDefinition() 76 | { 77 | $arrayDefinition = new ValidationDefinition(); 78 | $arrayDefinition 79 | ->expectNKeys(2) 80 | ->expectAtLeastKeys(['title', 'content']) 81 | ->expectExactlyKeys(['title', 'content']) 82 | ->expectOnlyKeys(['title', 'content']) 83 | ->expectKeysToBeString(['title', 'content'], true); 84 | 85 | $strictValidator = new StrictValidationFromDefinition($arrayDefinition, [ 86 | 'title' => '', 87 | 'content' => '', 88 | ]); 89 | 90 | $this->assertTrue(true); 91 | 92 | $this->expectException(InvalidTypeException::class); 93 | $strictValidator = new StrictValidationFromDefinition($arrayDefinition, [ 94 | 'title' => '', 95 | 'content' => 1, 96 | ]); 97 | } 98 | 99 | /** 100 | * @throws InvalidTypeException 101 | * @throws InvalidStructureException 102 | */ 103 | public function testStrictArrayValidatorFromSchema() 104 | { 105 | $schemaArray = [ 106 | 'title' => [ 107 | 'type' => 'string', 108 | 'required' => true 109 | ], 110 | 'content' => [ 111 | 'type' => 'string', 112 | 'nullable' => true, 113 | ], 114 | ]; 115 | 116 | $schema = new Schema( 117 | new SchemaCompiler(), 118 | $schemaArray, 119 | 'mySchemaName' 120 | ); 121 | 122 | $arrayToValidate = [ 123 | 'title' => '', 124 | 'content' => null, 125 | ]; 126 | 127 | // will throw an exception if any of tests failed, 128 | // this should pass 129 | new StrictValidationFromSchema($schema, $arrayToValidate); 130 | $this->assertTrue(true); 131 | 132 | // this should not pass 133 | $this->expectException(InvalidTypeException::class); 134 | new StrictValidationFromSchema($schema, [ 135 | 'title' => '', 136 | 'content' => 1, 137 | ]); 138 | 139 | } 140 | 141 | public function testJsonSerialize() 142 | { 143 | $definition = new ValidationDefinition(); 144 | $definition->expectOnlyKeys(['title', 'content']); 145 | $this->assertTrue(json_encode($definition) === '{"expectOnlyKeys":[[["title","content"]]]}'); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /tests/ValidationFromDefinitionTest.php: -------------------------------------------------------------------------------- 1 | expectAtLeastKeys(['title', 'content']) 19 | ->expectExactlyKeys(['title', 'content']) 20 | ->expectOnlyKeys(['title', 'content']) 21 | ->expectKeysToBeString(['title', 'content'], true); 22 | 23 | $data = [ 24 | 'item1' => 45.1, 25 | 'item2' => 36.5, 26 | 'item3' => [], 27 | 'item4' => null, 28 | 'item5' => 99, 29 | ]; 30 | 31 | $validation = new ValidationFromDefinition($validationDefinition, $data); 32 | 33 | $this->assertTrue($validation->hasErrors()); 34 | $this->assertTrue(count($validation->getErrors()) === 3); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/ValidationFromSchemaTest.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'type' => 'string', 19 | 'required' => true 20 | ], 21 | 'content' => [ 22 | 'type' => 'string', 23 | 'nullable' => true, 24 | ], 25 | ]; 26 | 27 | $schema = new Schema( 28 | new SchemaCompiler(), 29 | $schemaArray, 30 | 'mySchemaName' 31 | ); 32 | 33 | $arrayToValidate = [ 34 | 'title' => '', 35 | 'content' => null, 36 | ]; 37 | 38 | // this should not pass 39 | $validation = new ValidationFromSchema($schema, [ 40 | 'title' => '', 41 | 'content' => 1, 42 | ]); 43 | 44 | $this->assertTrue($validation->hasErrors()); 45 | $this->assertTrue(count($validation->getErrors()) == 1); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /tests/ValidationTest.php: -------------------------------------------------------------------------------- 1 | [], 'field2' => 'text', 'field3' => 1, 'field4'=> true, 'field5' => 1.2, 'field6' => new StdClass()], // data 20 | null, // dataName 21 | [ // validation rules 22 | 'expectOnlyKeys' => [ ['field1', 'field2', 'field3', 'field4', 'field5', 'field6'] ], 23 | 'expectExactlyKeys' => [ ['field1', 'field2', 'field3', 'field4', 'field5', 'field6'] ], 24 | 'expectKeyToBeArray' => ['field1'], 25 | 'expectKeyToBeString' => ['field2'], 26 | 'expectKeyToBeInteger' => ['field3'], 27 | 'expectKeyToBeBoolean' => ['field4'], 28 | 'expectKeyToBeFloat' => ['field5'], 29 | 'expectKeyToBeObject' => ['field6'], 30 | 31 | 'expectKeysToBeArray' => [['field1']], 32 | 'expectKeysToBeString' => [['field2']], 33 | 'expectKeysToBeInteger' => [['field3']], 34 | 'expectKeysToBeBoolean' => [['field4']], 35 | 'expectKeysToBeFloat' => [['field5']], 36 | 'expectKeysToBeObject' => [['field6']], 37 | ], 38 | false, // has error(s) 39 | 0, // number of error(s) 40 | [] // error(s) messages 41 | ], 42 | 43 | // this one will test types errors 44 | [ 45 | ['field6' => [], 'field5' => 'text', 'field4' => 1, 'field3'=> true, 'field2' => 1.2, 'field1' => new StdClass()], // data 46 | 'myValidation', // dataName 47 | [ // validation rules 48 | 'expectKeyToBeArray' => ['field1'], 49 | 'expectKeyToBeString' => ['field2'], 50 | 'expectKeyToBeInteger' => ['field3'], 51 | 'expectKeyToBeBoolean' => ['field4'], 52 | 'expectKeyToBeFloat' => ['field5'], 53 | 'expectKeyToBeObject' => ['field6'], 54 | ], 55 | true, // has error(s) 56 | 6, // number of error(s) 57 | [ 58 | '[myValidation] invalid type for key [field1], type array is expected', 59 | '[myValidation] invalid type for key [field2], type string is expected', 60 | '[myValidation] invalid type for key [field3], type integer is expected', 61 | '[myValidation] invalid type for key [field4], type boolean is expected', 62 | '[myValidation] invalid type for key [field5], type float is expected', 63 | '[myValidation] invalid type for key [field6], type object is expected', 64 | ] // error(s) messages 65 | ], 66 | 67 | //this one will tests structure errors 68 | [ 69 | ['field6' => 'im here!', 'field7' => 'foo'], // data 70 | null, // dataName 71 | [ // validation rules 72 | 'expectOnlyKeys' => [ ['field1', 'field2', 'field3', 'field4', 'field5', 'field6'] ], 73 | 'expectExactlyKeys' => [ ['field1', 'field2', 'field3', 'field4', 'field5', 'field6'] ], 74 | 'expectAtLeastKeys' => [ ['field1'] ], 75 | 'expectOnlyOneFromKeys' => [ ['field1'] ], 76 | 'expectNKeys' => [1] 77 | ], 78 | true, // has error(s) 79 | 5, // number of error(s) 80 | [ 81 | 'invalid data, expected only keys [field1, field2, field3, field4, field5, field6], received [field6, field7]', 82 | 'invalid data, expected exactly keys [field1, field2, field3, field4, field5, field6], received [field6, field7]', 83 | 'invalid data, expected at least keys [field1], received [field6, field7]', 84 | 'invalid data, expected only one of keys [field1], received [field6, field7]', 85 | 'invalid data, expected 1 element, received 2 elements' 86 | ] // error(s) messages 87 | ], 88 | ]; 89 | } 90 | 91 | /** 92 | * @dataProvider dataProvider 93 | * @param array $data 94 | * @param string|null $dataName 95 | * @param array $validationMethods 96 | * @param bool $hasErrors 97 | * @param int $errorsCount 98 | * @param array $errorsMsg 99 | */ 100 | public function testScenarios(array $data, ?string $dataName, array $validationMethods, bool $hasErrors, int $errorsCount, array $errorsMsg) 101 | { 102 | $validation = new Validation($data, $dataName); 103 | 104 | foreach ($validationMethods as $methodName => $methodArgs) { 105 | call_user_func_array([$validation, $methodName], $methodArgs); 106 | } 107 | 108 | $this->assertTrue($validation->hasErrors() === $hasErrors); 109 | $this->assertTrue(count($validation->getErrors()) === $errorsCount); 110 | $this->assertTrue($validation->getErrors() === $errorsMsg); 111 | 112 | if ($errorsCount > 0) { 113 | $errors = $validation->getErrors(); 114 | $this->assertTrue($validation->getLastError() === $errors[array_key_last($errors)]); 115 | } else { 116 | $this->assertTrue($validation->getLastError() === null); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/ValidatorTest.php: -------------------------------------------------------------------------------- 1 | 'foo', 16 | 'content' => 'foobar', 17 | ]; 18 | 19 | private $data2 = [ 20 | 'title' => 'foo' 21 | ]; 22 | 23 | private $data3 = [ 24 | 'title' => null, 25 | 'views' => 45, 26 | 'comments' => [] 27 | ]; 28 | 29 | public function testExpectExactlyKeys() 30 | { 31 | $validation = new Validator(); 32 | $this->assertTrue($validation->expectExactlyKeys($this->data1, ['title', 'content'])); 33 | $this->assertFalse($validation->expectExactlyKeys($this->data1, ['title', 'content', 'extra'])); 34 | $this->assertFalse($validation->expectExactlyKeys($this->data1, ['title'])); 35 | $this->assertFalse($validation->expectExactlyKeys($this->data1, ['extra'])); 36 | $this->assertFalse($validation->expectExactlyKeys($this->data1, [])); 37 | } 38 | 39 | public function testExpectOnlyOneFromKeys() 40 | { 41 | $validation = new Validator(); 42 | $this->assertTrue($validation->expectOnlyOneFromKeys($this->data2, ['title', 'extra'])); 43 | $this->assertTrue($validation->expectOnlyOneFromKeys($this->data2, ['title'])); 44 | $this->assertFalse($validation->expectOnlyOneFromKeys($this->data2, ['extra'])); 45 | } 46 | 47 | public function testExpectAtLeastKeys() 48 | { 49 | $validation = new Validator(); 50 | $this->assertTrue($validation->expectAtLeastKeys($this->data1, ['title'])); 51 | $this->assertTrue($validation->expectAtLeastKeys($this->data1, ['content'])); 52 | $this->assertTrue($validation->expectAtLeastKeys($this->data1, ['title', 'content'])); 53 | $this->assertFalse($validation->expectAtLeastKeys($this->data1, ['extra'])); 54 | $this->assertFalse($validation->expectAtLeastKeys($this->data1, ['title', 'content', 'extra'])); 55 | } 56 | 57 | public function testExpectOnlyKeys() 58 | { 59 | $validation = new Validator(); 60 | $this->assertTrue($validation->expectOnlyKeys($this->data1, ['title', 'content'])); 61 | $this->assertTrue($validation->expectOnlyKeys($this->data1, ['title', 'content', 'extra'])); 62 | $this->assertFalse($validation->expectOnlyKeys($this->data1, ['title'])); 63 | } 64 | 65 | public function testExpectNElement() 66 | { 67 | $validation = new Validator(); 68 | $this->assertTrue($validation->expectNKeys($this->data1, 2)); 69 | $this->assertFalse($validation->expectNKeys($this->data1, 1)); 70 | } 71 | 72 | public function testIsArray() 73 | { 74 | $validation = new Validator(); 75 | $this->assertTrue($validation->expectKeyToBeArray($this->data3, 'comments', false)); 76 | $this->assertFalse($validation->expectKeyToBeArray($this->data3, 'title', false)); 77 | $this->assertTrue($validation->expectKeyToBeArray($this->data3, 'title', true)); 78 | 79 | $data = [ 80 | 'item1' => 45, 81 | 'item2' => [], 82 | 'item3' => [], 83 | 'item4' => null, 84 | ]; 85 | $this->assertTrue($validation->expectKeysToBeArray($data, ['item2'], false)); 86 | $this->assertTrue($validation->expectKeysToBeArray($data, ['item2', 'item3'], false)); 87 | $this->assertFalse($validation->expectKeysToBeArray($data, ['item2', 'item3', 'item4'], false)); 88 | $this->assertTrue($validation->expectKeysToBeArray($data, ['item2', 'item3', 'item4'], true)); 89 | } 90 | 91 | public function testIsInt() 92 | { 93 | $data = [ 94 | 'item1' => 45, 95 | 'item2' => 36, 96 | 'item3' => [], 97 | 'item4' => null, 98 | 'item5' => '', 99 | ]; 100 | $validation = new Validator(); 101 | $this->assertTrue($validation->expectKeyToBeInteger($data, 'item1', false)); 102 | $this->assertFalse($validation->expectKeyToBeInteger($data, 'item3', false)); 103 | $this->assertFalse($validation->expectKeyToBeInteger($data, 'item4', false)); 104 | $this->assertTrue($validation->expectKeyToBeInteger($data, 'item4', true)); 105 | 106 | 107 | $this->assertTrue($validation->expectKeysToBeInteger($data, ['item1', 'item2'], false)); 108 | $this->assertFalse($validation->expectKeysToBeInteger($data, ['item1', 'item2', 'item4'], false)); 109 | $this->assertTrue($validation->expectKeysToBeInteger($data, ['item1', 'item2', 'item4'], true)); 110 | $this->assertFalse($validation->expectKeysToBeInteger($data, ['item1', 'item2', 'item3', 'item4'], true)); 111 | } 112 | 113 | public function testIsFloat() 114 | { 115 | $data = [ 116 | 'item1' => 45.1, 117 | 'item2' => 36.5, 118 | 'item3' => [], 119 | 'item4' => null, 120 | 'item5' => 99, 121 | ]; 122 | $validation = new Validator(); 123 | $this->assertTrue($validation->expectKeyToBeFloat($data, 'item1', false)); 124 | $this->assertFalse($validation->expectKeyToBeFloat($data, 'item3', false)); 125 | $this->assertFalse($validation->expectKeyToBeFloat($data, 'item4', false)); 126 | $this->assertTrue($validation->expectKeyToBeFloat($data, 'item4', true)); 127 | 128 | 129 | $this->assertTrue($validation->expectKeysToBeFloat($data, ['item1', 'item2'], false)); 130 | $this->assertFalse($validation->expectKeysToBeFloat($data, ['item1', 'item2', 'item4'], false)); 131 | $this->assertTrue($validation->expectKeysToBeFloat($data, ['item1', 'item2', 'item4'], true)); 132 | $this->assertFalse($validation->expectKeysToBeFloat($data, ['item1', 'item2', 'item3', 'item4'], true)); 133 | $this->assertFalse($validation->expectKeysToBeFloat($data, ['item1', 'item2', 'item5'], false)); 134 | } 135 | 136 | public function testIsBool() 137 | { 138 | $data = [ 139 | 'item1' => true, 140 | 'item2' => false, 141 | 'item3' => [], 142 | 'item4' => null, 143 | 'item5' => 1, 144 | ]; 145 | $validation = new Validator(); 146 | $this->assertTrue($validation->expectKeyToBeBoolean($data, 'item1', false)); 147 | $this->assertFalse($validation->expectKeyToBeBoolean($data, 'item3', false)); 148 | $this->assertFalse($validation->expectKeyToBeBoolean($data, 'item5', false)); 149 | $this->assertFalse($validation->expectKeyToBeBoolean($data, 'item4', false)); 150 | $this->assertTrue($validation->expectKeyToBeBoolean($data, 'item4', true)); 151 | 152 | 153 | $this->assertTrue($validation->expectKeysToBeBoolean($data, ['item1', 'item2'], false)); 154 | $this->assertFalse($validation->expectKeysToBeBoolean($data, ['item1', 'item2', 'item4'], false)); 155 | $this->assertTrue($validation->expectKeysToBeBoolean($data, ['item1', 'item2', 'item4'], true)); 156 | $this->assertFalse($validation->expectKeysToBeBoolean($data, ['item1', 'item2', 'item3', 'item4'], true)); 157 | } 158 | 159 | public function testIsString() 160 | { 161 | $data = [ 162 | 'item1' => 'string', 163 | 'item2' => 'string', 164 | 'item3' => [], 165 | 'item4' => null, 166 | 'item5' => 2, 167 | ]; 168 | $validation = new Validator(); 169 | $this->assertTrue($validation->expectKeyToBeString($data, 'item1', false)); 170 | $this->assertFalse($validation->expectKeyToBeString($data, 'item3', false)); 171 | $this->assertFalse($validation->expectKeyToBeString($data, 'item4', false)); 172 | $this->assertTrue($validation->expectKeyToBeString($data, 'item4', true)); 173 | 174 | 175 | $this->assertTrue($validation->expectKeysToBeString($data, ['item1', 'item2'], false)); 176 | $this->assertFalse($validation->expectKeysToBeString($data, ['item1', 'item2', 'item4'], false)); 177 | $this->assertTrue($validation->expectKeysToBeString($data, ['item1', 'item2', 'item4'], true)); 178 | $this->assertFalse($validation->expectKeysToBeString($data, ['item1', 'item2', 'item3', 'item4'], true)); 179 | } 180 | 181 | public function testIsObject() 182 | { 183 | $data = [ 184 | 'item1' => new stdClass(), 185 | 'item2' => new DateTime(), 186 | 'item3' => null, 187 | ]; 188 | $validation = new Validator(); 189 | $this->assertTrue($validation->expectKeyToBeObject($data, 'item1', false)); 190 | $this->assertFalse($validation->expectKeyToBeObject($data, 'item3', false)); 191 | $this->assertTrue($validation->expectKeyToBeObject($data, 'item3', true)); 192 | $this->assertTrue($validation->expectKeysToBeObject($data, ['item1', 'item2'], false)); 193 | $this->assertFalse($validation->expectKeysToBeObject($data, ['item1', 'item2', 'item3'], false)); 194 | $this->assertTrue($validation->expectKeysToBeObject($data, ['item1', 'item2', 'item3'], true)); 195 | } 196 | } 197 | --------------------------------------------------------------------------------