1: <?php
2: 3: 4: 5: 6: 7:
8:
9: namespace Wei;
10:
11: use Wei\Validator\BaseValidator;
12:
13: 14: 15: 16: 17:
18: class Validate extends Base
19: {
20: 21: 22: 23: 24:
25: protected $rules = array();
26:
27: 28: 29: 30: 31:
32: protected $data = array();
33:
34: 35: 36: 37: 38:
39: protected $messages = array();
40:
41: 42: 43: 44: 45:
46: protected $names = array();
47:
48: 49: 50: 51: 52:
53: protected $beforeValidate;
54:
55: 56: 57: 58: 59:
60: protected $ruleValid;
61:
62: 63: 64: 65: 66:
67: protected $ruleInvalid;
68:
69: 70: 71: 72: 73:
74: protected $fieldValid;
75:
76: 77: 78: 79: 80:
81: protected $fieldInvalid;
82:
83: 84: 85: 86: 87:
88: protected $success;
89:
90: 91: 92: 93: 94:
95: protected $failure;
96:
97: 98: 99: 100: 101:
102: protected $breakRule = false;
103:
104: 105: 106: 107: 108:
109: protected $breakField = false;
110:
111: 112: 113: 114: 115: 116:
117: protected $skip = false;
118:
119: 120: 121: 122: 123:
124: protected $validRules = array();
125:
126: 127: 128: 129: 130:
131: protected $invalidRules = array();
132:
133: 134: 135: 136: 137:
138: protected $result;
139:
140: 141: 142: 143: 144:
145: protected $ruleValidators = array();
146:
147: 148: 149: 150: 151: 152:
153: public function __invoke(array $options = array())
154: {
155: $validator = new self($options + get_object_vars($this));
156:
157: $validator->valid($options);
158:
159: return $validator;
160: }
161:
162: 163: 164: 165: 166: 167: 168:
169: public function valid($options = array())
170: {
171: $options && $this->setOption($options);
172:
173:
174: $this->result = true;
175:
176: $this->beforeValidate && call_user_func($this->beforeValidate, $this, $this->wei);
177:
178: foreach ($this->rules as $field => $rules) {
179: $data = $this->getFieldData($field);
180:
181: 182: 183: 184: 185: 186: 187: 188: 189:
190: if (is_string($rules)) {
191: $rules = array($rules => true);
192: } elseif ($rules instanceof BaseValidator) {
193: $rules = array($rules);
194: } elseif (!is_array($rules)) {
195: throw new \InvalidArgumentException(sprintf(
196: 'Expected argument of type array, string or instance of Wei\Validator\BaseValidator, "%s" given',
197: is_object($rules) ? get_class($rules) : gettype($rules)
198: ));
199: }
200:
201:
202: if (!isset($rules['required'])) {
203: $isRequired = true;
204: } else {
205: $isRequired = (bool) $rules['required'];
206: unset($rules['required']);
207: }
208: $rules = array('required' => $isRequired) + $rules;
209:
210:
211: foreach ($rules as $rule => $params) {
212:
213: $props = $this->prepareProps($field, $rule);
214:
215:
216:
217: $validator = null;
218: $result = $this->validateOne($rule, $data, $params, $validator, $props);
219:
220: if (is_object($params)) {
221: $rule = get_class($params);
222: }
223:
224:
225: $this->ruleValidators[$field][$rule] = $validator;
226:
227:
228: if (false === $result) {
229: $this->result = false;
230: }
231:
232:
233: $method = $result ? 'addValidRule' : 'addInvalidRule';
234: $this->$method($field, $rule);
235:
236:
237: $callback = $result ? 'ruleValid' : 'ruleInvalid';
238: if ($this->$callback && false === call_user_func($this->$callback, $rule, $field, $this, $this->wei)) {
239: return $this->result;
240: }
241:
242: if ($result) {
243:
244:
245: if ('required' === $rule && $validator->isInvalid($data)) {
246: break;
247: }
248: } else {
249:
250: if ('required' === $rule || $this->breakRule || $this->skip) {
251: break;
252: }
253: }
254: }
255:
256:
257: $callback = $this->isFieldValid($field) ? 'fieldValid' : 'fieldInvalid';
258: if ($this->$callback && false === call_user_func($this->$callback, $field, $this, $this->wei)) {
259: return $this->result;
260: }
261:
262: if (!$this->result && $this->skip) {
263: continue;
264: }
265:
266:
267: if (!$this->result && ($this->breakRule || $this->breakField)) {
268: break;
269: }
270: }
271:
272:
273: $callback = $this->result ? 'success' : 'failure';
274: $this->$callback && call_user_func($this->$callback, $this, $this->wei);
275:
276: return $this->result;
277: }
278:
279: 280: 281: 282: 283: 284: 285:
286: protected function prepareProps($field, $rule)
287: {
288: $props = $messages = array();
289:
290: $props['validator'] = $this;
291:
292:
293: if (isset($this->names[$field])) {
294: $props['name'] = $this->names[$field];
295: }
296:
297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323:
324:
325: if (isset($this->messages[$field][$rule]) && is_array($this->messages[$field])) {
326: $messages = $this->messages[$field][$rule];
327:
328: } elseif (isset($this->messages[$field]) && is_scalar($this->messages[$field])) {
329: $messages = $this->messages[$field];
330: }
331:
332:
333: if (is_scalar($messages)) {
334: $props['message'] = $messages;
335: } elseif (is_array($messages)) {
336: foreach ($messages as $name => $message) {
337: $props[$name . 'Message'] = $message;
338: }
339: }
340:
341: return $props;
342: }
343:
344: 345: 346: 347: 348: 349: 350:
351: public function addValidRule($field, $rule)
352: {
353: $this->validRules[$field][] = $rule;
354: return $this;
355: }
356:
357: 358: 359: 360: 361: 362: 363:
364: public function addInvalidRule($field, $rule)
365: {
366: $this->invalidRules[$field][] = $rule;
367: return $this;
368: }
369:
370: 371: 372: 373: 374:
375: public function getValidFields()
376: {
377: return array_keys(array_diff_key($this->validRules, $this->invalidRules));
378: }
379:
380: 381: 382: 383: 384:
385: public function getInvalidFields()
386: {
387: return array_keys($this->invalidRules);
388: }
389:
390: 391: 392: 393: 394: 395:
396: public function isFieldValid($field)
397: {
398: return !in_array($field, $this->getInvalidFields());
399: }
400:
401: 402: 403: 404: 405: 406:
407: public function isFieldInvalid($field)
408: {
409: return in_array($field, $this->getInvalidFields());
410: }
411:
412: 413: 414: 415: 416: 417:
418: public function setRules(array $rules = null)
419: {
420: $this->rules = (array)$rules;
421: return $this;
422: }
423:
424: 425: 426: 427: 428:
429: public function getRules()
430: {
431: return $this->rules;
432: }
433:
434: 435: 436: 437: 438: 439:
440: public function getFieldRules($field)
441: {
442: return isset($this->rules[$field]) ? $this->rules[$field] : array();
443: }
444:
445: 446: 447: 448: 449: 450: 451:
452: public function getRuleParams($field, $rule)
453: {
454: return isset($this->rules[$field][$rule]) ? (array) $this->rules[$field][$rule] : array();
455: }
456:
457: 458: 459: 460: 461: 462:
463: public function getValidRules($field)
464: {
465: return isset($this->validRules[$field]) ? $this->validRules[$field] : array();
466: }
467:
468: 469: 470: 471: 472: 473:
474: public function getInvalidRules($field = null)
475: {
476: return $field ?
477: isset($this->invalidRules[$field]) ? $this->invalidRules[$field] : array()
478: : $this->invalidRules;
479: }
480:
481: 482: 483: 484: 485:
486: public function isValid()
487: {
488: return is_null($this->result) ? $this->__invoke() : $this->result;
489: }
490:
491: 492: 493: 494: 495: 496: 497:
498: public function addRule($field, $rule, $parameters)
499: {
500: $this->rules[$field][$rule] = $parameters;
501: }
502:
503: 504: 505: 506: 507: 508: 509:
510: public function hasRule($field, $rule)
511: {
512: return isset($this->rules[$field][$rule]);
513: }
514:
515: 516: 517: 518: 519: 520: 521:
522: public function removeRule($field, $rule)
523: {
524: if (isset($this->rules[$field][$rule])) {
525: unset($this->rules[$field][$rule]);
526: return true;
527: }
528: return false;
529: }
530:
531: 532: 533: 534: 535: 536:
537: public function removeField($field)
538: {
539: if (isset($this->rules[$field])) {
540: unset($this->rules[$field]);
541: return true;
542: }
543: return false;
544: }
545:
546: 547: 548: 549: 550: 551: 552:
553: public function setData($data)
554: {
555: if (!is_array($data) && !is_object($data)) {
556: throw new \InvalidArgumentException(sprintf(
557: 'Expected argument of type array or object, "%s" given',
558: is_object($data) ? get_class($data) : gettype($data)
559: ));
560: }
561: $this->data = $data;
562: return $this;
563: }
564:
565: 566: 567: 568: 569:
570: public function getData()
571: {
572: return $this->data;
573: }
574:
575: 576: 577: 578: 579: 580:
581: public function getFieldData($field)
582: {
583:
584: if ((is_array($this->data) && array_key_exists($field, $this->data))
585: || ($this->data instanceof \ArrayAccess && $this->data->offsetExists($field))
586: ) {
587: return $this->data[$field];
588: } elseif (isset($this->data->$field)) {
589: return $this->data->$field;
590: } elseif (method_exists($this->data, 'get' . $field)) {
591: return $this->data->{'get' . $field}();
592: } else {
593: return null;
594: }
595: }
596:
597: 598: 599: 600: 601: 602: 603:
604: public function setFieldData($field, $data)
605: {
606: if (is_array($this->data)) {
607: $this->data[$field] = $data;
608: } else {
609: $this->data->$field = $data;
610: }
611: return $this;
612: }
613:
614: 615: 616: 617: 618: 619:
620: public function setMessages(array $messages = null)
621: {
622: $this->messages = (array)$messages;
623: return $this;
624: }
625:
626: 627: 628: 629: 630:
631: public function getMessages()
632: {
633: return $this->messages;
634: }
635:
636: 637: 638: 639: 640:
641: public function getDetailMessages()
642: {
643: $messages = array();
644: foreach ($this->invalidRules as $field => $rules) {
645: foreach ($rules as $rule) {
646: $messages[$field][$rule] = $this->ruleValidators[$field][$rule]->getMessages();
647: }
648: }
649: return $messages;
650: }
651:
652: 653: 654: 655: 656:
657: public function getSummaryMessages()
658: {
659: $messages = $this->getDetailMessages();
660: $summaries = array();
661: foreach ($messages as $field => $rules) {
662: foreach ($rules as $options) {
663: foreach ($options as $message) {
664: $summaries[$field][] = $message;
665: }
666: }
667: }
668: return $summaries;
669: }
670:
671: 672: 673: 674: 675: 676:
677: public function getJoinedMessage($separator = "\n")
678: {
679: $messages = $this->getDetailMessages();
680: $array = array();
681: foreach ($messages as $rules) {
682: foreach ($rules as $options) {
683: foreach ($options as $message) {
684: $array[] = $message;
685: }
686: }
687: }
688: return implode($separator, array_unique($array));
689: }
690:
691: 692: 693: 694: 695:
696: public function getFirstMessage()
697: {
698: if ($this->isValid()) {
699: return false;
700: }
701: return current(current(current($this->getDetailMessages())));
702: }
703:
704: 705: 706: 707: 708: 709: 710:
711: public function getRuleValidator($field, $rule)
712: {
713: return isset($this->ruleValidators[$field][$rule]) ? $this->ruleValidators[$field][$rule] : null;
714: }
715:
716: 717: 718: 719: 720:
721: public function setNames($names)
722: {
723: $this->names = (array)$names;
724: }
725:
726: 727: 728: 729: 730:
731: public function getNames()
732: {
733: return $this->names;
734: }
735:
736: 737: 738: 739: 740: 741: 742: 743: 744:
745: public function validateOne($rule, $input, $options = array(), &$validator = null, $props = array())
746: {
747:
748: if (is_int($rule)) {
749: $rule = $options;
750: if (is_string($options)) {
751: $options = true;
752: }
753: }
754:
755: if ($rule instanceof Validator\BaseValidator) {
756: $validator = $rule;
757: return $rule($input);
758: }
759:
760: $validator = $this->createRuleValidator($rule, $props);
761:
762: if (!is_array($options)) {
763: $options = array($options);
764: }
765:
766: if (is_int(key($options))) {
767: array_unshift($options, $input);
768: $result = call_user_func_array($validator, $options);
769: } else {
770: $validator->setOption($options);
771: $result = $validator($input);
772: }
773:
774: return $result;
775: }
776:
777: 778: 779: 780: 781: 782: 783: 784:
785: public function createRuleValidator($rule, array $options = array())
786: {
787:
788: if (0 === stripos($rule, 'not')) {
789: $options['negative'] = true;
790: $rule = substr($rule, 3);
791: }
792:
793: $object = 'is' . ucfirst($rule);
794: $class = $this->wei->getClass($object);
795: if (!$class || !class_exists($class)) {
796: throw new \InvalidArgumentException(sprintf('Validator "%s" not found', $rule));
797: }
798:
799:
800: $options = $options + array('wei' => $this->wei) + (array)$this->wei->getConfig('is' . ucfirst($rule));
801:
802: return new $class($options);
803: }
804: }
805: