[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);
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);

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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());
}
}