Merge branch '3.3' into 3.4

* 3.3:
  [Yaml] Clarify "incompatible key casting" deprecation message
  minor #23043 add \ to PHP_VERSION_ID fixes #22650
  [PhpUnitBridge] Fix detection of PHPUnit 5
  Adding a new event subscriber that "parses" the _controller attribute in the FW
This commit is contained in:
Nicolas Grekas 2017-06-03 00:30:16 +02:00
commit 36a8160690
13 changed files with 192 additions and 6 deletions

View File

@ -16,7 +16,7 @@ use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
if (class_exists('PHPUnit_Framework_BaseTestListener')) {
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
class_alias('Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener', 'Symfony\Bridge\PhpUnit\SymfonyTestsListener');
return;

View File

@ -13,7 +13,7 @@ namespace Symfony\Bridge\PhpUnit\TextUI;
use PHPUnit\TextUI\Command as BaseCommand;
if (class_exists('PHPUnit_TextUI_Command')) {
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
class_alias('Symfony\Bridge\PhpUnit\Legacy\Command', 'Symfony\Bridge\PhpUnit\TextUI\Command');
return;

View File

@ -14,7 +14,7 @@ namespace Symfony\Bridge\PhpUnit\TextUI;
use PHPUnit\TextUI\TestRunner as BaseRunner;
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
if (class_exists('PHPUnit_TextUI_Command')) {
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunner', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner');
return;

View File

@ -0,0 +1,48 @@
<?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\Bundle\FrameworkBundle\EventListener;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Guarantees that the _controller key is parsed into its final format.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class ResolveControllerNameSubscriber implements EventSubscriberInterface
{
private $parser;
public function __construct(ControllerNameParser $parser)
{
$this->parser = $parser;
}
public function onKernelRequest(GetResponseEvent $event)
{
$controller = $event->getRequest()->attributes->get('_controller');
if ($controller && false === strpos($controller, '::') && 2 === substr_count($controller, ':')) {
// controller in the a:b:c notation then
$event->getRequest()->attributes->set('_controller', $this->parser->parse($controller));
}
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array('onKernelRequest', 24),
);
}
}

View File

@ -70,5 +70,10 @@
<service id="validate_request_listener" class="Symfony\Component\HttpKernel\EventListener\ValidateRequestListener" public="true">
<tag name="kernel.event_subscriber" />
</service>
<service id="resolve_controller_name_subscriber" class="Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber">
<argument type="service" id="controller_name_converter" />
<tag name="kernel.event_subscriber" />
</service>
</services>
</container>

View File

@ -0,0 +1,54 @@
<?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\Bundle\FrameworkBundle\Tests\EventListener;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class ResolveControllerNameSubscriberTest extends TestCase
{
public function testReplacesControllerAttribute()
{
$parser = $this->getMockBuilder(ControllerNameParser::class)->disableOriginalConstructor()->getMock();
$parser->expects($this->any())
->method('parse')
->with('AppBundle:Starting:format')
->willReturn('App\\Final\\Format::methodName');
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = new Request();
$request->attributes->set('_controller', 'AppBundle:Starting:format');
$subscriber = new ResolveControllerNameSubscriber($parser);
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$this->assertEquals('App\\Final\\Format::methodName', $request->attributes->get('_controller'));
}
public function testSkipsOtherControllerFormats()
{
$parser = $this->getMockBuilder(ControllerNameParser::class)->disableOriginalConstructor()->getMock();
$parser->expects($this->never())
->method('parse');
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = new Request();
$request->attributes->set('_controller', 'Other:format');
$subscriber = new ResolveControllerNameSubscriber($parser);
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$this->assertEquals('Other:format', $request->attributes->get('_controller'));
}
}

View File

@ -0,0 +1,38 @@
<?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\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class SubRequestServiceResolutionController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function indexAction()
{
$request = $this->container->get('request_stack')->getCurrentRequest();
$path['_forwarded'] = $request->attributes;
$path['_controller'] = 'TestBundle:SubRequestServiceResolution:fragment';
$subRequest = $request->duplicate(array(), null, $path);
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
public function fragmentAction(LoggerInterface $logger)
{
return new Response('---');
}
}

View File

@ -20,4 +20,12 @@ class SubRequestsTest extends WebTestCase
$this->assertEquals('--fr/json--en/html--fr/json--http://localhost/subrequest/fragment/en', $client->getResponse()->getContent());
}
public function testSubRequestControllerServicesAreResolved()
{
$client = $this->createClient(array('test_case' => 'ControllerServiceResolution', 'root_config' => 'config.yml'));
$client->request('GET', 'https://localhost/subrequest');
$this->assertEquals('---', $client->getResponse()->getContent());
}
}

View File

@ -0,0 +1,18 @@
<?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.
*/
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
return array(
new FrameworkBundle(),
new TestBundle(),
);

View File

@ -0,0 +1,10 @@
imports:
- { resource: ../config/default.yml }
services:
Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\SubRequestServiceResolutionController:
public: true
tags: [controller.service_arguments]
logger: { class: Psr\Log\NullLogger }
Psr\Log\LoggerInterface: '@logger'

View File

@ -0,0 +1,4 @@
sub_request_page:
path: /subrequest
defaults:
_controller: 'TestBundle:SubRequestServiceResolution:index'

View File

@ -237,7 +237,8 @@ class Parser
}
if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags) && !is_string($key)) {
@trigger_error('Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.', E_USER_DEPRECATED);
$keyType = is_numeric($key) ? 'numeric key' : 'incompatible key type';
@trigger_error(sprintf('Implicit casting of %s to string on line %d is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.', $keyType, $this->getRealCurrentLineNb()), E_USER_DEPRECATED);
}
// Convert float keys to strings, to avoid being converted to integers by PHP

View File

@ -1081,7 +1081,7 @@ EOF;
/**
* @group legacy
* @expectedDeprecation Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.
* @expectedDeprecation Implicit casting of numeric key to string on line 1 is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.
*/
public function testFloatKeys()
{
@ -1103,7 +1103,7 @@ EOF;
/**
* @group legacy
* @expectedDeprecation Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.
* @expectedDeprecation Implicit casting of incompatible key type to string on line 1 is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.
*/
public function testBooleanKeys()
{