[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
This commit is contained in:
Sébastien Lavoie 2012-06-08 00:32:21 -04:00
parent 1541fe26e4
commit 6f9eda9582
4 changed files with 104 additions and 4 deletions

View File

@ -261,7 +261,12 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
return new ValueGuess(sprintf('.{%s,%s}', (string) $constraint->min, (string) $constraint->max), Guess::LOW_CONFIDENCE); return new ValueGuess(sprintf('.{%s,%s}', (string) $constraint->min, (string) $constraint->max), Guess::LOW_CONFIDENCE);
case 'Symfony\Component\Validator\Constraints\Regex': 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': case 'Symfony\Component\Validator\Constraints\Min':
return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE); return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE);

View File

@ -528,7 +528,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
->method('guessPattern') ->method('guessPattern')
->with('Application\Author', 'firstName') ->with('Application\Author', 'firstName')
->will($this->returnValue(new ValueGuess( ->will($this->returnValue(new ValueGuess(
'/[a-z]/', '[a-z]',
Guess::MEDIUM_CONFIDENCE Guess::MEDIUM_CONFIDENCE
))); )));
@ -536,7 +536,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
->method('guessPattern') ->method('guessPattern')
->with('Application\Author', 'firstName') ->with('Application\Author', 'firstName')
->will($this->returnValue(new ValueGuess( ->will($this->returnValue(new ValueGuess(
'/[a-zA-Z]/', '[a-zA-Z]',
Guess::HIGH_CONFIDENCE Guess::HIGH_CONFIDENCE
))); )));
@ -544,7 +544,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$factory->expects($this->once()) $factory->expects($this->once())
->method('createNamedBuilder') ->method('createNamedBuilder')
->with('firstName', 'text', null, array('pattern' => '/[a-zA-Z]/')) ->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]'))
->will($this->returnValue('builderInstance')); ->will($this->returnValue('builderInstance'));
$builder = $factory->createBuilderForProperty( $builder = $factory->createBuilderForProperty(

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Validator\Constraints; namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/** /**
* @Annotation * @Annotation
@ -22,6 +23,7 @@ class Regex extends Constraint
{ {
public $message = 'This value is not valid.'; public $message = 'This value is not valid.';
public $pattern; public $pattern;
public $htmlPattern = null;
public $match = true; public $match = true;
/** /**
@ -39,4 +41,46 @@ class Regex extends Constraint
{ {
return array('pattern'); 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;
}
} }

View File

@ -113,4 +113,55 @@ class RegexValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('pattern', $constraint->getDefaultOption()); $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());
}
} }