diff --git lib/validator/opValidatorChoice.class.php lib/validator/opValidatorChoice.class.php new file mode 100644 index 0000000..a4ab992 --- /dev/null +++ lib/validator/opValidatorChoice.class.php @@ -0,0 +1,84 @@ +getChoices(); + + if ($this->getOption('multiple')) + { + $value = $this->cleanMultiple($value, $choices); + } + else + { + if (!self::inChoices($value, $choices)) + { + throw new sfValidatorError($this, 'invalid', array('value' => $value)); + } + } + + return $value; + } + + /** + * Cleans a value when multiple is true. + * + * @param mixed $value The submitted value + * + * @return array The cleaned value + */ + protected function cleanMultiple($value, $choices) + { + if (!is_array($value)) + { + $value = array($value); + } + + foreach ($value as $v) + { + if (!self::inChoices($v, $choices)) + { + throw new sfValidatorError($this, 'invalid', array('value' => $v)); + } + } + + $count = count($value); + + if ($this->hasOption('min') && $count < $this->getOption('min')) + { + throw new sfValidatorError($this, 'min', array('count' => $count, 'min' => $this->getOption('min'))); + } + + if ($this->hasOption('max') && $count > $this->getOption('max')) + { + throw new sfValidatorError($this, 'max', array('count' => $count, 'max' => $this->getOption('max'))); + } + + return $value; + } + + /** + * Checks if a value is part of given choices (see bug #4212) + * + * @param mixed $value The value to check + * @param array $choices The array of available choices + * + * @return Boolean + */ + static protected function inChoices($value, array $choices = array()) + { + foreach ($choices as $choice) + { + if ((string) $choice === (string) $value) + { + return true; + } + } + + return false; + } +} diff --git test/unit/validator/opValidatorChoiceTest.php test/unit/validator/opValidatorChoiceTest.php new file mode 100644 index 0000000..2a5e119 --- /dev/null +++ test/unit/validator/opValidatorChoiceTest.php @@ -0,0 +1,49 @@ +diag('opValidatorChoice'); + +$t->diag('->clean()'); + +$v = new opValidatorChoice(array( + 'choices' => array('00', '000', '0.0'), +)); + +try +{ + $v->clean('0'); + $t->fail('->clean() throws a sfValidatorError if not in choices'); + $t->skip('', 1); +} +catch (Exception $e) +{ + $t->pass('->clean() throws a sfValidatorError if not in choices'); + $t->is($e->getCode(), 'invalid', '->clean() throws a sfValidatorError'); +} + +$t->is($v->clean('00'), '00', '->clean() accepts in choices'); +$t->is($v->clean('000'), '000', '->clean() accepts in choices'); +$t->is($v->clean('0.0'), '0.0', '->clean() accepts in choices'); + + +$v = new opValidatorChoice(array( + 'choices' => array('011', '11.0'), +)); + +try +{ + $v->clean('11'); + $t->fail('->clean() throws a sfValidatorError if not in choices'); + $t->skip('', 1); +} +catch (Exception $e) +{ + $t->pass('->clean() throws a sfValidatorError if not in choices'); + $t->is($e->getCode(), 'invalid', '->clean() throws a sfValidatorError'); +} + +$t->is($v->clean('011'), '011', '->clean() accepts in choices'); +$t->is($v->clean('11.0'), '11.0', '->clean() accepts in choices');