Merge branch '2.7' into 2.8

* 2.7:
  [Intl] Fixed the broken link
  [Routing] Fix trailing slash redirection for non-safe verbs
  [Debug] Fix bad registration of exception handler, leading to mem leak
  [Form] Fixed empty data on expanded ChoiceType and FileType
This commit is contained in:
Robin Chalas 2018-02-03 00:51:31 +01:00
commit 0293f3756d
14 changed files with 317 additions and 78 deletions

View File

@ -151,9 +151,20 @@ class ErrorHandler
}
if (!$replace && $prev) {
restore_error_handler();
$handlerIsRegistered = is_array($prev) && $handler === $prev[0];
} else {
$handlerIsRegistered = true;
}
if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] === $handler) {
if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
restore_exception_handler();
if (!$handlerIsRegistered) {
$handler = $prev[0];
} elseif ($handler !== $prev[0] && $replace) {
set_exception_handler(array($handler, 'handleException'));
$p = $prev[0]->setExceptionHandler(null);
$handler->setExceptionHandler($p);
$prev[0]->setExceptionHandler($p);
}
} else {
$handler->setExceptionHandler($prev);
}

View File

@ -35,7 +35,7 @@ class ErrorHandlerTest extends TestCase
$newHandler = new ErrorHandler();
$this->assertSame($newHandler, ErrorHandler::register($newHandler, false));
$this->assertSame($handler, ErrorHandler::register($newHandler, false));
$h = set_error_handler('var_dump');
restore_error_handler();
$this->assertSame(array($handler, 'handleError'), $h);

View File

@ -33,7 +33,6 @@ use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as Lega
use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -91,12 +90,12 @@ class ChoiceType extends AbstractType
$form = $event->getForm();
$data = $event->getData();
// Since the type always use mapper an empty array will not be
// considered as empty in Form::submit(), we need to evaluate
// empty data here so its value is submitted to sub forms
if (null === $data) {
$emptyData = $form->getConfig()->getEmptyData();
if (false === FormUtil::isEmpty($emptyData) && array() !== $emptyData) {
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData;
}
$data = $emptyData instanceof \Closure ? $emptyData($form, $data) : $emptyData;
}
// Convert the submitted data to a string, if scalar, before

View File

@ -27,10 +27,10 @@ class FileType extends AbstractType
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Ensure that submitted data is always an uploaded file or an array of some
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
$form = $event->getForm();
$requestHandler = $form->getConfig()->getRequestHandler();
$data = null;
if ($options['multiple']) {
$data = array();
@ -46,19 +46,16 @@ class FileType extends AbstractType
}
}
// submitted data for an input file (not required) without choosing any file
if (array(null) === $data || array() === $data) {
// Since the array is never considered empty in the view data format
// on submission, we need to evaluate the configured empty data here
if (array() === $data) {
$emptyData = $form->getConfig()->getEmptyData();
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData;
$data = $emptyData instanceof \Closure ? $emptyData($form, $data) : $emptyData;
}
$event->setData($data);
} elseif (!$requestHandler->isFileUpload($event->getData())) {
$emptyData = $form->getConfig()->getEmptyData();
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData;
$event->setData($data);
$event->setData(null);
}
});
}

View File

@ -699,6 +699,21 @@ class ChoiceTypeTest extends BaseTypeTest
$this->assertSame('test', $form->getData());
}
public function testSubmitSingleChoiceWithEmptyDataAndInitialData()
{
$form = $this->factory->create(static::TESTED_TYPE, 'initial', array(
'multiple' => false,
'expanded' => false,
'choices' => array('initial', 'test'),
'choices_as_values' => true,
'empty_data' => 'test',
));
$form->submit(null);
$this->assertSame('test', $form->getData());
}
public function testSubmitMultipleChoiceWithEmptyData()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
@ -714,6 +729,36 @@ class ChoiceTypeTest extends BaseTypeTest
$this->assertSame(array('test'), $form->getData());
}
public function testSubmitMultipleChoiceWithEmptyDataAndInitialEmptyArray()
{
$form = $this->factory->create(static::TESTED_TYPE, array(), array(
'multiple' => true,
'expanded' => false,
'choices' => array('test'),
'choices_as_values' => true,
'empty_data' => array('test'),
));
$form->submit(null);
$this->assertSame(array('test'), $form->getData());
}
public function testSubmitMultipleChoiceWithEmptyDataAndInitialData()
{
$form = $this->factory->create(static::TESTED_TYPE, array('initial'), array(
'multiple' => true,
'expanded' => false,
'choices' => array('initial', 'test'),
'choices_as_values' => true,
'empty_data' => array('test'),
));
$form->submit(null);
$this->assertSame(array('test'), $form->getData());
}
public function testSubmitSingleChoiceExpandedWithEmptyData()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
@ -729,6 +774,21 @@ class ChoiceTypeTest extends BaseTypeTest
$this->assertSame('test', $form->getData());
}
public function testSubmitSingleChoiceExpandedWithEmptyDataAndInitialData()
{
$form = $this->factory->create(static::TESTED_TYPE, 'initial', array(
'multiple' => false,
'expanded' => true,
'choices' => array('initial', 'test'),
'choices_as_values' => true,
'empty_data' => 'test',
));
$form->submit(null);
$this->assertSame('test', $form->getData());
}
public function testSubmitMultipleChoiceExpandedWithEmptyData()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
@ -744,6 +804,36 @@ class ChoiceTypeTest extends BaseTypeTest
$this->assertSame(array('test'), $form->getData());
}
public function testSubmitMultipleChoiceExpandedWithEmptyDataAndInitialEmptyArray()
{
$form = $this->factory->create(static::TESTED_TYPE, array(), array(
'multiple' => true,
'expanded' => true,
'choices' => array('test'),
'choices_as_values' => true,
'empty_data' => array('test'),
));
$form->submit(null);
$this->assertSame(array('test'), $form->getData());
}
public function testSubmitMultipleChoiceExpandedWithEmptyDataAndInitialData()
{
$form = $this->factory->create(static::TESTED_TYPE, array('init'), array(
'multiple' => true,
'expanded' => true,
'choices' => array('init', 'test'),
'choices_as_values' => true,
'empty_data' => array('test'),
));
$form->submit(null);
$this->assertSame(array('test'), $form->getData());
}
/**
* @group legacy
*/

View File

@ -5,7 +5,7 @@ A PHP replacement layer for the C intl extension that also provides access to
the localization data of the ICU library.
The replacement layer is limited to the locale "en". If you want to use other
locales, you should [install the intl PHP extension] [0] instead.
locales, you should [install the intl PHP extension][0] instead.
Resources
---------

View File

@ -101,7 +101,7 @@ EOF;
\$allow = array();
\$pathinfo = rawurldecode(\$rawPathinfo);
\$context = \$this->context;
\$request = \$this->request;
\$request = \$this->request ?: \$this->createRequest(\$pathinfo);
$code
@ -283,7 +283,11 @@ EOF;
if ($hasTrailingSlash) {
$code .= <<<EOF
if (substr(\$pathinfo, -1) !== '/') {
if ('/' === substr(\$pathinfo, -1)) {
// no-op
} elseif (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) {
goto $gotoname;
} else {
return \$this->redirect(\$rawPathinfo.'/', '$name');
}
@ -329,7 +333,7 @@ EOF;
}
$code .= " }\n";
if ($methods) {
if ($methods || $hasTrailingSlash) {
$code .= " $gotoname:\n";
}

View File

@ -20,7 +20,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$allow = array();
$pathinfo = rawurldecode($rawPathinfo);
$context = $this->context;
$request = $this->request;
$request = $this->request ?: $this->createRequest($pathinfo);
// foo
if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {

View File

@ -20,7 +20,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
$allow = array();
$pathinfo = rawurldecode($rawPathinfo);
$context = $this->context;
$request = $this->request;
$request = $this->request ?: $this->createRequest($pathinfo);
// foo
if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
@ -66,23 +66,33 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
// baz3
if ('/test/baz3' === rtrim($pathinfo, '/')) {
if (substr($pathinfo, -1) !== '/') {
if ('/' === substr($pathinfo, -1)) {
// no-op
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
goto not_baz3;
} else {
return $this->redirect($rawPathinfo.'/', 'baz3');
}
return array('_route' => 'baz3');
}
not_baz3:
}
// baz4
if (preg_match('#^/test/(?P<foo>[^/]++)/?$#s', $pathinfo, $matches)) {
if (substr($pathinfo, -1) !== '/') {
if ('/' === substr($pathinfo, -1)) {
// no-op
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
goto not_baz4;
} else {
return $this->redirect($rawPathinfo.'/', 'baz4');
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
}
not_baz4:
// baz5
if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
@ -170,12 +180,17 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
// hey
if ('/multi/hey' === rtrim($pathinfo, '/')) {
if (substr($pathinfo, -1) !== '/') {
if ('/' === substr($pathinfo, -1)) {
// no-op
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
goto not_hey;
} else {
return $this->redirect($rawPathinfo.'/', 'hey');
}
return array('_route' => 'hey');
}
not_hey:
}

View File

@ -20,7 +20,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$allow = array();
$pathinfo = rawurldecode($rawPathinfo);
$context = $this->context;
$request = $this->request;
$request = $this->request ?: $this->createRequest($pathinfo);
if (0 === strpos($pathinfo, '/rootprefix')) {
// static

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Tests\Matcher;
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
class DumpedRedirectableUrlMatcherTest extends RedirectableUrlMatcherTest
{
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
static $i = 0;
$class = 'DumpedRedirectableUrlMatcher'.++$i;
$dumper = new PhpMatcherDumper($routes);
$dumpedRoutes = eval('?>'.$dumper->dump(array('class' => $class, 'base_class' => 'Symfony\Component\Routing\Tests\Matcher\TestDumpedRedirectableUrlMatcher')));
return $this->getMockBuilder($class)
->setConstructorArgs(array($context ?: new RequestContext()))
->setMethods(array('redirect'))
->getMock();
}
}
class TestDumpedRedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
{
public function redirect($path, $route, $scheme = null)
{
return array();
}
}

View File

@ -0,0 +1,39 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Tests\Matcher;
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
class DumpedUrlMatcherTest extends UrlMatcherTest
{
/**
* @expectedException \LogicException
* @expectedExceptionMessage The "schemes" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.
*/
public function testSchemeRequirement()
{
parent::testSchemeRequirement();
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
static $i = 0;
$class = 'DumpedUrlMatcher'.++$i;
$dumper = new PhpMatcherDumper($routes);
$dumpedRoutes = eval('?>'.$dumper->dump(array('class' => $class)));
return new $class($context ?: new RequestContext());
}
}

View File

@ -11,20 +11,19 @@
namespace Symfony\Component\Routing\Tests\Matcher;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
class RedirectableUrlMatcherTest extends TestCase
class RedirectableUrlMatcherTest extends UrlMatcherTest
{
public function testRedirectWhenNoSlash()
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/'));
$matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
$matcher->expects($this->once())->method('redirect');
$matcher = $this->getUrlMatcher($coll);
$matcher->expects($this->once())->method('redirect')->will($this->returnValue(array()));
$matcher->match('/foo');
}
@ -38,7 +37,7 @@ class RedirectableUrlMatcherTest extends TestCase
$context = new RequestContext();
$context->setMethod('POST');
$matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, $context));
$matcher = $this->getUrlMatcher($coll, $context);
$matcher->match('/foo');
}
@ -47,7 +46,7 @@ class RedirectableUrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array('FTP', 'HTTPS')));
$matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
$matcher = $this->getUrlMatcher($coll);
$matcher
->expects($this->once())
->method('redirect')
@ -62,11 +61,10 @@ class RedirectableUrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array('https', 'http')));
$matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
$matcher = $this->getUrlMatcher($coll);
$matcher
->expects($this->never())
->method('redirect')
;
->method('redirect');
$matcher->match('/foo');
}
@ -75,8 +73,22 @@ class RedirectableUrlMatcherTest extends TestCase
$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 = $this->getUrlMatcher($coll);
$matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/')->willReturn(array());
$matcher->match('/foo%3Abar');
}
public function testSchemeRequirement()
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array('https')));
$matcher = $this->getUrlMatcher($coll, new RequestContext());
$matcher->expects($this->once())->method('redirect')->with('/foo', 'foo', 'https')->willReturn(array('_route' => 'foo'));
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($routes, $context ?: new RequestContext()));
}
}

View File

@ -26,7 +26,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertInternalType('array', $matcher->match('/foo'));
}
@ -35,7 +35,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('post')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
try {
$matcher->match('/foo');
@ -50,7 +50,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('get')));
$matcher = new UrlMatcher($coll, new RequestContext('', 'head'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'head'));
$this->assertInternalType('array', $matcher->match('/foo'));
}
@ -60,7 +60,7 @@ class UrlMatcherTest extends TestCase
$coll->add('foo1', new Route('/foo', array(), array(), array(), '', array(), array('post')));
$coll->add('foo2', new Route('/foo', array(), array(), array(), '', array(), array('put', 'delete')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
try {
$matcher->match('/foo');
@ -75,7 +75,7 @@ class UrlMatcherTest extends TestCase
// test the patterns are matched and parameters are returned
$collection = new RouteCollection();
$collection->add('foo', new Route('/foo/{bar}'));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
try {
$matcher->match('/no-match');
$this->fail();
@ -86,17 +86,17 @@ class UrlMatcherTest extends TestCase
// test that defaults are merged
$collection = new RouteCollection();
$collection->add('foo', new Route('/foo/{bar}', array('def' => 'test')));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz'));
// test that route "method" is ignored if no method is given in the context
$collection = new RouteCollection();
$collection->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('get', 'head')));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertInternalType('array', $matcher->match('/foo'));
// route does not match with POST method context
$matcher = new UrlMatcher($collection, new RequestContext('', 'post'));
$matcher = $this->getUrlMatcher($collection, new RequestContext('', 'post'));
try {
$matcher->match('/foo');
$this->fail();
@ -104,28 +104,28 @@ class UrlMatcherTest extends TestCase
}
// route does match with GET or HEAD method context
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertInternalType('array', $matcher->match('/foo'));
$matcher = new UrlMatcher($collection, new RequestContext('', 'head'));
$matcher = $this->getUrlMatcher($collection, new RequestContext('', 'head'));
$this->assertInternalType('array', $matcher->match('/foo'));
// route with an optional variable as the first segment
$collection = new RouteCollection();
$collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar')));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo'));
$this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo'));
$collection = new RouteCollection();
$collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar')));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo'));
$this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/'));
// route with only optional variables
$collection = new RouteCollection();
$collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array()));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/'));
$this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a'));
$this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b'));
@ -138,7 +138,7 @@ class UrlMatcherTest extends TestCase
$collection->addPrefix('/b');
$collection->addPrefix('/a');
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo'));
}
@ -149,7 +149,7 @@ class UrlMatcherTest extends TestCase
$collection->addPrefix('/b');
$collection->addPrefix('/{_locale}');
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo'));
}
@ -158,7 +158,7 @@ class UrlMatcherTest extends TestCase
$collection = new RouteCollection();
$collection->add('$péß^a|', new Route('/bar'));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar'));
}
@ -166,9 +166,9 @@ class UrlMatcherTest extends TestCase
{
$collection = new RouteCollection();
$chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-';
$collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+')));
$collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+'), array('utf8' => true)));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar'));
$this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar'));
}
@ -178,7 +178,7 @@ class UrlMatcherTest extends TestCase
$collection = new RouteCollection();
$collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+')));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched');
}
@ -192,7 +192,7 @@ class UrlMatcherTest extends TestCase
$collection->addCollection($collection1);
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
$this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1'));
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\ResourceNotFoundException');
@ -205,12 +205,12 @@ class UrlMatcherTest extends TestCase
$coll->add('foo', new Route('/foo/{foo}'));
$coll->add('bar', new Route('/foo/bar/{foo}'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar'));
$collection = new RouteCollection();
$collection->add('foo', new Route('/{bar}'));
$matcher = new UrlMatcher($collection, new RequestContext());
$matcher = $this->getUrlMatcher($collection);
try {
$matcher->match('/');
$this->fail();
@ -223,7 +223,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml'));
}
@ -232,7 +232,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-'));
}
@ -241,7 +241,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
// 'w' eagerly matches as much as possible and the other variables match the remaining chars.
// This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement.
// Otherwise they would also consume '.xml' and _format would never match as it's an optional variable.
@ -260,7 +260,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('test', new Route('/get{what}', array('what' => 'All')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get'));
$this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites'));
@ -275,7 +275,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('test', new Route('/get{what}Suffix'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix'));
}
@ -284,7 +284,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('test', new Route('/{page}.{_format}'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html'));
}
@ -296,7 +296,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('test', new Route('/{page}.{_format}'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$matcher->match('/index.sl/ash');
}
@ -308,7 +308,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$matcher->match('/do.t.html');
}
@ -320,7 +320,7 @@ class UrlMatcherTest extends TestCase
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo', array(), array(), array(), '', array('https')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$matcher->match('/foo');
}
@ -333,7 +333,7 @@ class UrlMatcherTest extends TestCase
$route = new Route('/foo');
$route->setCondition('context.getMethod() == "POST"');
$coll->add('foo', $route);
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$matcher->match('/foo');
}
@ -343,7 +343,7 @@ class UrlMatcherTest extends TestCase
$route = new Route('/foo/{bar}');
$route->setCondition('request.getBaseUrl() == "/sub/front.php" and request.getPathInfo() == "/foo/bar"');
$coll->add('foo', $route);
$matcher = new UrlMatcher($coll, new RequestContext('/sub/front.php'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('/sub/front.php'));
$this->assertEquals(array('bar' => 'bar', '_route' => 'foo'), $matcher->match('/foo/bar'));
}
@ -352,7 +352,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/{foo}'));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523'));
}
@ -368,7 +368,7 @@ class UrlMatcherTest extends TestCase
$coll->addCollection($subColl);
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('_route' => 'bar'), $matcher->match('/new'));
}
@ -377,7 +377,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
}
@ -388,10 +388,10 @@ class UrlMatcherTest extends TestCase
$coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net'));
$coll->setHost('{locale}.example.com');
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar'));
}
@ -403,7 +403,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
$matcher->match('/foo/bar');
}
@ -415,7 +415,7 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/locale', array(), array('locale' => 'EN|FR|DE')));
$matcher = new UrlMatcher($coll, new RequestContext());
$matcher = $this->getUrlMatcher($coll);
$matcher->match('/en');
}
@ -424,7 +424,36 @@ class UrlMatcherTest extends TestCase
$coll = new RouteCollection();
$coll->add('foo', new Route('/', array(), array('locale' => 'EN|FR|DE'), array(), '{locale}.example.com'));
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
$this->assertEquals(array('_route' => 'foo', 'locale' => 'en'), $matcher->match('/'));
}
public function testNestedCollections()
{
$coll = new RouteCollection();
$subColl = new RouteCollection();
$subColl->add('a', new Route('/a'));
$subColl->add('b', new Route('/b'));
$subColl->add('c', new Route('/c'));
$subColl->addPrefix('/p');
$coll->addCollection($subColl);
$coll->add('baz', new Route('/{baz}'));
$subColl = new RouteCollection();
$subColl->add('buz', new Route('/buz'));
$subColl->addPrefix('/prefix');
$coll->addCollection($subColl);
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(array('_route' => 'a'), $matcher->match('/p/a'));
$this->assertEquals(array('_route' => 'baz', 'baz' => 'p'), $matcher->match('/p'));
$this->assertEquals(array('_route' => 'buz'), $matcher->match('/prefix/buz'));
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return new UrlMatcher($routes, $context ?: new RequestContext());
}
}