From 6f9eda95820a9d7469c12b471fb3b816bc9f7763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lavoie?= Date: Fri, 8 Jun 2012 00:32:21 -0400 Subject: [PATCH] [Form][Validator] Fixed generation of HTML5 pattern attribute based on Assert\Regex to remove delimiters. [Validator] Added delimiter escaping to Validator\Constraints\Regex::getNonDelimitedPattern [Form][Validator] Added htmlPattern option for Regex Validation. [Validator] Fixed Validator\Constraints\Regex::getNonDelimitedPattern variable declarations [Validator] Fixed tests for Regex htmlPattern option (instead of html_pattern) [Validation] tweaked generation of pattern to include .* when not anchors are present. Also removed the exception and made getNonDelimitedPattern private --- .../Validator/ValidatorTypeGuesser.php | 7 ++- .../Component/Form/Tests/FormFactoryTest.php | 6 +-- .../Component/Validator/Constraints/Regex.php | 44 ++++++++++++++++ .../Tests/Constraints/RegexValidatorTest.php | 51 +++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index d76710fba8..eeb43f1dad 100755 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -261,7 +261,12 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface 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 ); + $htmlPattern = $constraint->getHtmlPattern(); + + if (null !== $htmlPattern) { + return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE); + } + break; 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 b3dd506495..189cdeec8c 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -528,7 +528,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->method('guessPattern') ->with('Application\Author', 'firstName') ->will($this->returnValue(new ValueGuess( - '/[a-z]/', + '[a-z]', Guess::MEDIUM_CONFIDENCE ))); @@ -536,7 +536,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase ->method('guessPattern') ->with('Application\Author', 'firstName') ->will($this->returnValue(new ValueGuess( - '/[a-zA-Z]/', + '[a-zA-Z]', Guess::HIGH_CONFIDENCE ))); @@ -544,7 +544,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase $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 73f8b7b332..0a55251a99 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 $htmlPattern = null; public $match = true; /** @@ -39,4 +41,46 @@ class Regex extends Constraint { return array('pattern'); } + + /** + * Returns htmlPattern if exists or pattern is convertible. + * + * @return string|null + */ + public function getHtmlPattern() + { + // If htmlPattern is specified, use it + if (null !== $this->htmlPattern) { + return empty($this->htmlPattern) + ? null + : $this->htmlPattern; + } + + return $this->getNonDelimitedPattern(); + } + + /** + * Convert the htmlPattern to a suitable format for HTML5 pattern. + * Example: /^[a-z]+$/ would be converted to [a-z]+ + * However, if options are specified, it cannot be converted + * + * @link http://dev.w3.org/html5/spec/single-page.html#the-pattern-attribute + * + * @return string|null + */ + private function getNonDelimitedPattern() + { + if (preg_match('/^(.)(\^?)(.*?)(\$?)\1$/', $this->pattern, $matches)) { + $delimiter = $matches[1]; + $start = empty($matches[2]) ? '.*' : ''; + $pattern = $matches[3]; + $end = empty($matches[4]) ? '.*' : ''; + + // Unescape the delimiter in pattern + $pattern = str_replace('\\' . $delimiter, $delimiter, $pattern); + return $start . $pattern . $end; + } + + return null; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php index 755f488577..0e94da2bfa 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php @@ -113,4 +113,55 @@ class RegexValidatorTest extends \PHPUnit_Framework_TestCase $this->assertEquals('pattern', $constraint->getDefaultOption()); } + + public function testHtmlPatternEscaping() + { + $constraint = new Regex(array( + 'pattern' => '/^[0-9]+\/$/', + )); + + $this->assertEquals('[0-9]+/', $constraint->getHtmlPattern()); + + $constraint = new Regex(array( + 'pattern' => '#^[0-9]+\#$#', + )); + + $this->assertEquals('[0-9]+#', $constraint->getHtmlPattern()); + } + + public function testHtmlPattern() + { + // Specified htmlPattern + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + 'htmlPattern' => '[a-zA-Z]+', + )); + $this->assertEquals('[a-zA-Z]+', $constraint->getHtmlPattern()); + + // Disabled htmlPattern + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + 'htmlPattern' => false, + )); + $this->assertNull($constraint->getHtmlPattern()); + + // Cannot be converted + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/i', + )); + $this->assertNull($constraint->getHtmlPattern()); + + // Automaticaly converted + $constraint = new Regex(array( + 'pattern' => '/^[a-z]+$/', + )); + $this->assertEquals('[a-z]+', $constraint->getHtmlPattern()); + + // Automaticaly converted, adds .* + $constraint = new Regex(array( + 'pattern' => '/[a-z]+/', + )); + $this->assertEquals('.*[a-z]+.*', $constraint->getHtmlPattern()); + } + }