Skip to content

Commit

Permalink
[Form][Validator] Fixed generation of HTML5 pattern attribute based o…
Browse files Browse the repository at this point in the history
…n 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
  • Loading branch information
lavoiesl committed Jul 4, 2012
1 parent 518c51d commit 889ddfd
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,12 @@ 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 );
$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);
Expand Down
6 changes: 3 additions & 3 deletions src/Symfony/Component/Form/Tests/FormFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -528,23 +528,23 @@ public function testCreateBuilderUsesPatternIfFound()
->method('guessPattern')
->with('Application\Author', 'firstName')
->will($this->returnValue(new ValueGuess(
'/[a-z]/',
'[a-z]',
Guess::MEDIUM_CONFIDENCE
)));

$this->guesser2->expects($this->once())
->method('guessPattern')
->with('Application\Author', 'firstName')
->will($this->returnValue(new ValueGuess(
'/[a-zA-Z]/',
'[a-zA-Z]',
Guess::HIGH_CONFIDENCE
)));

$factory = $this->createMockFactory(array('createNamedBuilder'));

$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(
Expand Down
44 changes: 44 additions & 0 deletions src/Symfony/Component/Validator/Constraints/Regex.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;

/**
* @Annotation
Expand All @@ -22,6 +23,7 @@ class Regex extends Constraint
{
public $message = 'This value is not valid.';
public $pattern;
public $htmlPattern = null;
public $match = true;

/**
Expand All @@ -39,4 +41,46 @@ public function getRequiredOptions()
{
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,55 @@ public function testConstraintGetDefaultOption()

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

}

0 comments on commit 889ddfd

Please sign in to comment.