Merge branch '2.8' into 3.3

* 2.8:
  Preserve percent-encoding in URLs when performing redirects in the UrlMatcher
  [Console] Fix a bug when passing a letter that could be an alias
  add missing validation options to XSD file
This commit is contained in:
Fabien Potencier 2017-12-14 11:31:56 -08:00
commit 13f58b403c
16 changed files with 160 additions and 15 deletions

View File

@ -197,6 +197,8 @@
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="static-method" type="xsd:boolean" />
<xsd:attribute name="translation-domain" type="xsd:string" />
<xsd:attribute name="strict-email" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="file_mapping">

View File

@ -0,0 +1,7 @@
<?php
$container->loadFromExtension('framework', array(
'validation' => array(
'strict_email' => true,
),
));

View File

@ -0,0 +1,7 @@
<?php
$container->loadFromExtension('framework', array(
'validation' => array(
'translation_domain' => 'messages',
),
));

View File

@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config>
<framework:validation strict-email="true" />
</framework:config>
</container>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config>
<framework:validation translation-domain="messages" />
</framework:config>
</container>

View File

@ -0,0 +1,3 @@
framework:
validation:
strict_email: true

View File

@ -0,0 +1,3 @@
framework:
validation:
translation_domain: messages

View File

@ -658,6 +658,20 @@ abstract class FrameworkExtensionTest extends TestCase
// no cache, no annotations, no static methods
}
public function testValidationTranslationDomain()
{
$container = $this->createContainerFromFile('validation_translation_domain');
$this->assertSame('messages', $container->getParameter('validator.translation_domain'));
}
public function testValidationStrictEmail()
{
$container = $this->createContainerFromFile('validation_strict_email');
$this->assertTrue($container->getDefinition('validator.email')->getArgument(0));
}
public function testValidationMapping()
{
$container = $this->createContainerFromFile('validation_mapping');

View File

@ -287,6 +287,8 @@ class ArgvInput extends Input
}
if (0 === strpos($token, '-') && 0 !== strpos($token, '--')) {
$noValue = explode('=', $token);
$token = $noValue[0];
$searchableToken = str_replace('-', '', $token);
$searchableValue = str_replace('-', '', $value);
if ('' !== $searchableToken && '' !== $searchableValue && false !== strpos($searchableToken, $searchableValue)) {

View File

@ -317,6 +317,9 @@ class ArgvInputTest extends TestCase
$input = new ArgvInput(array('cli.php', '-fh'));
$this->assertTrue($input->hasParameterOption('-fh'), '->hasParameterOption() returns true if the given short option is in the raw input');
$input = new ArgvInput(array('cli.php', '-e=test'));
$this->assertFalse($input->hasParameterOption('-s'), '->hasParameterOption() returns true if the given short option is in the raw input');
$input = new ArgvInput(array('cli.php', '--foo', 'foo'));
$this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input');

View File

@ -96,10 +96,10 @@ EOF;
$code = rtrim($this->compileRoutes($this->getRoutes(), $supportsRedirections), "\n");
return <<<EOF
public function match(\$pathinfo)
public function match(\$rawPathinfo)
{
\$allow = array();
\$pathinfo = rawurldecode(\$pathinfo);
\$pathinfo = rawurldecode(\$rawPathinfo);
\$trimmedPathinfo = rtrim(\$pathinfo, '/');
\$context = \$this->context;
\$request = \$this->request;
@ -331,7 +331,7 @@ EOF;
if ($hasTrailingSlash) {
$code .= <<<EOF
if (substr(\$pathinfo, -1) !== '/') {
return \$this->redirect(\$pathinfo.'/', '$name');
return \$this->redirect(\$rawPathinfo.'/', '$name');
}
@ -346,7 +346,7 @@ EOF;
$code .= <<<EOF
\$requiredSchemes = $schemes;
if (!isset(\$requiredSchemes[\$scheme])) {
return \$this->redirect(\$pathinfo, '$name', key(\$requiredSchemes));
return \$this->redirect(\$rawPathinfo, '$name', key(\$requiredSchemes));
}

View File

@ -15,10 +15,10 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$this->context = $context;
}
public function match($pathinfo)
public function match($rawPathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$pathinfo = rawurldecode($rawPathinfo);
$trimmedPathinfo = rtrim($pathinfo, '/');
$context = $this->context;
$request = $this->request;

View File

@ -15,10 +15,10 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
$this->context = $context;
}
public function match($pathinfo)
public function match($rawPathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$pathinfo = rawurldecode($rawPathinfo);
$trimmedPathinfo = rtrim($pathinfo, '/');
$context = $this->context;
$request = $this->request;
@ -83,7 +83,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
// baz3
if ('/test/baz3' === $trimmedPathinfo) {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'baz3');
return $this->redirect($rawPathinfo.'/', 'baz3');
}
return array('_route' => 'baz3');
@ -94,7 +94,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
// baz4
if (preg_match('#^/test/(?P<foo>[^/]++)/?$#s', $pathinfo, $matches)) {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'baz4');
return $this->redirect($rawPathinfo.'/', 'baz4');
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
@ -177,7 +177,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
// hey
if ('/multi/hey' === $trimmedPathinfo) {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'hey');
return $this->redirect($rawPathinfo.'/', 'hey');
}
return array('_route' => 'hey');
@ -323,7 +323,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
if ('/secure' === $pathinfo) {
$requiredSchemes = array ( 'https' => 0,);
if (!isset($requiredSchemes[$scheme])) {
return $this->redirect($pathinfo, 'secure', key($requiredSchemes));
return $this->redirect($rawPathinfo, 'secure', key($requiredSchemes));
}
return array('_route' => 'secure');
@ -333,7 +333,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
if ('/nonsecure' === $pathinfo) {
$requiredSchemes = array ( 'http' => 0,);
if (!isset($requiredSchemes[$scheme])) {
return $this->redirect($pathinfo, 'nonsecure', key($requiredSchemes));
return $this->redirect($rawPathinfo, 'nonsecure', key($requiredSchemes));
}
return array('_route' => 'nonsecure');

View File

@ -15,10 +15,10 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$this->context = $context;
}
public function match($pathinfo)
public function match($rawPathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$pathinfo = rawurldecode($rawPathinfo);
$trimmedPathinfo = rtrim($pathinfo, '/');
$context = $this->context;
$request = $this->request;

View File

@ -13,11 +13,39 @@ namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class PhpMatcherDumperTest extends TestCase
{
/**
* @var string
*/
private $matcherClass;
/**
* @var string
*/
private $dumpPath;
protected function setUp()
{
parent::setUp();
$this->matcherClass = uniqid('ProjectUrlMatcher');
$this->dumpPath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_matcher.'.$this->matcherClass.'.php';
}
protected function tearDown()
{
parent::tearDown();
@unlink($this->dumpPath);
}
/**
* @expectedException \LogicException
*/
@ -36,6 +64,23 @@ class PhpMatcherDumperTest extends TestCase
$dumper->dump();
}
public function testRedirectPreservesUrlEncoding()
{
$collection = new RouteCollection();
$collection->add('foo', new Route('/foo:bar/'));
$class = $this->generateDumpedMatcher($collection, true);
$matcher = $this->getMockBuilder($class)
->setMethods(array('redirect'))
->setConstructorArgs(array(new RequestContext()))
->getMock();
$matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/', 'foo');
$matcher->match('/foo%3Abar');
}
/**
* @dataProvider getRouteCollections
*/
@ -383,4 +428,31 @@ class PhpMatcherDumperTest extends TestCase
array($trailingSlashCollection, 'url_matcher7.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
);
}
/**
* @param $dumper
*/
private function generateDumpedMatcher(RouteCollection $collection, $redirectableStub = false)
{
$options = array('class' => $this->matcherClass);
if ($redirectableStub) {
$options['base_class'] = '\Symfony\Component\Routing\Tests\Matcher\Dumper\RedirectableUrlMatcherStub';
}
$dumper = new PhpMatcherDumper($collection);
$code = $dumper->dump($options);
file_put_contents($this->dumpPath, $code);
include $this->dumpPath;
return $this->matcherClass;
}
}
abstract class RedirectableUrlMatcherStub extends UrlMatcher implements RedirectableUrlMatcherInterface
{
public function redirect($path, $route, $scheme = null)
{
}
}

View File

@ -69,4 +69,14 @@ class RedirectableUrlMatcherTest extends TestCase
;
$matcher->match('/foo');
}
public function testRedirectPreservesUrlEncoding()
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo:bar/'));
$matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
$matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/');
$matcher->match('/foo%3Abar');
}
}