You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.7KB

  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 boolean whether the comparison is strict (both type and value must be the same)
  37. */
  38. public $strict = false;
  39. /**
  40. * @var boolean 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 boolean 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. $range = [];
  100. foreach ($this->range as $value) {
  101. $range[] = (string) $value;
  102. }
  103. $options = [
  104. 'range' => $range,
  105. 'not' => $this->not,
  106. 'message' => Yii::$app->getI18n()->format($this->message, [
  107. 'attribute' => $model->getAttributeLabel($attribute),
  108. ], Yii::$app->language),
  109. ];
  110. if ($this->skipOnEmpty) {
  111. $options['skipOnEmpty'] = 1;
  112. }
  113. if ($this->allowArray) {
  114. $options['allowArray'] = 1;
  115. }
  116. ValidationAsset::register($view);
  117. return 'yii.validation.range(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
  118. }
  119. }