/framework/validators/EachValidator.php

https://gitlab.com/brucealdridge/yii2 · PHP · 152 lines · 70 code · 12 blank · 70 comment · 13 complexity · 697b1978d2cf8d17fd500003d36a6c4c MD5 · raw file

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\validators;
  8. use yii\base\InvalidConfigException;
  9. use Yii;
  10. use yii\base\Model;
  11. /**
  12. * EachValidator validates an array by checking each of its elements against an embedded validation rule.
  13. *
  14. * ~~~php
  15. * class MyModel extends Model
  16. * {
  17. * public $categoryIDs = [];
  18. *
  19. * public function rules()
  20. * {
  21. * return [
  22. * // checks if every category ID is an integer
  23. * ['categoryIDs', 'each', 'rule' => ['integer']],
  24. * ]
  25. * }
  26. * }
  27. * ~~~
  28. *
  29. * > Note: This validator will not work with inline validation rules in case of usage outside the model scope,
  30. * e.g. via [[validate()]] method.
  31. *
  32. * @author Paul Klimov <klimov.paul@gmail.com>
  33. * @since 2.0.4
  34. */
  35. class EachValidator extends Validator
  36. {
  37. /**
  38. * @var array|Validator definition of the validation rule, which should be used on array values.
  39. * It should be specified in the same format as at [[yii\base\Model::rules()]], except it should not
  40. * contain attribute list as the first element.
  41. * For example:
  42. *
  43. * ~~~
  44. * ['integer']
  45. * ['match', 'pattern' => '/[a-z]/is']
  46. * ~~~
  47. *
  48. * Please refer to [[yii\base\Model::rules()]] for more details.
  49. */
  50. public $rule;
  51. /**
  52. * @var boolean whether to use error message composed by validator declared via [[rule]] if its validation fails.
  53. * If enabled, error message specified for this validator itself will appear only if attribute value is not an array.
  54. * If disabled, own error message value will be used always.
  55. */
  56. public $allowMessageFromRule = true;
  57. /**
  58. * @var Validator validator instance.
  59. */
  60. private $_validator;
  61. /**
  62. * @inheritdoc
  63. */
  64. public function init()
  65. {
  66. parent::init();
  67. if ($this->message === null) {
  68. $this->message = Yii::t('yii', '{attribute} is invalid.');
  69. }
  70. }
  71. /**
  72. * Returns the validator declared in [[rule]].
  73. * @param Model|null $model model in which context validator should be created.
  74. * @return Validator the declared validator.
  75. */
  76. private function getValidator($model = null)
  77. {
  78. if ($this->_validator === null) {
  79. $this->_validator = $this->createEmbeddedValidator($model);
  80. }
  81. return $this->_validator;
  82. }
  83. /**
  84. * Creates validator object based on the validation rule specified in [[rule]].
  85. * @param Model|null $model model in which context validator should be created.
  86. * @throws \yii\base\InvalidConfigException
  87. * @return Validator validator instance
  88. */
  89. private function createEmbeddedValidator($model)
  90. {
  91. $rule = $this->rule;
  92. if ($rule instanceof Validator) {
  93. return $rule;
  94. } elseif (is_array($rule) && isset($rule[0])) { // validator type
  95. if (!is_object($model)) {
  96. $model = new Model(); // mock up context model
  97. }
  98. return Validator::createValidator($rule[0], $model, $this->attributes, array_slice($rule, 1));
  99. } else {
  100. throw new InvalidConfigException('Invalid validation rule: a rule must be an array specifying validator type.');
  101. }
  102. }
  103. /**
  104. * @inheritdoc
  105. */
  106. public function validateAttribute($model, $attribute)
  107. {
  108. $value = $model->$attribute;
  109. $validator = $this->getValidator();
  110. if ($validator instanceof FilterValidator && is_array($value)) {
  111. $filteredValue = [];
  112. foreach ($value as $k => $v) {
  113. if (!$validator->skipOnArray || !is_array($v)) {
  114. $filteredValue[$k] = call_user_func($validator->filter, $v);
  115. }
  116. }
  117. $model->$attribute = $filteredValue;
  118. } else {
  119. $this->getValidator($model); // ensure model context while validator creation
  120. parent::validateAttribute($model, $attribute);
  121. }
  122. }
  123. /**
  124. * @inheritdoc
  125. */
  126. protected function validateValue($value)
  127. {
  128. if (!is_array($value)) {
  129. return [$this->message, []];
  130. }
  131. $validator = $this->getValidator();
  132. foreach ($value as $v) {
  133. $result = $validator->validateValue($v);
  134. if ($result !== null) {
  135. return $this->allowMessageFromRule ? $result : [$this->message, []];
  136. }
  137. }
  138. return null;
  139. }
  140. }