Skip to content

Commit

Permalink
merged branch lavoiesl/master (PR #4522)
Browse files Browse the repository at this point in the history
Commits
-------

6f9eda9 [Form][Validator] Fixed generation of HTML5 pattern attribute based on Assert\Regex to remove delimiters.

Discussion
----------

[Form][Validator] Fixed generation of HTML5 pattern attribute based on Assert\Regex by removing delimiters or using a new option: htmlPattern.

Hopefully, this time is the good one…

* Fixes: [#3766, #4077, #4513, #4520, #4521]
* Bug fix: yes
* Feature addition: yes
* BC break: no
* Symfony2 tests pass: yes

In Issue #3766, it was asked that Assert\Regex generates HTML5 pattern attribute.
It was done in PR #4077, but the generated Regex is in delimited format which is not supported by HTML5.

Hence, `/[a-z]+/` would be converted to `[a-z]+`.
If flags are specified like in `/[a-z]+/i`, it cannot be converted and pattern validation will be disabled client-side. If is however now possible, using a new option, `htmlPattern`, to specify the pattern you want to be used.

Example:

```php
<?php
/**
 * @Assert\Regex(pattern="/^[0-9]+[a-z]*$/i", htmlPattern="^[0-9]+[a-zA-Z]*$")
 */
private $civic_number;
```

**Note**: [Documentation](http://symfony.com/doc/current/reference/constraints/Regex.html) should be updated accordingly.

---------------------------------------------------------------------------

by lavoiesl at 2012-06-08T15:45:17Z

God, I just found out you can "add more commits to this pull request by pushing to the master branch on lavoiesl/symfony"…

---------------------------------------------------------------------------

by travisbot at 2012-06-08T15:50:31Z

This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1568634) (merged 2d767b41 into b84b46b).

---------------------------------------------------------------------------

by petajaros at 2012-07-04T14:23:16Z

Anything new about this issue?

---------------------------------------------------------------------------

by lavoiesl at 2012-07-04T16:25:43Z

Alright, tests are passing using `phpunit -c phpunit.xml.dist --filter 'RegexValidatorTest'`. @travisbot reports errors because he can’t even start the tests due to dependencies, which is not related

---------------------------------------------------------------------------

by vicb at 2012-07-04T16:31:13Z

It should be ready to merge when you have taken the last comments into account. thanks.

---------------------------------------------------------------------------

by lavoiesl at 2012-07-04T16:39:05Z

So it seems this PR will finally pass, thanks a lot.

---------------------------------------------------------------------------

by vicb at 2012-07-04T17:03:35Z

Thank you for this PR and the changes.

---------------------------------------------------------------------------

by fabpot at 2012-07-04T17:10:20Z

@lavoiesl Can you squash your commits before I merge? Thanks.

---------------------------------------------------------------------------

by lavoiesl at 2012-07-04T17:25:18Z

There. I also left trace of some commits I did.

Thanks
  • Loading branch information
fabpot committed Jul 4, 2012
2 parents f1422ee + 889ddfd commit 7b3528d
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
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
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
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;
}
}
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 7b3528d

Please sign in to comment.