diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index db1c2a8a6f..415464c40b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,3 +1,9 @@
+# Console
+/src/Symfony/Component/Console/Logger/ConsoleLogger.php @dunglas
+# DependencyInjection
+/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @dunglas
+# HttpKernel
+/src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas
# LDAP
/src/Symfony/Component/Ldap/* @csarrazi
# Lock
@@ -5,6 +11,13 @@
# Messenger
/src/Symfony/Bridge/Doctrine/Messenger/* @sroze
/src/Symfony/Component/Messenger/* @sroze
+# PropertyInfo
+/src/Symfony/Component/PropertyInfo/* @dunglas
+/src/Symfony/Bridge/Doctrine/PropertyInfo/* @dunglas
+# Serializer
+/src/Symfony/Component/Serializer/* @dunglas
+# WebLink
+/src/Symfony/Component/WebLink/* @dunglas
# Workflow
/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @lyrixx
/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @lyrixx
diff --git a/CHANGELOG-4.1.md b/CHANGELOG-4.1.md
index 5437c76fd6..3f712a6dfd 100644
--- a/CHANGELOG-4.1.md
+++ b/CHANGELOG-4.1.md
@@ -7,6 +7,35 @@ in 4.1 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.1.0...v4.1.1
+* 4.1.0 (2018-05-30)
+
+ * bug #27420 Revert "feature #26702 Mark ExceptionInterfaces throwable (ostrolucky)" (nicolas-grekas)
+ * bug #27415 Insert correct parameter_bag service in AbstractController (curry684)
+
+* 4.1.0-BETA3 (2018-05-26)
+
+ * bug #27388 [Routing] Account for greediness when merging route patterns (nicolas-grekas)
+ * bug #27344 [HttpKernel] reset kernel start time on reboot (kiler129)
+ * bug #27365 [Serializer] Check the value of enable_max_depth if defined (dunglas)
+ * bug #27358 [PhpUnitBridge] silence some stderr outputs (ostrolucky)
+ * bug #27366 [DI] never inline lazy services (nicolas-grekas)
+ * bug #27352 Remove reference to the test container after kernel shutdown (stof)
+ * bug #27350 [HttpKernel] fix deprecation in AbstractTestSessionListener (alekitto)
+ * bug #27367 [FrameworkBundle] cleanup generated test container (nicolas-grekas)
+ * bug #27379 [FrameworkBundle] Fix using test.service_container when Client is rebooted (nicolas-grekas)
+ * bug #27364 [DI] Fix bad exception on uninitialized references to non-shared services (nicolas-grekas)
+ * bug #27359 [HttpFoundation] Fix perf issue during MimeTypeGuesser intialization (nicolas-grekas)
+ * security #cve-2018-11408 [SecurityBundle] Fail if security.http_utils cannot be configured
+ * security #cve-2018-11406 clear CSRF tokens when the user is logged out
+ * security #cve-2018-11385 migrating session for UsernamePasswordJsonAuthenticationListener
+ * security #cve-2018-11385 migrating session for UsernamePasswordJsonAuthenticationListener
+ * security #cve-2018-11385 Adding session authentication strategy to Guard to avoid session fixation
+ * security #cve-2018-11385 Adding session strategy to ALL listeners to avoid *any* possible fixation
+ * security #cve-2018-11386 [HttpFoundation] Break infinite loop in PdoSessionHandler when MySQL is in loose mode
+ * bug #27341 [WebProfilerBundle] Fixed validator/dump trace CSS (yceruto)
+ * bug #27337 [FrameworkBundle] fix typo in CacheClearCommand (emilielorenzo)
+ * bug #27292 [Serializer] Fix and improve constraintViolationListNormalizer's RFC7807 compliance (dunglas)
+
* 4.1.0-BETA2 (2018-05-21)
* bug #27312 Supress deprecation notices thrown when getting private servies from container in tests (arderyp)
diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md
index 14dc6f07a6..fe43d0cf99 100644
--- a/UPGRADE-4.0.md
+++ b/UPGRADE-4.0.md
@@ -759,6 +759,9 @@ Security
* The `GuardAuthenticatorInterface` interface has been removed.
Use `AuthenticatorInterface` instead.
+ * When extending `AbstractGuardAuthenticator` getCredentials() cannot return
+ `null` anymore, return false from `supports()` if no credentials available instead.
+
SecurityBundle
--------------
diff --git a/UPGRADE-4.1.md b/UPGRADE-4.1.md
index 64921efd28..8410c67f84 100644
--- a/UPGRADE-4.1.md
+++ b/UPGRADE-4.1.md
@@ -64,6 +64,9 @@ Form
}
```
+ * Added `help` option to the form field. If you have custom Form extension for it, you should remove it.
+ Also remove it from the custom form theme.
+
FrameworkBundle
---------------
diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php
index 5f2be50923..c18f857285 100644
--- a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php
+++ b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php
@@ -49,6 +49,8 @@ class WebProcessorTest extends TestCase
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
+
+ Request::setTrustedProxies(array(), -1);
}
public function testCanBeConstructedWithExtraFields()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
index 954961119e..b317786c68 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
@@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Controller;
use Psr\Container\ContainerInterface;
use Doctrine\Common\Persistence\ManagerRegistry;
+use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
@@ -84,7 +85,7 @@ abstract class AbstractController implements ServiceSubscriberInterface
'form.factory' => '?'.FormFactoryInterface::class,
'security.token_storage' => '?'.TokenStorageInterface::class,
'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class,
- 'parameter_bag' => '?'.ContainerInterface::class,
+ 'parameter_bag' => '?'.ContainerBagInterface::class,
'message_bus' => '?'.MessageBusInterface::class,
);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index 64f4651390..70a83f2052 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -64,9 +64,6 @@ class FrameworkBundle extends Bundle
{
public function boot()
{
- if (!ini_get('xdebug.file_link_format') && !get_cfg_var('xdebug.file_link_format')) {
- ini_set('xdebug.file_link_format', $this->container->getParameter('debug.file_link_format'));
- }
ErrorHandler::register(null, false)->throwAt($this->container->getParameter('debug.error_handler.throw_at'), true);
if ($this->container->getParameter('kernel.http_method_override')) {
@@ -102,7 +99,7 @@ class FrameworkBundle extends Bundle
$this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class, PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_AFTER_REMOVING, -255);
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
- $this->addCompilerPassIfExists($container, AddConsoleCommandPass::class);
+ $this->addCompilerPassIfExists($container, AddConsoleCommandPass::class, PassConfig::TYPE_BEFORE_REMOVING);
$this->addCompilerPassIfExists($container, TranslatorPass::class);
$container->addCompilerPass(new LoggingTranslatorPass());
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
index 565aef68fd..f6dd2bb9df 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
@@ -74,6 +74,7 @@
%kernel.debug%
%kernel.charset%
+ %debug.file_link_format%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
index 77e92a09c0..0ae42c14ce 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
@@ -24,6 +24,32 @@ class AbstractControllerTest extends ControllerTraitTest
return new TestAbstractController();
}
+ /**
+ * This test protects the default subscribed core services against accidental modification.
+ */
+ public function testSubscribedServices()
+ {
+ $subscribed = AbstractController::getSubscribedServices();
+ $expectedServices = array(
+ 'router' => '?Symfony\\Component\\Routing\\RouterInterface',
+ 'request_stack' => '?Symfony\\Component\\HttpFoundation\\RequestStack',
+ 'http_kernel' => '?Symfony\\Component\\HttpKernel\\HttpKernelInterface',
+ 'serializer' => '?Symfony\\Component\\Serializer\\SerializerInterface',
+ 'session' => '?Symfony\\Component\\HttpFoundation\\Session\\SessionInterface',
+ 'security.authorization_checker' => '?Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface',
+ 'templating' => '?Symfony\\Component\\Templating\\EngineInterface',
+ 'twig' => '?Twig\\Environment',
+ 'doctrine' => '?Doctrine\\Common\\Persistence\\ManagerRegistry',
+ 'form.factory' => '?Symfony\\Component\\Form\\FormFactoryInterface',
+ 'parameter_bag' => '?Symfony\\Component\\DependencyInjection\\ParameterBag\\ContainerBagInterface',
+ 'message_bus' => '?Symfony\\Component\\Messenger\\MessageBusInterface',
+ 'security.token_storage' => '?Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface',
+ 'security.csrf.token_manager' => '?Symfony\\Component\\Security\\Csrf\\CsrfTokenManagerInterface',
+ );
+
+ $this->assertEquals($expectedServices, $subscribed, 'Subscribed core services in AbstractController have changed');
+ }
+
public function testGetParameter()
{
$container = new Container(new FrozenParameterBag(array('foo' => 'bar')));
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
index a77ba08b51..dff6bb4b98 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
@@ -30,6 +30,7 @@ class ExceptionController
protected $twig;
protected $debug;
protected $profiler;
+ private $fileLinkFormat;
public function __construct(Profiler $profiler = null, Environment $twig, bool $debug, FileLinkFormatter $fileLinkFormat = null)
{
diff --git a/src/Symfony/Component/Asset/Exception/ExceptionInterface.php b/src/Symfony/Component/Asset/Exception/ExceptionInterface.php
index 777f64b321..cce1b5cced 100644
--- a/src/Symfony/Component/Asset/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Asset/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Asset\Exception;
*
* @author Fabien Potencier
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Console/Exception/ExceptionInterface.php b/src/Symfony/Component/Console/Exception/ExceptionInterface.php
index 1624e13d0b..491cc4c645 100644
--- a/src/Symfony/Component/Console/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Console/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Console\Exception;
*
* @author Jérôme Tamarelle
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php b/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php
index 2a0136d797..af3e66ec59 100644
--- a/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php
+++ b/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php
@@ -12,10 +12,12 @@
namespace Symfony\Component\Console\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
-use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
+use Symfony\Component\DependencyInjection\ChildDefinition;
+use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\TypedReference;
@@ -28,7 +30,7 @@ class AddConsoleCommandPassTest extends TestCase
public function testProcess($public)
{
$container = new ContainerBuilder();
- $container->addCompilerPass(new AddConsoleCommandPass());
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->setParameter('my-command.class', 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand');
$id = 'my-command';
@@ -124,7 +126,7 @@ class AddConsoleCommandPassTest extends TestCase
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
- $container->addCompilerPass(new AddConsoleCommandPass());
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
$definition = new Definition('Symfony\Component\Console\Tests\DependencyInjection\MyCommand');
$definition->addTag('console.command');
@@ -142,7 +144,7 @@ class AddConsoleCommandPassTest extends TestCase
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
- $container->addCompilerPass(new AddConsoleCommandPass());
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
$definition = new Definition('SplObjectStorage');
$definition->addTag('console.command');
@@ -171,6 +173,79 @@ class AddConsoleCommandPassTest extends TestCase
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command1'));
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command2'));
}
+
+ public function testProcessOnChildDefinitionWithClass()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
+ $className = 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand';
+
+ $parentId = 'my-parent-command';
+ $childId = 'my-child-command';
+
+ $parentDefinition = new Definition(/* no class */);
+ $parentDefinition->setAbstract(true)->setPublic(false);
+
+ $childDefinition = new ChildDefinition($parentId);
+ $childDefinition->addTag('console.command')->setPublic(true);
+ $childDefinition->setClass($className);
+
+ $container->setDefinition($parentId, $parentDefinition);
+ $container->setDefinition($childId, $childDefinition);
+
+ $container->compile();
+ $command = $container->get($childId);
+
+ $this->assertInstanceOf($className, $command);
+ }
+
+ public function testProcessOnChildDefinitionWithParentClass()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
+ $className = 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand';
+
+ $parentId = 'my-parent-command';
+ $childId = 'my-child-command';
+
+ $parentDefinition = new Definition($className);
+ $parentDefinition->setAbstract(true)->setPublic(false);
+
+ $childDefinition = new ChildDefinition($parentId);
+ $childDefinition->addTag('console.command')->setPublic(true);
+
+ $container->setDefinition($parentId, $parentDefinition);
+ $container->setDefinition($childId, $childDefinition);
+
+ $container->compile();
+ $command = $container->get($childId);
+
+ $this->assertInstanceOf($className, $command);
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage The definition for "my-child-command" has no class.
+ */
+ public function testProcessOnChildDefinitionWithoutClass()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
+
+ $parentId = 'my-parent-command';
+ $childId = 'my-child-command';
+
+ $parentDefinition = new Definition();
+ $parentDefinition->setAbstract(true)->setPublic(false);
+
+ $childDefinition = new ChildDefinition($parentId);
+ $childDefinition->addTag('console.command')->setPublic(true);
+
+ $container->setDefinition($parentId, $parentDefinition);
+ $container->setDefinition($childId, $childDefinition);
+
+ $container->compile();
+ }
}
class MyCommand extends Command
diff --git a/src/Symfony/Component/CssSelector/Exception/ExceptionInterface.php b/src/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
index 9e259006b0..e4c5ae1b6b 100644
--- a/src/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
@@ -19,6 +19,6 @@ namespace Symfony\Component\CssSelector\Exception;
*
* @author Jean-François Simon
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Dotenv/Exception/ExceptionInterface.php b/src/Symfony/Component/Dotenv/Exception/ExceptionInterface.php
index 140a93f966..90509f7db5 100644
--- a/src/Symfony/Component/Dotenv/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Dotenv/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Dotenv\Exception;
*
* @author Fabien Potencier
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php b/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php
index fc438d9f31..8f4f10aac7 100644
--- a/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Filesystem\Exception;
*
* @author Romain Neutron
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Form/Exception/ExceptionInterface.php b/src/Symfony/Component/Form/Exception/ExceptionInterface.php
index 69145f0bcd..d455932edf 100644
--- a/src/Symfony/Component/Form/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Form/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Form\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
index b5b4adf122..2f1abf5846 100644
--- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
+++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
@@ -210,7 +210,7 @@ class ResponseHeaderBag extends HeaderBag
*
* @param string $format
*
- * @return array
+ * @return Cookie[]
*
* @throws \InvalidArgumentException When the $format is invalid
*/
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
index 0077976645..a1bb951f8f 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
@@ -21,7 +21,6 @@ class RequestTest extends TestCase
{
protected function tearDown()
{
- // reset
Request::setTrustedProxies(array(), -1);
Request::setTrustedHosts(array());
}
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
index 6d70731cea..430a6f9196 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
@@ -36,13 +36,15 @@ class ExceptionListener implements EventSubscriberInterface
protected $logger;
protected $debug;
private $charset;
+ private $fileLinkFormat;
- public function __construct($controller, LoggerInterface $logger = null, $debug = false, $charset = null)
+ public function __construct($controller, LoggerInterface $logger = null, $debug = false, $charset = null, $fileLinkFormat = null)
{
$this->controller = $controller;
$this->logger = $logger;
$this->debug = $debug;
$this->charset = $charset;
+ $this->fileLinkFormat = $fileLinkFormat;
}
public function logKernelException(GetResponseForExceptionEvent $event)
@@ -130,7 +132,7 @@ class ExceptionListener implements EventSubscriberInterface
$attributes = array(
'exception' => $exception = FlattenException::create($exception),
'_controller' => $this->controller ?: function () use ($exception) {
- $handler = new ExceptionHandler($this->debug, $this->charset);
+ $handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat);
return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders());
},
diff --git a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php
index e742845858..75cc078134 100644
--- a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php
+++ b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php
@@ -115,7 +115,9 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
$server['HTTP_X_FORWARDED_FOR'] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
}
- $server['REMOTE_ADDR'] = '127.0.0.1';
+ $trustedProxies = Request::getTrustedProxies();
+ $server['REMOTE_ADDR'] = $trustedProxies ? reset($trustedProxies) : '127.0.0.1';
+
unset($server['HTTP_IF_MODIFIED_SINCE']);
unset($server['HTTP_IF_NONE_MATCH']);
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php
index d060943255..8016603180 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php
@@ -21,6 +21,11 @@ use Symfony\Component\HttpKernel\KernelEvents;
class ValidateRequestListenerTest extends TestCase
{
+ protected function tearDown()
+ {
+ Request::setTrustedProxies(array(), -1);
+ }
+
/**
* @expectedException \Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException
*/
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
index 844b53b9a1..03a72e8057 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
@@ -168,16 +168,33 @@ class InlineFragmentRendererTest extends TestCase
public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest()
{
$expectedSubRequest = Request::create('/');
- if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
- $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
- $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
- }
+ $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
+ $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
$strategy->render('/', $request);
}
+ public function testFirstTrustedProxyIsSetAsRemote()
+ {
+ Request::setTrustedProxies(array('1.1.1.1'), -1);
+
+ $expectedSubRequest = Request::create('/');
+ $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
+ $expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
+ $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
+ $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
+
+ $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
+
+ $request = Request::create('/');
+ $request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
+ $strategy->render('/', $request);
+
+ Request::setTrustedProxies(array(), -1);
+ }
+
/**
* Creates a Kernel expecting a request equals to $request
* Allows delta in comparison in case REQUEST_TIME changed by 1 second.
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
index 2a9a30d9ca..2b14367673 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
@@ -1350,6 +1350,8 @@ class HttpCacheTest extends HttpCacheTestCase
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
$this->assertEquals($expected, Request::getTrustedProxies());
+
+ Request::setTrustedProxies(array(), -1);
}
public function getTrustedProxyData()
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
index bb19c496cc..d7c61a1ea9 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
@@ -340,6 +340,8 @@ class HttpKernelTest extends TestCase
$kernel = $this->getHttpKernel($dispatcher);
$kernel->handle($request, $kernel::MASTER_REQUEST, false);
+
+ Request::setTrustedProxies(array(), -1);
}
private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = array())
diff --git a/src/Symfony/Component/Intl/Exception/ExceptionInterface.php b/src/Symfony/Component/Intl/Exception/ExceptionInterface.php
index 0a73682379..4fc076cafb 100644
--- a/src/Symfony/Component/Intl/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Intl/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Intl\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Ldap/Exception/ExceptionInterface.php b/src/Symfony/Component/Ldap/Exception/ExceptionInterface.php
index dbc4819e92..b861a3fe8d 100644
--- a/src/Symfony/Component/Ldap/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Ldap/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Ldap\Exception;
*
* @author Charles Sarrazin
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Lock/Exception/ExceptionInterface.php b/src/Symfony/Component/Lock/Exception/ExceptionInterface.php
index 30343f939e..0d41958474 100644
--- a/src/Symfony/Component/Lock/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Lock/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Lock\Exception;
*
* @author Jérémy Derussé
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Messenger/Exception/ExceptionInterface.php b/src/Symfony/Component/Messenger/Exception/ExceptionInterface.php
index 3a208deacc..56f665b9ee 100644
--- a/src/Symfony/Component/Messenger/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Messenger/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Messenger\Exception;
*
* @author Samuel Roze
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json
index 47904dcbdf..131a53c231 100644
--- a/src/Symfony/Component/Messenger/composer.json
+++ b/src/Symfony/Component/Messenger/composer.json
@@ -30,7 +30,7 @@
"symfony/var-dumper": "~3.4|~4.0"
},
"suggest": {
- "sroze/enqueue-bridge": "For using the php-enqueue library as a transport."
+ "enqueue/messenger-adapter": "For using the php-enqueue library as a transport."
},
"autoload": {
"psr-4": { "Symfony\\Component\\Messenger\\": "" },
diff --git a/src/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php b/src/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php
index ea99d050e4..b62bb51d46 100644
--- a/src/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\OptionsResolver\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
index 440af8b578..12dc77b3c6 100644
--- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
+++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
@@ -29,10 +29,6 @@ class OptionsResolverTest extends TestCase
$this->resolver = new OptionsResolver();
}
- ////////////////////////////////////////////////////////////////////////////
- // resolve()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
* @expectedExceptionMessage The option "foo" does not exist. Defined options are: "a", "z".
@@ -69,10 +65,6 @@ class OptionsResolverTest extends TestCase
$this->resolver->resolve();
}
- ////////////////////////////////////////////////////////////////////////////
- // setDefault()/hasDefault()
- ////////////////////////////////////////////////////////////////////////////
-
public function testSetDefaultReturnsThis()
{
$this->assertSame($this->resolver, $this->resolver->setDefault('foo', 'bar'));
@@ -115,10 +107,6 @@ class OptionsResolverTest extends TestCase
$this->assertTrue($this->resolver->hasDefault('foo'));
}
- ////////////////////////////////////////////////////////////////////////////
- // lazy setDefault()
- ////////////////////////////////////////////////////////////////////////////
-
public function testSetLazyReturnsThis()
{
$this->assertSame($this->resolver, $this->resolver->setDefault('foo', function (Options $options) {}));
@@ -232,10 +220,6 @@ class OptionsResolverTest extends TestCase
$this->assertSame(2, $calls);
}
- ////////////////////////////////////////////////////////////////////////////
- // setRequired()/isRequired()/getRequiredOptions()
- ////////////////////////////////////////////////////////////////////////////
-
public function testSetRequiredReturnsThis()
{
$this->assertSame($this->resolver, $this->resolver->setRequired('foo'));
@@ -330,10 +314,6 @@ class OptionsResolverTest extends TestCase
$this->assertSame(array('foo', 'bar'), $this->resolver->getRequiredOptions());
}
- ////////////////////////////////////////////////////////////////////////////
- // isMissing()/getMissingOptions()
- ////////////////////////////////////////////////////////////////////////////
-
public function testIsMissingIfNotSet()
{
$this->assertFalse($this->resolver->isMissing('foo'));
@@ -373,10 +353,6 @@ class OptionsResolverTest extends TestCase
$this->assertSame(array('bar'), $this->resolver->getMissingOptions());
}
- ////////////////////////////////////////////////////////////////////////////
- // setDefined()/isDefined()/getDefinedOptions()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException
*/
@@ -474,10 +450,6 @@ class OptionsResolverTest extends TestCase
$this->assertFalse($this->resolver->isDefined('foo'));
}
- ////////////////////////////////////////////////////////////////////////////
- // setAllowedTypes()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
*/
@@ -662,10 +634,6 @@ class OptionsResolverTest extends TestCase
$this->resolver->resolve();
}
- ////////////////////////////////////////////////////////////////////////////
- // addAllowedTypes()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
*/
@@ -748,10 +716,6 @@ class OptionsResolverTest extends TestCase
$this->assertNotEmpty($this->resolver->resolve());
}
- ////////////////////////////////////////////////////////////////////////////
- // setAllowedValues()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
*/
@@ -903,10 +867,6 @@ class OptionsResolverTest extends TestCase
$this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve());
}
- ////////////////////////////////////////////////////////////////////////////
- // addAllowedValues()
- ////////////////////////////////////////////////////////////////////////////
-
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
*/
@@ -1023,10 +983,6 @@ class OptionsResolverTest extends TestCase
$this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve());
}
- ////////////////////////////////////////////////////////////////////////////
- // setNormalizer()
- ////////////////////////////////////////////////////////////////////////////
-
public function testSetNormalizerReturnsThis()
{
$this->resolver->setDefault('foo', 'bar');
@@ -1278,10 +1234,6 @@ class OptionsResolverTest extends TestCase
$this->assertEmpty($this->resolver->resolve());
}
- ////////////////////////////////////////////////////////////////////////////
- // setDefaults()
- ////////////////////////////////////////////////////////////////////////////
-
public function testSetDefaultsReturnsThis()
{
$this->assertSame($this->resolver, $this->resolver->setDefaults(array('foo', 'bar')));
@@ -1316,10 +1268,6 @@ class OptionsResolverTest extends TestCase
$this->resolver->resolve();
}
- ////////////////////////////////////////////////////////////////////////////
- // remove()
- ////////////////////////////////////////////////////////////////////////////
-
public function testRemoveReturnsThis()
{
$this->resolver->setDefault('foo', 'bar');
@@ -1408,10 +1356,6 @@ class OptionsResolverTest extends TestCase
$this->assertNotNull($this->resolver->remove('foo'));
}
- ////////////////////////////////////////////////////////////////////////////
- // clear()
- ////////////////////////////////////////////////////////////////////////////
-
public function testClearReturnsThis()
{
$this->assertSame($this->resolver, $this->resolver->clear());
@@ -1498,10 +1442,6 @@ class OptionsResolverTest extends TestCase
$this->assertEmpty($this->resolver->resolve());
}
- ////////////////////////////////////////////////////////////////////////////
- // ArrayAccess
- ////////////////////////////////////////////////////////////////////////////
-
public function testArrayAccess()
{
$this->resolver->setDefault('default1', 0);
@@ -1616,10 +1556,6 @@ class OptionsResolverTest extends TestCase
$this->resolver->resolve();
}
- ////////////////////////////////////////////////////////////////////////////
- // Countable
- ////////////////////////////////////////////////////////////////////////////
-
public function testCount()
{
$this->resolver->setDefault('default', 0);
diff --git a/src/Symfony/Component/Process/Exception/ExceptionInterface.php b/src/Symfony/Component/Process/Exception/ExceptionInterface.php
index bd4a60403b..75c1c9e5d8 100644
--- a/src/Symfony/Component/Process/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Process/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Process\Exception;
*
* @author Johannes M. Schmitt
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Process/ExecutableFinder.php b/src/Symfony/Component/Process/ExecutableFinder.php
index 1ec6526d45..defa66de6b 100644
--- a/src/Symfony/Component/Process/ExecutableFinder.php
+++ b/src/Symfony/Component/Process/ExecutableFinder.php
@@ -73,7 +73,7 @@ class ExecutableFinder
$suffixes = array('');
if ('\\' === DIRECTORY_SEPARATOR) {
$pathExt = getenv('PATHEXT');
- $suffixes = array_merge($suffixes, $pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes);
+ $suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
}
foreach ($suffixes as $suffix) {
foreach ($dirs as $dir) {
diff --git a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
index 68d6110e3a..3b2500b7fc 100644
--- a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
+++ b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
@@ -117,6 +117,36 @@ class ExecutableFinderTest extends TestCase
$this->assertSamePath(PHP_BINARY, $result);
}
+ /**
+ * @requires PHP 5.4
+ */
+ public function testFindBatchExecutableOnWindows()
+ {
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+ if ('\\' !== DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Can be only tested on windows');
+ }
+
+ $target = tempnam(sys_get_temp_dir(), 'example-windows-executable');
+
+ touch($target);
+ touch($target.'.BAT');
+
+ $this->assertFalse(is_executable($target));
+
+ $this->setPath(sys_get_temp_dir());
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find(basename($target), false);
+
+ unlink($target);
+ unlink($target.'.BAT');
+
+ $this->assertSamePath($target.'.BAT', $result);
+ }
+
private function assertSamePath($expected, $tested)
{
if ('\\' === DIRECTORY_SEPARATOR) {
diff --git a/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php b/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
index fabf9a0802..d1fcdac942 100644
--- a/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\PropertyAccess\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Routing/Exception/ExceptionInterface.php b/src/Symfony/Component/Routing/Exception/ExceptionInterface.php
index 22e72b16bd..db7636211f 100644
--- a/src/Symfony/Component/Routing/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Routing/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Routing\Exception;
*
* @author Alexandre Salomé
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md
index 9348d1f38f..c60efff979 100644
--- a/src/Symfony/Component/Security/CHANGELOG.md
+++ b/src/Symfony/Component/Security/CHANGELOG.md
@@ -41,7 +41,7 @@ CHANGELOG
* Added `getUser`, `getToken` and `isGranted` methods to `Security`.
* added a `setToken()` method to the `SwitchUserEvent` class to allow to replace the created token while switching users
- when custom token generation is required by application.
+ when custom token generation is required by application.
* Using voters that do not implement the `VoterInterface`is now deprecated in
the `AccessDecisionManager` and this functionality will be removed in 4.0.
* Using the `ContextListener` without setting the `logoutOnUserChange`
@@ -51,6 +51,8 @@ CHANGELOG
* deprecated HTTP digest authentication
* Added a new password encoder for the Argon2i hashing algorithm
* deprecated `GuardAuthenticatorInterface` in favor of `AuthenticatorInterface`
+ * deprecated to return `null` from `getCredentials()` in classes that extend
+ `AbstractGuardAuthenticator`. Return `false` from `supports()` instead.
3.3.0
-----
diff --git a/src/Symfony/Component/Security/Core/Exception/ExceptionInterface.php b/src/Symfony/Component/Security/Core/Exception/ExceptionInterface.php
index 7bc2b9132c..5000d02780 100644
--- a/src/Symfony/Component/Security/Core/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Security/Core/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Security\Core\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php
index ee69a793b6..07225971b4 100644
--- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php
@@ -59,7 +59,25 @@ class RememberMeListener implements ListenerInterface
}
$request = $event->getRequest();
- if (null === $token = $this->rememberMeServices->autoLogin($request)) {
+ try {
+ if (null === $token = $this->rememberMeServices->autoLogin($request)) {
+ return;
+ }
+ } catch (AuthenticationException $e) {
+ if (null !== $this->logger) {
+ $this->logger->warning(
+ 'The token storage was not populated with remember-me token as the'
+ .' RememberMeServices was not able to create a token from the remember'
+ .' me information.', array('exception' => $e)
+ );
+ }
+
+ $this->rememberMeServices->loginFail($request);
+
+ if (!$this->catchExceptions) {
+ throw $e;
+ }
+
return;
}
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
index 932c5edc96..fb27453029 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
@@ -145,6 +145,43 @@ class RememberMeListenerTest extends TestCase
$listener->handle($event);
}
+ public function testOnCoreSecurityAuthenticationExceptionDuringAutoLoginTriggersLoginFail()
+ {
+ list($listener, $tokenStorage, $service, $manager) = $this->getListener();
+
+ $tokenStorage
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $exception = new AuthenticationException('Authentication failed.');
+ $service
+ ->expects($this->once())
+ ->method('autoLogin')
+ ->will($this->throwException($exception))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('loginFail')
+ ;
+
+ $manager
+ ->expects($this->never())
+ ->method('authenticate')
+ ;
+
+ $event = $this->getGetResponseEvent();
+ $event
+ ->expects($this->once())
+ ->method('getRequest')
+ ->will($this->returnValue(new Request()))
+ ;
+
+ $listener->handle($event);
+ }
+
public function testOnCoreSecurity()
{
list($listener, $tokenStorage, $service, $manager) = $this->getListener();
diff --git a/src/Symfony/Component/Serializer/Exception/ExceptionInterface.php b/src/Symfony/Component/Serializer/Exception/ExceptionInterface.php
index 859dcb4618..99ed63246c 100644
--- a/src/Symfony/Component/Serializer/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Serializer/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Serializer\Exception;
*
* @author Johannes M. Schmitt
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
index eb66d6540d..121e01530d 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
@@ -349,6 +349,12 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
}
} elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) {
$parameterData = $data[$key];
+ if (null === $parameterData && $constructorParameter->allowsNull()) {
+ $params[] = null;
+ // Don't run set for a parameter passed to the constructor
+ unset($data[$key]);
+ continue;
+ }
try {
if (null !== $constructorParameter->getClass()) {
if (!$this->serializer instanceof DenormalizerInterface) {
diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/NullableConstructorArgumentDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/NullableConstructorArgumentDummy.php
new file mode 100644
index 0000000000..616fab4ae8
--- /dev/null
+++ b/src/Symfony/Component/Serializer/Tests/Fixtures/NullableConstructorArgumentDummy.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Serializer\Tests\Fixtures;
+
+class NullableConstructorArgumentDummy
+{
+ private $foo;
+
+ public function __construct(?\stdClass $foo)
+ {
+ $this->foo = $foo;
+ }
+
+ public function setFoo($foo)
+ {
+ $this->foo = 'this setter should not be called when using the constructor argument';
+ }
+
+ public function getFoo()
+ {
+ return $this->foo;
+ }
+}
diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php
index e07fb56bf5..28edc05872 100644
--- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php
@@ -9,6 +9,7 @@ use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy;
+use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy;
use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy;
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy;
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer;
@@ -116,4 +117,15 @@ class AbstractNormalizerTest extends TestCase
$this->assertEquals('baz', $dummy->quz);
$this->assertNull($dummy->foo);
}
+
+ /**
+ * @requires PHP 7.1
+ */
+ public function testObjectWithNullableConstructorArgument()
+ {
+ $normalizer = new ObjectNormalizer();
+ $dummy = $normalizer->denormalize(array('foo' => null), NullableConstructorArgumentDummy::class);
+
+ $this->assertNull($dummy->getFoo());
+ }
}
diff --git a/src/Symfony/Component/Translation/Exception/ExceptionInterface.php b/src/Symfony/Component/Translation/Exception/ExceptionInterface.php
index 8f9c54ef7a..c85fb93ca8 100644
--- a/src/Symfony/Component/Translation/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Translation/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Translation\Exception;
*
* @author Fabien Potencier
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Validator/Exception/ExceptionInterface.php b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php
index 390e8c053f..77d09b9029 100644
--- a/src/Symfony/Component/Validator/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Validator\Exception;
*
* @author Bernhard Schussek
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Workflow/Exception/ExceptionInterface.php b/src/Symfony/Component/Workflow/Exception/ExceptionInterface.php
index 5298262674..b0dfa9b79b 100644
--- a/src/Symfony/Component/Workflow/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Workflow/Exception/ExceptionInterface.php
@@ -15,6 +15,6 @@ namespace Symfony\Component\Workflow\Exception;
* @author Fabien Potencier
* @author Grégoire Pineau
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/Yaml/Exception/ExceptionInterface.php b/src/Symfony/Component/Yaml/Exception/ExceptionInterface.php
index 909131684c..ad850eea1d 100644
--- a/src/Symfony/Component/Yaml/Exception/ExceptionInterface.php
+++ b/src/Symfony/Component/Yaml/Exception/ExceptionInterface.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Yaml\Exception;
*
* @author Fabien Potencier
*/
-interface ExceptionInterface extends \Throwable
+interface ExceptionInterface
{
}