├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Concerns │ ├── MessagesAttributes.php │ └── ValidatesAttributes.php ├── Exceptions │ └── ValidationException.php ├── Validator.php └── messages │ └── en.php └── tests └── ValidatorTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vendor 3 | composer.lock 4 | .buildpath 5 | .settings 6 | .project 7 | bin 8 | /nbproject/* 9 | *.iml 10 | .idea 11 | .php_cs.cache -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: 3 | - 'src/*' 4 | excluded_paths: 5 | - 'tests/*' 6 | dependency_paths: 7 | - 'vendor/' 8 | 9 | 10 | build: 11 | environment: 12 | php: 13 | version: '7.1' 14 | 15 | checks: 16 | php: 17 | remove_extra_empty_lines: true 18 | remove_php_closing_tag: true 19 | remove_trailing_whitespace: true 20 | fix_use_statements: 21 | remove_unused: true 22 | preserve_multiple: false 23 | preserve_blanklines: true 24 | order_alphabetically: true 25 | fix_php_opening_tag: true 26 | fix_linefeed: true 27 | fix_line_ending: true 28 | fix_identation_4spaces: true 29 | fix_doc_comments: true 30 | 31 | tools: 32 | external_code_coverage: 33 | timeout: 600 34 | runs: 1 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '7.1' 5 | - '7.2' 6 | 7 | 8 | 9 | install: composer install 10 | 11 | script: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover 12 | 13 | after_script: 14 | - wget https://scrutinizer-ci.com/ocular.phar 15 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog For runner/validator 2 | 3 | ## [1.0.0] - 2018-12-25 4 | 5 | ### Added 6 | - 增加可引入自定义语言包 7 | - 增加自定义错误消息 8 | 9 | ### Changed 10 | - 拆分 validate 及消息处理为 trait 11 | - extend 的 callback 类作用域取消绑定到 Validator 示例. validate 函数参数增加传入 Validator 实例 12 | - validate 从 protected 改为 publish 13 | 14 | ## [v1.0.1] - 2019-03-04 15 | ### Added 16 | - 增加支持通过魔术方法调用扩展规则 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Validator

2 | 3 |

Lightweight Validation Like Laravel

4 | 5 |

6 | 7 | 8 | 9 | StyleCI 10 | 11 | 12 | 13 |

14 | 15 | ## 使用 16 | ```php 17 | 'https://github.com/RunnerLee', 31 | ]; 32 | $rule = [ 33 | 'blog' => 'required|url', 34 | ]; 35 | $validator = new Validator($data, $rule); 36 | 37 | var_dump($validator->validate()); // output: true 38 | 39 | // 获取错误消息 40 | $validator->messages(); 41 | ``` 42 | 43 | ## 内置验证规则 44 | * `accept`:字段的取值范围必须是:yes、on、'1'、1、true 中的一个 45 | * `numeric`:字段的值必须是数字(包括整形和浮点数) 46 | * `integer`:字段的值必须是整形 47 | * `float`:字段的值必须是浮点型 48 | * `size`:字段的值必须为指定长度 49 | * `url`:字段的值必须是合法的 url 类型 50 | * `boolean`:字段的值必须是布尔类型 51 | * `confirm`:字段的值必须与指定值相等 52 | * `date`:字段的值必须是一个合法的日期 53 | * `email`:字段的值必须是一个合法的 email 54 | * `required`:必须包含该字段 55 | * `requiredWith`:如果指定的字段中的任意一个有值且不为空,则此字段为必填 56 | * `requiredWithout`:如果缺少任意一个指定的字段,则此字段为必填 57 | * `requiredIf`:如果指定的其它字段(anotherfield)等于任何一个 value 时,此字段为必填 58 | * `array`:字段的值必须是数组类型 59 | * `string`:字段的值必须是字符串类型 60 | * `min`:字段的值必须大于等于指定值 61 | * `max`:字段的值必须小于等于指定值 62 | * `range`:字段的值长度必须指定范围内,包含 min 和 max。 63 | * `regex`:字段的值必须匹配指定的正则表达式 64 | * `in`:字段的值必须在指定的数组内 65 | * `ip`:字段的值必须是一个合法的 ip 66 | * `dateFormat`:字段的值必须是一个合法的 date format 格式。参考:http://php.net/manual/en/datetime.createfromformat.php 67 | * `dateBefore`:字段的值必须小于给定时间。给定时间值非时间戳格式,而是 date/time 字符串,如:10 September 2000 68 | * `dateAfter`:字段的值必须大于给定时间。时间值格式同上。 69 | * `json`:字段的值必须是一个合法的 JSON 格式 70 | 71 | ## Note 72 | 73 | #### 关于空字符串 74 | 如果传入一个数组: 75 | 76 | ```php 77 | $data = [ 78 | 'foo' => '', 79 | ]; 80 | ``` 81 | 82 | 同时规则设置为: 83 | ```php 84 | $rules= [ 85 | 'foo' => 'string', 86 | ]; 87 | ``` 88 | 89 | 此时校验结果会是通过的. 也就是说 `validator` 不会把 `''` 当作 `null` 处理. 90 | 91 | 92 | ## 参考 93 | [https://github.com/vlucas/valitron](https://github.com/vlucas/valitron) 94 | 95 | [https://github.com/illuminate/validation](https://github.com/illuminate/validation) 96 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "runner/validator", 3 | "license": "MIT", 4 | "description": "", 5 | "authors": [ 6 | { 7 | "name": "runnerlee", 8 | "email": "runnerleer@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.6", 13 | "ext-mbstring": "*" 14 | }, 15 | "require-dev": { 16 | "phpunit/phpunit": "^5.0", 17 | "phpstan/phpstan": "^0.10.6" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "Runner\\Validator\\": "src/" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | src 21 | 22 | src/Exceptions 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Concerns/MessagesAttributes.php: -------------------------------------------------------------------------------- 1 | templates = require $file; 19 | $this->templates = array_merge($this->templates, self::$extensionTemplates); 20 | 21 | foreach ($customMessage as $rule => $template) { 22 | $this->templates[self::formatRuleName($rule)] = $template; 23 | } 24 | } 25 | 26 | /** 27 | * @param string $rule 28 | * @param string $field 29 | * @param array $parameters 30 | * 31 | * @return string 32 | */ 33 | protected function buildMessage($rule, $field, array $parameters = []) 34 | { 35 | if (!isset($this->templates[$rule])) { 36 | return "{$field} field check failed"; 37 | } 38 | array_unshift($parameters, "{$field} {$this->templates[$rule]}"); 39 | 40 | try { 41 | return sprintf(...$parameters); 42 | } catch (Exception $e) { 43 | return "{$field} filed check failed"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Concerns/ValidatesAttributes.php: -------------------------------------------------------------------------------- 1 | getSize($field, $value) === $size; 80 | } 81 | 82 | /** 83 | * @param $field 84 | * @param $value 85 | * @param array $parameters 86 | * @param Validator $validator 87 | * 88 | * @return bool 89 | */ 90 | public function validateUrl($field, $value, array $parameters, Validator $validator) 91 | { 92 | return false !== filter_var($value, FILTER_VALIDATE_URL); 93 | } 94 | 95 | /** 96 | * @param $field 97 | * @param $value 98 | * @param array $parameters 99 | * @param Validator $validator 100 | * 101 | * @return bool 102 | */ 103 | public function validateBoolean($field, $value, array $parameters, Validator $validator) 104 | { 105 | return in_array($value, [true, false, 0, 1, '0', '1'], true); 106 | } 107 | 108 | /** 109 | * @param $field 110 | * @param $value 111 | * @param array $parameters 112 | * @param Validator $validator 113 | * 114 | * @return bool 115 | */ 116 | public function validateConfirm($field, $value, array $parameters, Validator $validator) 117 | { 118 | return $value === $this->data[$parameters[0]]; 119 | } 120 | 121 | /** 122 | * @param $field 123 | * @param $value 124 | * @param array $parameters 125 | * @param Validator $validator 126 | * 127 | * @return bool 128 | */ 129 | public function validateDate($field, $value, array $parameters, Validator $validator) 130 | { 131 | return false !== strtotime($value); 132 | } 133 | 134 | /** 135 | * 邮箱地址 136 | * 137 | * @param $field 138 | * @param $value 139 | * @param array $parameters 140 | * @param Validator $validator 141 | * 142 | * @return bool 143 | */ 144 | public function validateEmail($field, $value, array $parameters, Validator $validator) 145 | { 146 | return false !== filter_var($value, FILTER_VALIDATE_EMAIL); 147 | } 148 | 149 | /** 150 | * @param $field 151 | * @param $value 152 | * @param array $parameters 153 | * @param Validator $validator 154 | * 155 | * @return bool 156 | */ 157 | public function validateRequired($field, $value, array $parameters, Validator $validator) 158 | { 159 | return !is_null($value); 160 | } 161 | 162 | /** 163 | * @param $field 164 | * @param $value 165 | * @param array $parameters 166 | * @param Validator $validator 167 | * 168 | * @return bool 169 | */ 170 | public function validateRequiredWith($field, $value, array $parameters, Validator $validator) 171 | { 172 | return !is_null($value) || !array_key_exists($parameters[0], $this->data); 173 | } 174 | 175 | /** 176 | * @param $field 177 | * @param $value 178 | * @param array $parameters 179 | * @param Validator $validator 180 | * 181 | * @return bool 182 | */ 183 | public function validateRequiredWithout($field, $value, array $parameters, Validator $validator) 184 | { 185 | return !is_null($value) || array_key_exists($parameters[0], $this->data); 186 | } 187 | 188 | /** 189 | * @param $field 190 | * @param $value 191 | * @param array $parameters 192 | * @param Validator $validator 193 | * 194 | * @return bool 195 | */ 196 | public function validateRequiredIf($field, $value, array $parameters, Validator $validator) 197 | { 198 | $otherField = array_shift($parameters); 199 | 200 | return !is_null($value) || ( 201 | !array_key_exists($otherField, $this->data) || false === array_search($this->data[$otherField], $parameters) 202 | ); 203 | } 204 | 205 | /** 206 | * @param $field 207 | * @param $value 208 | * @param array $parameters 209 | * @param Validator $validator 210 | * 211 | * @return bool 212 | */ 213 | public function validateRequiredUnless($field, $value, array $parameters, Validator $validator) 214 | { 215 | $otherField = array_shift($parameters); 216 | 217 | return !is_null($value) || ( 218 | !array_key_exists($otherField, $this->data) || false !== array_search($this->data[$otherField], $parameters) 219 | ); 220 | } 221 | 222 | /** 223 | * @param $field 224 | * @param $value 225 | * @param array $parameters 226 | * 227 | * @return bool 228 | */ 229 | public function validateArray($field, $value, array $parameters, Validator $validator) 230 | { 231 | return is_array($value); 232 | } 233 | 234 | /** 235 | * @param $field 236 | * @param $value 237 | * @param array $parameters 238 | * @param Validator $validator 239 | * 240 | * @return bool 241 | */ 242 | public function validateString($field, $value, array $parameters, Validator $validator) 243 | { 244 | return is_string($value); 245 | } 246 | 247 | /** 248 | * @param $field 249 | * @param $value 250 | * @param array $parameters 251 | * @param Validator $validator 252 | * 253 | * @return bool 254 | */ 255 | public function validateNullable($field, $value, array $parameters, Validator $validator) 256 | { 257 | return true; 258 | } 259 | 260 | /** 261 | * @param $field 262 | * @param $value 263 | * @param array $parameters 264 | * @param Validator $validator 265 | * 266 | * @return bool 267 | */ 268 | public function validateMin($field, $value, array $parameters, Validator $validator) 269 | { 270 | return $this->getSize($field, $value) >= $parameters[0]; 271 | } 272 | 273 | /** 274 | * @param $field 275 | * @param $value 276 | * @param array $parameters 277 | * @param Validator $validator 278 | * 279 | * @return bool 280 | */ 281 | public function validateMax($field, $value, array $parameters, Validator $validator) 282 | { 283 | return $this->getSize($field, $value) <= $parameters[0]; 284 | } 285 | 286 | /** 287 | * @param $field 288 | * @param $value 289 | * @param array $parameters 290 | * @param Validator $validator 291 | * 292 | * @return bool 293 | */ 294 | public function validateRange($field, $value, array $parameters, Validator $validator) 295 | { 296 | $size = $this->getSize($field, $value); 297 | if (!isset($parameters[0])) { 298 | return false; 299 | } 300 | if (isset($parameters[1])) { 301 | if ('' === $parameters[0]) { 302 | if ('' === $parameters[1]) { 303 | return false; 304 | } 305 | 306 | return $size <= $parameters[1]; 307 | } 308 | if ('' === $parameters[1]) { 309 | return $size >= $parameters[0]; 310 | } 311 | 312 | return $size >= $parameters[0] && $size <= $parameters[1]; 313 | } 314 | 315 | return '' === $parameters[0] ? false : ($size >= $parameters[0]); 316 | } 317 | 318 | /** 319 | * @param $field 320 | * @param $value 321 | * @param array $parameters 322 | * @param Validator $validator 323 | * 324 | * @return bool 325 | */ 326 | public function validateRegex($field, $value, array $parameters, Validator $validator) 327 | { 328 | return (bool) preg_match($parameters[0], $value); 329 | } 330 | 331 | /** 332 | * @param $field 333 | * @param $value 334 | * @param array $parameters 335 | * @param Validator $validator 336 | * 337 | * @return bool 338 | */ 339 | public function validateIn($field, $value, array $parameters, Validator $validator) 340 | { 341 | return in_array($value, $parameters, true); 342 | } 343 | 344 | /** 345 | * @param $field 346 | * @param $value 347 | * @param array $parameters 348 | * @param Validator $validator 349 | * 350 | * @return bool 351 | */ 352 | public function validateIp($field, $value, array $parameters, Validator $validator) 353 | { 354 | return false !== filter_var($value, FILTER_VALIDATE_IP); 355 | } 356 | 357 | /** 358 | * @param $field 359 | * @param $value 360 | * @param array $parameters 361 | * @param Validator $validator 362 | * 363 | * @return bool 364 | */ 365 | public function validateDateFormat($field, $value, array $parameters, Validator $validator) 366 | { 367 | return !(bool) date_parse_from_format($parameters[0], $value)['error_count']; 368 | } 369 | 370 | /** 371 | * @param $field 372 | * @param $value 373 | * @param array $parameters 374 | * @param Validator $validator 375 | * 376 | * @return bool 377 | */ 378 | public function validateDateBefore($field, $value, array $parameters, Validator $validator) 379 | { 380 | return strtotime($value) < strtotime($parameters[0]); 381 | } 382 | 383 | /** 384 | * @param $field 385 | * @param $value 386 | * @param array $parameters 387 | * @param Validator $validator 388 | * 389 | * @return bool 390 | */ 391 | public function validateDateAfter($field, $value, array $parameters, Validator $validator) 392 | { 393 | return strtotime($value) > strtotime($parameters[0]); 394 | } 395 | 396 | /** 397 | * @param $field 398 | * @param $value 399 | * @param array $parameters 400 | * @param Validator $validator 401 | * 402 | * @return bool 403 | */ 404 | public function validateJson($field, $value, array $parameters, Validator $validator) 405 | { 406 | return is_array(json_decode($value, true)); 407 | } 408 | 409 | /** 410 | * @param $field 411 | * @param $value 412 | * @param array $parameters 413 | * @param Validator $validator 414 | * 415 | * @return bool 416 | */ 417 | public function validateDiff($field, $value, array $parameters, Validator $validator) 418 | { 419 | $specifyField = array_shift($parameters); 420 | 421 | return array_key_exists($specifyField, $this->data) && $value !== $this->data[$specifyField]; 422 | } 423 | 424 | /** 425 | * @param $field 426 | * @param $value 427 | * 428 | * @return int|float 429 | */ 430 | public function getSize($field, $value) 431 | { 432 | switch (true) { 433 | case isset($this->ruleGroups[$field]['String']) && is_string($value): 434 | return strlen($value); 435 | case is_array($value): 436 | return count($value); 437 | case false !== $temp = filter_var($value, FILTER_VALIDATE_INT): 438 | return $temp; 439 | case false !== $temp = filter_var($value, FILTER_VALIDATE_FLOAT): 440 | return $temp; 441 | default: 442 | return mb_strlen($value); 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /src/Exceptions/ValidationException.php: -------------------------------------------------------------------------------- 1 | data = $data; 62 | $this->parseRules($rules); 63 | $this->loadMessageTemplate($file, $customMessages); 64 | } 65 | 66 | /** 67 | * @param $name 68 | * @param $callback 69 | * @param bool $isForce 70 | * @param string $message 71 | */ 72 | public static function addExtension($name, $callback, $isForce = false, $message = null) 73 | { 74 | $name = self::formatRuleName($name); 75 | 76 | self::$extensions[$name] = $callback; 77 | 78 | $isForce && self::$forceRules[] = $name; 79 | 80 | !empty($message) && (static::$extensionTemplates[$name] = $message); 81 | } 82 | 83 | /** 84 | * @return bool 85 | */ 86 | public function validate() 87 | { 88 | foreach ($this->ruleGroups as $field => $rules) { 89 | if ($this->hasField($field)) { 90 | $value = $this->getField($field); 91 | foreach ($rules as $rule => $parameters) { 92 | if (!$this->runValidateRule($rule, $field, $value, $parameters)) { 93 | $this->messages[$field][$rule] = $this->buildMessage($rule, $field, $parameters); 94 | } 95 | } 96 | } elseif ($forceRules = array_intersect(self::$forceRules, array_keys($rules))) { 97 | foreach ($forceRules as $rule) { 98 | if (!$this->runValidateRule($rule, $field, null, $rules[$rule])) { 99 | $this->messages[$field][$rule] = $this->buildMessage($rule, $field, $rules[$rule]); 100 | } 101 | } 102 | } 103 | } 104 | 105 | return 0 === count($this->messages); 106 | } 107 | 108 | /** 109 | * @return array 110 | */ 111 | public function fails() 112 | { 113 | return array_keys($this->messages); 114 | } 115 | 116 | /** 117 | * @return array 118 | */ 119 | public function messages() 120 | { 121 | return $this->messages; 122 | } 123 | 124 | /** 125 | * @return array 126 | */ 127 | public function data() 128 | { 129 | return $this->data; 130 | } 131 | 132 | /** 133 | * @param array $ruleGroups 134 | */ 135 | protected function parseRules(array $ruleGroups) 136 | { 137 | $map = []; 138 | foreach ($ruleGroups as $field => $rules) { 139 | foreach (explode('|', $rules) as $rule) { 140 | list($rule, $parameters) = explode(':', (false === strpos($rule, ':') ? ($rule.':') : $rule), 2); 141 | !isset($map[$rule]) && $map[$rule] = self::formatRuleName($rule); 142 | $rule = $map[$rule]; 143 | $this->ruleGroups[$field][$rule] = ('' === $parameters ? [] : explode(',', $parameters)); 144 | } 145 | } 146 | } 147 | 148 | /** 149 | * @param $name 150 | * 151 | * @return string 152 | */ 153 | protected static function formatRuleName($name) 154 | { 155 | return implode( 156 | '', 157 | array_map( 158 | function ($value) { 159 | return ucfirst($value); 160 | }, 161 | explode('_', $name) 162 | ) 163 | ); 164 | } 165 | 166 | /** 167 | * @param string $field 168 | * 169 | * @return bool 170 | */ 171 | protected function hasField($field) 172 | { 173 | $field = explode('.', $field); 174 | $item = array_shift($field); 175 | if (!array_key_exists($item, $this->data)) { 176 | return false; 177 | } 178 | $value = $this->data[$item]; 179 | 180 | foreach ($field as $item) { 181 | if (!array_key_exists($item, $value)) { 182 | return false; 183 | } 184 | $value = $value[$item]; 185 | } 186 | 187 | return true; 188 | } 189 | 190 | /** 191 | * @param string $field 192 | * 193 | * @return mixed 194 | */ 195 | protected function getField($field) 196 | { 197 | $field = explode('.', $field); 198 | $item = array_shift($field); 199 | $value = $this->data[$item]; 200 | foreach ($field as $item) { 201 | $value = $value[$item]; 202 | } 203 | 204 | return $value; 205 | } 206 | 207 | /** 208 | * @param $field 209 | * @param $value 210 | * @param $rule 211 | * @param array $parameters 212 | * 213 | * @return bool 214 | */ 215 | protected function runValidateRule($rule, $field, $value, array $parameters = []) 216 | { 217 | $callback = array_key_exists($rule, self::$extensions) ? self::$extensions[$rule] : [$this, "validate{$rule}"]; 218 | 219 | return (bool) call_user_func($callback, $field, $value, $parameters, $this); 220 | } 221 | 222 | public function __call($method, $arguments) 223 | { 224 | $rule = self::formatRuleName(substr($method, 8)); 225 | 226 | if (!isset(self::$extensions[$rule])) { 227 | throw new BadMethodCallException(sprintf('Method %s::%s does not exists', static::class, $method)); 228 | } 229 | 230 | return $this->runValidateRule($rule, ...$arguments); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/messages/en.php: -------------------------------------------------------------------------------- 1 | 'is required', 10 | 'Accepted' => 'must be accepted', 11 | 'Numeric' => 'must be numeric', 12 | 'Integer' => 'must be an integer', 13 | 'Float' => 'must be a float', 14 | 'Size' => "'s size must be %s", 15 | 'Min' => 'must be at least %d', 16 | 'Max' => 'must be no more than %d', 17 | 'In' => 'contains invalid value', 18 | 'Ip' => 'is not a valid IP address', 19 | 'Email' => 'is not a valid email address', 20 | 'Url' => 'is not a valid URL', 21 | 'Regex' => 'contains invalid characters', 22 | 'Date' => 'is not a valid date', 23 | 'DateFormat' => "must be date with format '%s'", 24 | 'Boolean' => 'must be a boolean', 25 | 'Range' => 'must be between %d and %d characters', 26 | 'Confirm' => 'must be same as %s field', 27 | 'Array' => 'must be an array', 28 | 'String' => 'must be a string', 29 | 'Json' => 'must be a json string', 30 | ]; 31 | -------------------------------------------------------------------------------- /tests/ValidatorTest.php: -------------------------------------------------------------------------------- 1 | assertArrayHasKey($field, $validator->data()); 15 | 16 | return false !== array_search($value, ['google', 'bing']); 17 | }); 18 | 19 | $validator = new Validator($this->getData(), $this->getRules()); 20 | 21 | $this->assertSame(true, $validator->validate()); 22 | $this->assertSame($this->getData(), $validator->data()); 23 | 24 | $data = [ 25 | 'range_a' => '1.4', 26 | 'range_b' => '1.4', 27 | 'channel_range' => 'baidu', 28 | ]; 29 | 30 | $validator = new Validator( 31 | $data, 32 | [ 33 | 'do_not_has_field' => 'required|size:1', 34 | 'range_a' => 'range', 35 | 'range_b' => 'range:,', 36 | 'channel_range' => 'channel_range', 37 | ] 38 | ); 39 | 40 | $this->assertSame(false, $validator->validate()); 41 | $this->assertSame($data, $validator->data()); 42 | $this->assertSame([ 43 | 'do_not_has_field', 44 | 'range_a', 45 | 'range_b', 46 | 'channel_range', 47 | ], $validator->fails()); 48 | } 49 | 50 | public function testMessage() 51 | { 52 | $data = [ 53 | 'data' => 'demo', 54 | ]; 55 | $rules = [ 56 | 'data' => 'size:3', 57 | ]; 58 | $validator = new Validator($data, $rules); 59 | 60 | $this->assertSame(false, $validator->validate()); 61 | $this->assertSame("data 's size must be 3", $validator->messages()['data']['Size']); 62 | 63 | Validator::addExtension( 64 | 'testing', 65 | function () { 66 | return false; 67 | }, 68 | false, 69 | 'is testing' 70 | ); 71 | 72 | $validator = new Validator( 73 | [ 74 | 'a' => 'b', 75 | ], 76 | [ 77 | 'a' => 'testing', 78 | ] 79 | ); 80 | 81 | $this->assertSame(false, $validator->validate()); 82 | $this->assertSame( 83 | [ 84 | 'a' => [ 85 | 'Testing' => 'a is testing', 86 | ], 87 | ], 88 | $validator->messages() 89 | ); 90 | } 91 | 92 | public function testAddExtension() 93 | { 94 | Validator::addExtension('runner', function () { 95 | return true; 96 | }); 97 | 98 | $data = [ 99 | 'a' => 'string', 100 | ]; 101 | 102 | $validator = new Validator($data, [ 103 | 'a' => 'runner' 104 | ]); 105 | 106 | $this->assertSame(true, $validator->validate()); 107 | 108 | $this->assertSame(true, $validator->validateRunner('a', 'a', [])); 109 | 110 | $validator = new Validator($data, [ 111 | 'a' => 'demo', 112 | ]); 113 | 114 | $this->expectException(BadMethodCallException::class); 115 | $validator->validate(); 116 | } 117 | 118 | public function testReplaceMessage() 119 | { 120 | $validator = new Validator( 121 | [ 122 | 'runnerlee' => 'hhh', 123 | ], 124 | [ 125 | 'runnerlee' => 'integer', 126 | ], 127 | [ 128 | 'integer' => 'is the most handsome man', 129 | ] 130 | ); 131 | $validator->validate(); 132 | 133 | $this->assertSame( 134 | [ 135 | 'runnerlee' => [ 136 | 'Integer' => 'runnerlee is the most handsome man', 137 | ], 138 | ], 139 | $validator->messages() 140 | ); 141 | } 142 | 143 | protected function getRules() 144 | { 145 | return [ 146 | 'data' => 'size:4', 147 | 'url' => 'url', 148 | 'array' => 'required|array|min:1', 149 | 'array.hello' => 'numeric', 150 | 'accept' => 'accept', 151 | 'integer' => 'integer', 152 | 'boolean' => 'boolean', 153 | 'string' => 'string', 154 | 'confirm' => 'confirm:string', 155 | 'date' => 'date', 156 | 'email' => 'email', 157 | 'numeric_string' => 'string|size:6', 158 | 'block_reason' => 'string|required_with:is_blocked', 159 | 'channel' => 'required|channel_range', 160 | 'diff_beta' => 'diff:diff_alpha', 161 | 'json' => 'json', 162 | 'ip' => 'ip', 163 | 'in' => 'in:a,b,c', 164 | 'float' => 'required_unless:channel,baidu|float|size:1.44|min:1.44|max:1.44', 165 | 'sub_arr.demo' => 'size:3', 166 | 'without_alpha' => 'required_without:without_beta|required_if:channel,google', 167 | 'nullable' => 'nullable', 168 | 'range_a' => 'range:1,1.5', 169 | 'range_b' => 'range:,1.5', 170 | 'range_c' => 'range:1,', 171 | 'range_g' => 'range:1', 172 | 'regex' => 'regex:#\w+#', 173 | 'date_format' => 'date_format:Y-m-d', 174 | 'date_before' => 'date_before:2018-01-02', 175 | 'date_after' => 'date_after:2017-12-31', 176 | ]; 177 | } 178 | 179 | protected function getData() 180 | { 181 | return [ 182 | 'data' => 'demo', 183 | 'url' => 'http://runnerlee.com', 184 | 'array' => [ 185 | 'hello' => '1.1', 186 | ], 187 | 'accept' => 'on', 188 | 'integer' => '1', 189 | 'boolean' => 0, 190 | 'string' => 'hello world', 191 | 'confirm' => 'hello world', 192 | 'date' => '1995-09-06', 193 | 'email' => 'runnerleer@gmail.com', 194 | 'numeric_string' => '123456', 195 | 'is_blocked' => 'no', 196 | 'block_reason' => '123', 197 | 'channel' => 'google', 198 | 'diff_alpha' => 'hello', 199 | 'diff_beta' => 'world', 200 | 'json' => '{"a":"b"}', 201 | 'ip' => '127.0.0.1', 202 | 'in' => 'a', 203 | 'float' => '1.44', 204 | 'sub_arr' => [], 205 | 'without_alpha' => 'a', 206 | 'range_a' => '1.5', 207 | 'range_b' => '1.5', 208 | 'range_c' => '1.5', 209 | 'range_e' => '1.5', 210 | 'range_f' => '1.5', 211 | 'range_g' => '3', 212 | 'regex' => '123abc', 213 | 'date_format' => '2018-01-01', 214 | 'date_before' => '2018-01-01', 215 | 'date_after' => '2018-01-01', 216 | 'nullable' => null, 217 | ]; 218 | } 219 | } 220 | --------------------------------------------------------------------------------