RangeValidator.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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;
  9. use yii\base\InvalidConfigException;
  10. use yii\helpers\ArrayHelper;
  11. /**
  12. * RangeValidator validates that the attribute value is among a list of values.
  13. *
  14. * The range can be specified via the [[range]] property.
  15. * If the [[not]] property is set true, the validator will ensure the attribute value
  16. * is NOT among the specified range.
  17. *
  18. * @author Qiang Xue <qiang.xue@gmail.com>
  19. * @since 2.0
  20. */
  21. class RangeValidator extends Validator
  22. {
  23. /**
  24. * @var array|\Traversable|\Closure a list of valid values that the attribute value should be among or an anonymous function that returns
  25. * such a list. The signature of the anonymous function should be as follows,
  26. *
  27. * ```php
  28. * function($model, $attribute) {
  29. * // compute range
  30. * return $range;
  31. * }
  32. * ```
  33. */
  34. public $range;
  35. /**
  36. * @var bool whether the comparison is strict (both type and value must be the same)
  37. */
  38. public $strict = false;
  39. /**
  40. * @var bool whether to invert the validation logic. Defaults to false. If set to true,
  41. * the attribute value should NOT be among the list of values defined via [[range]].
  42. */
  43. public $not = false;
  44. /**
  45. * @var bool whether to allow array type attribute.
  46. */
  47. public $allowArray = false;
  48. /**
  49. * {@inheritdoc}
  50. */
  51. public function init()
  52. {
  53. parent::init();
  54. if (!is_array($this->range)
  55. && !($this->range instanceof \Closure)
  56. && !($this->range instanceof \Traversable)
  57. ) {
  58. throw new InvalidConfigException('The "range" property must be set.');
  59. }
  60. if ($this->message === null) {
  61. $this->message = Yii::t('yii', '{attribute} is invalid.');
  62. }
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. protected function validateValue($value)
  68. {
  69. $in = false;
  70. if ($this->allowArray
  71. && ($value instanceof \Traversable || is_array($value))
  72. && ArrayHelper::isSubset($value, $this->range, $this->strict)
  73. ) {
  74. $in = true;
  75. }
  76. if (!$in && ArrayHelper::isIn($value, $this->range, $this->strict)) {
  77. $in = true;
  78. }
  79. return $this->not !== $in ? null : [$this->message, []];
  80. }
  81. /**
  82. * {@inheritdoc}
  83. */
  84. public function validateAttribute($model, $attribute)
  85. {
  86. if ($this->range instanceof \Closure) {
  87. $this->range = call_user_func($this->range, $model, $attribute);
  88. }
  89. parent::validateAttribute($model, $attribute);
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function clientValidateAttribute($model, $attribute, $view)
  95. {
  96. if ($this->range instanceof \Closure) {
  97. $this->range = call_user_func($this->range, $model, $attribute);
  98. }
  99. ValidationAsset::register($view);
  100. $options = $this->getClientOptions($model, $attribute);
  101. return 'yii.validation.range(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. public function getClientOptions($model, $attribute)
  107. {
  108. $range = [];
  109. foreach ($this->range as $value) {
  110. $range[] = (string) $value;
  111. }
  112. $options = [
  113. 'range' => $range,
  114. 'not' => $this->not,
  115. 'message' => $this->formatMessage($this->message, [
  116. 'attribute' => $model->getAttributeLabel($attribute),
  117. ]),
  118. ];
  119. if ($this->skipOnEmpty) {
  120. $options['skipOnEmpty'] = 1;
  121. }
  122. if ($this->allowArray) {
  123. $options['allowArray'] = 1;
  124. }
  125. return $options;
  126. }
  127. }