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 { }