diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index d76710fba89cc..28a9e234c8121 100755 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -261,7 +261,10 @@ public function guessPatternForConstraint(Constraint $constraint) return new ValueGuess(sprintf('.{%s,%s}', (string) $constraint->min, (string) $constraint->max), Guess::LOW_CONFIDENCE); case 'Symfony\Component\Validator\Constraints\Regex': - return new ValueGuess($constraint->pattern, Guess::HIGH_CONFIDENCE ); + $html_pattern = $constraint->getHtmlPattern(); + return $html_pattern + ? new ValueGuess($html_pattern, Guess::HIGH_CONFIDENCE) + : null; case 'Symfony\Component\Validator\Constraints\Min': return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE); diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index b3dd506495771..189cdeec8cb32 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -528,7 +528,7 @@ public function testCreateBuilderUsesPatternIfFound() ->method('guessPattern') ->with('Application\Author', 'firstName') ->will($this->returnValue(new ValueGuess( - '/[a-z]/', + '[a-z]', Guess::MEDIUM_CONFIDENCE ))); @@ -536,7 +536,7 @@ public function testCreateBuilderUsesPatternIfFound() ->method('guessPattern') ->with('Application\Author', 'firstName') ->will($this->returnValue(new ValueGuess( - '/[a-zA-Z]/', + '[a-zA-Z]', Guess::HIGH_CONFIDENCE ))); @@ -544,7 +544,7 @@ public function testCreateBuilderUsesPatternIfFound() $factory->expects($this->once()) ->method('createNamedBuilder') - ->with('firstName', 'text', null, array('pattern' => '/[a-zA-Z]/')) + ->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]')) ->will($this->returnValue('builderInstance')); $builder = $factory->createBuilderForProperty( diff --git a/src/Symfony/Component/Validator/Constraints/Regex.php b/src/Symfony/Component/Validator/Constraints/Regex.php index 73f8b7b3323df..de05ba712ae24 100644 --- a/src/Symfony/Component/Validator/Constraints/Regex.php +++ b/src/Symfony/Component/Validator/Constraints/Regex.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; /** * @Annotation @@ -22,6 +23,7 @@ class Regex extends Constraint { public $message = 'This value is not valid.'; public $pattern; + public $html_pattern = null; public $match = true; /** @@ -39,4 +41,38 @@ public function getRequiredOptions() { return array('pattern'); } + + /** + * Sometimes, like when converting to HTML5 pattern attribute, the regex is needed without the delimiters + * Example: /[a-z]+/ would be converted to [a-z]+ + * However, if options are specified, it cannot be converted and this will throw an Exception + * @return string regex + * @throws Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function getNonDelimitedPattern() { + if (preg_match('/^(.)(.*)\1$/', $this->pattern, $matches)) { + $delimiter = $matches[1]; + // Unescape the delimiter in pattern + $pattern = str_replace('\\' . $delimiter, $delimiter, $matches[2]); + return $pattern; + } else { + throw new ConstraintDefinitionException("Cannot remove delimiters from pattern '{$this->pattern}'."); + } + } + + public function getHtmlPattern() { + // If html_pattern is specified, use it + if (!is_null($this->html_pattern)) { + return empty($this->html_pattern) + ? false + : $this->html_pattern; + } else { + try { + return $this->getNonDelimitedPattern(); + } catch (ConstraintDefinitionException $e) { + // Pattern cannot be converted + return false; + } + } + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php index 755f488577851..82e743c3c2c69 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php @@ -113,4 +113,64 @@ public function testConstraintGetDefaultOption() $this->assertEquals('pattern', $constraint->getDefaultOption()); } + + public function testNonDelimitedPattern() { + $constraint = new Regex(array( + 'pattern' => '/^[0-9]+$/', + )); + + $this->assertEquals('^[0-9]+$', $constraint->getNonDelimitedPattern()); + } + + public function testNonDelimitedPatternEscaping() { + $constraint = new Regex(array( + 'pattern' => '/^[0-9]+\/$/', + )); + + $this->assertEquals('^[0-9]+/$', $constraint->getNonDelimitedPattern()); + + $constraint = new Regex(array( + 'pattern' => '#^[0-9]+\#$#', + )); + + $this->assertEquals('^[0-9]+#$', $constraint->getNonDelimitedPattern()); + } + + public function testNonDelimitedPatternError() { + $constraint = new Regex(array( + 'pattern' => '/^[0-9]+$/i', + )); + + $this->setExpectedException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $constraint->getNonDelimitedPattern(); + } + + public function testHtmlPattern() { + // Specified html_pattern + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + 'html_pattern' => '^[a-zA-Z]+$', + )); + $this->assertEquals('^[a-zA-Z]+$', $constraint->getHtmlPattern()); + + // Disabled html_pattern + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + 'html_pattern' => false, + )); + $this->assertFalse($constraint->getHtmlPattern()); + + // Cannot be converted + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + )); + $this->assertFalse($constraint->getHtmlPattern()); + + // Automaticaly converted + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/', + )); + $this->assertEquals('^[a-z]+$', $constraint->getHtmlPattern()); + } + }