diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php index 2a1ae70a1a..b31817d76d 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php @@ -60,7 +60,6 @@ class HttpCodeActivationStrategy extends ErrorLevelActivationStrategy continue; } - $urlBlacklist = null; if (\count($exclusion['urls'])) { return !preg_match('{('.implode('|', $exclusion['urls']).')}i', $request->getPathInfo()); } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index b1849afde8..3335149d7f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -648,6 +648,7 @@ class Configuration implements ConfigurationInterface ->fixXmlConfig('package') ->children() ->arrayNode('packages') + ->normalizeKeys(false) ->useAttributeAsKey('name') ->prototype('array') ->fixXmlConfig('base_url') diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php index 22fed9921b..5debaae9d6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php @@ -58,7 +58,7 @@ class TranslatorHelper extends Helper */ public function transChoice($id, $number, array $parameters = [], $domain = 'messages', $locale = null) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%count%" parameter.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED); if (null === $this->translator) { return $this->doTrans($id, ['%count%' => $number] + $parameters, $domain, $locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index d8acb04909..2ddf9175f3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -101,6 +101,35 @@ class ConfigurationTest extends TestCase $this->assertEquals($defaultConfig, $config['assets']); } + /** + * @dataProvider provideValidAssetsPackageNameConfigurationTests + */ + public function testValidAssetsPackageNameConfiguration($packageName) + { + $processor = new Processor(); + $configuration = new Configuration(true); + $config = $processor->processConfiguration($configuration, [ + [ + 'assets' => [ + 'packages' => [ + $packageName => [], + ], + ], + ], + ]); + + $this->assertArrayHasKey($packageName, $config['assets']['packages']); + } + + public function provideValidAssetsPackageNameConfigurationTests() + { + return [ + ['foobar'], + ['foo-bar'], + ['foo_bar'], + ]; + } + /** * @dataProvider provideInvalidAssetConfigurationTests */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Author.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Author.php index efb0b43027..e54d37aacc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Author.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Author.php @@ -4,5 +4,5 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serialization; class Author { - public $gender; + public $eyeColor; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Person.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Person.php index 92e84fbfaf..1da3e02fa5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Person.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Person.php @@ -4,5 +4,5 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serialization; class Person { - public $gender; + public $eyeColor; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/author.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/author.yml index 1aa06e3153..a7f8f6fece 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/author.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/author.yml @@ -1,4 +1,4 @@ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serialization\Author: attributes: - gender: + eyeColor: groups: ['group1', 'group2'] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/person.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/person.xml index 89e36afbe4..24f63bf09f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/person.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serialization/Resources/person.xml @@ -5,7 +5,7 @@ http://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd" > - + group1 group2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Author.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Author.php index 2a6b48ab4e..b02ba30c24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Author.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Author.php @@ -4,5 +4,5 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation; class Author { - public $gender; + public $eyeColor; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Person.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Person.php index 104a4a524b..b8543ba442 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Person.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Person.php @@ -4,5 +4,5 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation; class Person { - public $gender; + public $eyeColor; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/author.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/author.yml index fb03191d7d..62d42b288a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/author.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/author.yml @@ -1,4 +1,4 @@ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation\Author: properties: - gender: - - Choice: { choices: [male, female, other], message: Choose a valid gender. } + eyeColor: + - Choice: { choices: [brown, green, blue], message: Choose a valid eye color. } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/person.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/person.xml index f58be2dc6c..f3adc3c90f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/person.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Resources/person.xml @@ -4,14 +4,14 @@ xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> - + - + diff --git a/src/Symfony/Component/Form/FormRenderer.php b/src/Symfony/Component/Form/FormRenderer.php index b3a199775a..4b3866fe1c 100644 --- a/src/Symfony/Component/Form/FormRenderer.php +++ b/src/Symfony/Component/Form/FormRenderer.php @@ -163,9 +163,9 @@ class FormRenderer implements FormRendererInterface // to implement a custom "choice_widget" block (no matter in which theme), // or to fallback to the block of the parent type, which would be // "form_widget" in this example (again, no matter in which theme). - // If the designer wants to explicitly fallback to "form_widget" in his - // custom "choice_widget", for example because he only wants to wrap - // a
around the original implementation, he can simply call the + // If the designer wants to explicitly fallback to "form_widget" in their + // custom "choice_widget", for example because they only want to wrap + // a
around the original implementation, they can simply call the // widget() function again to render the block for the parent type. // // The second kind is implemented in the following blocks. diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php index 1873a58f0d..6c09ba8ead 100644 --- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php @@ -470,7 +470,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest // Insert the start tag, the end tag should be rendered by the helper // Unfortunately this is not valid HTML, because the surrounding table // tag is missing. If someone renders a form with table layout - // manually, she should call form_rest() explicitly within the + // manually, they should call form_rest() explicitly within the
// tag. $this->assertMatchesXpath(''.$html, '/form diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 222173ec00..ab0dcf6818 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -783,14 +783,14 @@ class RequestTest extends TestCase // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded). // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. - ['him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'], + ['baz=Foo%20Baz&bar=Foo+Bar', 'bar=Foo%20Bar&baz=Foo%20Baz', 'normalizes spaces in both encodings "%20" and "+"'], ['foo[]=1&foo[]=2', 'foo%5B0%5D=1&foo%5B1%5D=2', 'allows array notation'], ['foo=1&foo=2', 'foo=2', 'merges repeated parameters'], ['pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'], ['0', '0=', 'allows "0"'], - ['Jane Doe&John%20Doe', 'Jane_Doe=&John_Doe=', 'normalizes encoding in keys'], - ['her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'], + ['Foo Bar&Foo%20Baz', 'Foo_Bar=&Foo_Baz=', 'normalizes encoding in keys'], + ['bar=Foo Bar&baz=Foo%20Baz', 'bar=Foo%20Bar&baz=Foo%20Baz', 'normalizes encoding in values'], ['foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'], ['formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'], diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php index 2ad68d3a3d..0e790a72dd 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherTrait.php @@ -135,21 +135,16 @@ trait CompiledUrlMatcherTrait } } - if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) { - // no-op - } elseif (preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) { - $matches = $n; - } else { - $hasTrailingSlash = true; - } - - if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) { + $hasTrailingVar = $trimmedPathinfo !== $pathinfo && $hasTrailingVar; + if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) { if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) { return $allow = $allowSchemes = []; } - if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) { - continue; - } + continue; + } + + if ($hasTrailingSlash && $hasTrailingVar && preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) { + $matches = $n; } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 6fb750340c..318a141985 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -156,21 +156,18 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface continue; } - if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar = preg_match('#\{\w+\}/?$#', $route->getPath())) { - // no-op - } elseif (preg_match($regex, $trimmedPathinfo, $m)) { - $matches = $m; - } else { - $hasTrailingSlash = true; - } + $hasTrailingVar = $trimmedPathinfo !== $pathinfo && preg_match('#\{\w+\}/?$#', $route->getPath()); - if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) { + if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) { if ($supportsTrailingSlash && (!$requiredMethods || \in_array('GET', $requiredMethods))) { return $this->allow = $this->allowSchemes = []; } - if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) { - continue; - } + + continue; + } + + if ($hasTrailingSlash && $hasTrailingVar && preg_match($regex, $trimmedPathinfo, $m)) { + $matches = $m; } $hostMatches = []; diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 1657833982..dd7e7b1b41 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -731,12 +731,12 @@ class UrlMatcherTest extends TestCase $this->assertSame(['_route' => 'b'], $matcher->match('/bar/')); $coll = new RouteCollection(); - $coll->add('a', new Route('/dav/{foo<.*>?}', [], [], [], '', [], ['GET', 'OPTIONS'])); + $coll->add('a', new Route('/dav/{foo}', [], ['foo' => '.*'], [], '', [], ['GET', 'OPTIONS'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'OPTIONS')); $expected = [ '_route' => 'a', - 'foo' => 'files/bar', + 'foo' => 'files/bar/', ]; $this->assertEquals($expected, $matcher->match('/dav/files/bar/')); } @@ -766,6 +766,17 @@ class UrlMatcherTest extends TestCase $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); } + public function testGreedyTrailingRequirement() + { + $coll = new RouteCollection(); + $coll->add('a', new Route('/{a}', [], ['a' => '.+'])); + + $matcher = $this->getUrlMatcher($coll); + + $this->assertEquals(['_route' => 'a', 'a' => 'foo'], $matcher->match('/foo')); + $this->assertEquals(['_route' => 'a', 'a' => 'foo/'], $matcher->match('/foo/')); + } + protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new UrlMatcher($routes, $context ?: new RequestContext()); diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index ad718a23d3..e8546788d5 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -136,14 +136,9 @@ abstract class AbstractToken implements TokenInterface */ public function serialize() { - return serialize( - [ - \is_object($this->user) ? clone $this->user : $this->user, - $this->authenticated, - array_map(function ($role) { return clone $role; }, $this->roles), - $this->attributes, - ] - ); + $serialized = [$this->user, $this->authenticated, $this->roles, $this->attributes]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -151,7 +146,7 @@ abstract class AbstractToken implements TokenInterface */ public function unserialize($serialized) { - list($this->user, $this->authenticated, $this->roles, $this->attributes) = unserialize($serialized); + list($this->user, $this->authenticated, $this->roles, $this->attributes) = \is_array($serialized) ? $serialized : unserialize($serialized); } /** @@ -231,6 +226,19 @@ abstract class AbstractToken implements TokenInterface return sprintf('%s(user="%s", authenticated=%s, roles="%s")', $class, $this->getUsername(), json_encode($this->authenticated), implode(', ', $roles)); } + /** + * @internal + */ + protected function doSerialize($serialized, $isCalledFromOverridingMethod) + { + if (null === $isCalledFromOverridingMethod) { + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); + $isCalledFromOverridingMethod = isset($trace[2]['function'], $trace[2]['object']) && 'serialize' === $trace[2]['function'] && $this === $trace[2]['object']; + } + + return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); + } + private function hasUserChanged(UserInterface $user) { if (!($this->user instanceof UserInterface)) { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php index 59688ba26c..328d3043d2 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php @@ -59,7 +59,9 @@ class AnonymousToken extends AbstractToken */ public function serialize() { - return serialize([$this->secret, parent::serialize()]); + $serialized = [$this->secret, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -67,7 +69,7 @@ class AnonymousToken extends AbstractToken */ public function unserialize($serialized) { - list($this->secret, $parentStr) = unserialize($serialized); + list($this->secret, $parentStr) = \is_array($serialized) ? $serialized : unserialize($serialized); parent::unserialize($parentStr); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php index ede09cb3f7..bc6c0ce522 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php @@ -79,7 +79,9 @@ class PreAuthenticatedToken extends AbstractToken */ public function serialize() { - return serialize([$this->credentials, $this->providerKey, parent::serialize()]); + $serialized = [$this->credentials, $this->providerKey, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -87,7 +89,7 @@ class PreAuthenticatedToken extends AbstractToken */ public function unserialize($str) { - list($this->credentials, $this->providerKey, $parentStr) = unserialize($str); + list($this->credentials, $this->providerKey, $parentStr) = \is_array($str) ? $str : unserialize($str); parent::unserialize($parentStr); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php index 39c03d13d4..21a190d6b3 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php @@ -94,11 +94,9 @@ class RememberMeToken extends AbstractToken */ public function serialize() { - return serialize([ - $this->secret, - $this->providerKey, - parent::serialize(), - ]); + $serialized = [$this->secret, $this->providerKey, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -106,7 +104,7 @@ class RememberMeToken extends AbstractToken */ public function unserialize($serialized) { - list($this->secret, $this->providerKey, $parentStr) = unserialize($serialized); + list($this->secret, $this->providerKey, $parentStr) = \is_array($serialized) ? $serialized : unserialize($serialized); parent::unserialize($parentStr); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php index c1e95d479e..8a70047a48 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php @@ -91,7 +91,9 @@ class UsernamePasswordToken extends AbstractToken */ public function serialize() { - return serialize([$this->credentials, $this->providerKey, parent::serialize()]); + $serialized = [$this->credentials, $this->providerKey, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -99,7 +101,7 @@ class UsernamePasswordToken extends AbstractToken */ public function unserialize($serialized) { - list($this->credentials, $this->providerKey, $parentStr) = unserialize($serialized); + list($this->credentials, $this->providerKey, $parentStr) = \is_array($serialized) ? $serialized : unserialize($serialized); parent::unserialize($parentStr); } } diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index 503d3fbad4..cb91b42364 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -44,10 +44,9 @@ abstract class AccountStatusException extends AuthenticationException */ public function serialize() { - return serialize([ - $this->user, - parent::serialize(), - ]); + $serialized = [$this->user, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -55,7 +54,7 @@ abstract class AccountStatusException extends AuthenticationException */ public function unserialize($str) { - list($this->user, $parentData) = unserialize($str); + list($this->user, $parentData) = \is_array($str) ? $str : unserialize($str); parent::unserialize($parentData); } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index d7fb6b88f3..a8989c0687 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -38,15 +38,33 @@ class AuthenticationException extends RuntimeException implements \Serializable $this->token = $token; } + /** + * {@inheritdoc} + */ public function serialize() { - return serialize([ + $serialized = [ $this->token, $this->code, $this->message, $this->file, $this->line, - ]); + ]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); + } + + /** + * @internal + */ + protected function doSerialize($serialized, $isCalledFromOverridingMethod) + { + if (null === $isCalledFromOverridingMethod) { + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); + $isCalledFromOverridingMethod = isset($trace[2]['function'], $trace[2]['object']) && 'serialize' === $trace[2]['function'] && $this === $trace[2]['object']; + } + + return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); } public function unserialize($str) @@ -57,7 +75,7 @@ class AuthenticationException extends RuntimeException implements \Serializable $this->message, $this->file, $this->line - ) = unserialize($str); + ) = \is_array($str) ? $str : unserialize($str); } /** diff --git a/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php index bc9d88e43a..505dd2c735 100644 --- a/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php @@ -60,11 +60,9 @@ class CustomUserMessageAuthenticationException extends AuthenticationException */ public function serialize() { - return serialize([ - parent::serialize(), - $this->messageKey, - $this->messageData, - ]); + return serialize([parent::serialize(true), $this->messageKey, $this->messageData]); + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -72,7 +70,7 @@ class CustomUserMessageAuthenticationException extends AuthenticationException */ public function unserialize($str) { - list($parentData, $this->messageKey, $this->messageData) = unserialize($str); + list($parentData, $this->messageKey, $this->messageData) = \is_array($str) ? $str : unserialize($str); parent::unserialize($parentData); } diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 6549307eee..b4b8047f34 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -54,10 +54,9 @@ class UsernameNotFoundException extends AuthenticationException */ public function serialize() { - return serialize([ - $this->username, - parent::serialize(), - ]); + $serialized = [$this->username, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -65,7 +64,7 @@ class UsernameNotFoundException extends AuthenticationException */ public function unserialize($str) { - list($this->username, $parentData) = unserialize($str); + list($this->username, $parentData) = \is_array($str) ? $str : unserialize($str); parent::unserialize($parentData); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 0c50061513..066ca6892c 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -43,9 +43,14 @@ class ConcreteToken extends AbstractToken $this->setUser($user); } + /** + * {@inheritdoc} + */ public function serialize() { - return serialize([$this->credentials, parent::serialize()]); + $serialized = [$this->credentials, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } public function unserialize($serialized) diff --git a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php index ebf94384c0..d69d3bffcb 100644 --- a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Tests\Exception; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; class CustomUserMessageAuthenticationExceptionTest extends TestCase @@ -24,4 +25,18 @@ class CustomUserMessageAuthenticationExceptionTest extends TestCase $this->assertEquals(['foo' => true], $e->getMessageData()); $this->assertEquals('SAFE MESSAGE', $e->getMessage()); } + + public function testSharedSerializedData() + { + $token = new AnonymousToken('foo', 'bar'); + + $exception = new CustomUserMessageAuthenticationException(); + $exception->setToken($token); + $exception->setSafeMessage('message', ['token' => $token]); + + $processed = unserialize(serialize($exception)); + $this->assertEquals($token, $processed->getToken()); + $this->assertEquals($token, $processed->getMessageData()['token']); + $this->assertSame($processed->getToken(), $processed->getMessageData()['token']); + } } diff --git a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php index 55ffbbf71d..1e75129c57 100644 --- a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php +++ b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php @@ -76,7 +76,9 @@ class PostAuthenticationGuardToken extends AbstractToken implements GuardTokenIn */ public function serialize() { - return serialize([$this->providerKey, parent::serialize()]); + $serialized = [$this->providerKey, parent::serialize(true)]; + + return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); } /** @@ -84,7 +86,7 @@ class PostAuthenticationGuardToken extends AbstractToken implements GuardTokenIn */ public function unserialize($serialized) { - list($this->providerKey, $parentStr) = unserialize($serialized); + list($this->providerKey, $parentStr) = \is_array($serialized) ? $serialized : unserialize($serialized); parent::unserialize($parentStr); } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 53b7f7b691..74692783ea 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -193,11 +193,11 @@ XML; { $array = [ '#' => 'Paul', - '@gender' => 'm', + '@eye-color' => 'brown', ]; $expected = ''."\n". - 'Paul'."\n"; + 'Paul'."\n"; $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); } @@ -206,11 +206,11 @@ XML; { $array = [ 'firstname' => 'Paul', - '@gender' => 'm', + '@eye-color' => 'brown', ]; $expected = ''."\n". - 'Paul'."\n"; + 'Paul'."\n"; $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); } @@ -230,11 +230,11 @@ XML; public function testEncodeScalarWithAttribute() { $array = [ - 'person' => ['@gender' => 'M', '#' => 'Peter'], + 'person' => ['@eye-color' => 'brown', '#' => 'Peter'], ]; $expected = ''."\n". - 'Peter'."\n"; + 'Peter'."\n"; $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); } @@ -333,11 +333,11 @@ XML; $this->encoder->setSerializer($serializer); $array = [ - 'person' => ['@gender' => 'M', '#' => 'Peter'], + 'person' => ['@eye-color' => 'brown', '#' => 'Peter'], ]; $expected = ''."\n". - 'Peter'."\n"; + 'Peter'."\n"; $this->assertEquals($expected, $serializer->serialize($array, 'xml', $options)); } @@ -401,10 +401,10 @@ XML; public function testDecodeScalarWithAttribute() { $source = ''."\n". - 'Peter'."\n"; + 'Peter'."\n"; $expected = [ - 'person' => ['@gender' => 'M', '#' => 'Peter'], + 'person' => ['@eye-color' => 'brown', '#' => 'Peter'], ]; $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); @@ -413,11 +413,11 @@ XML; public function testDecodeScalarRootAttributes() { $source = ''."\n". - 'Peter'."\n"; + 'Peter'."\n"; $expected = [ '#' => 'Peter', - '@gender' => 'M', + '@eye-color' => 'brown', ]; $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); @@ -426,12 +426,12 @@ XML; public function testDecodeRootAttributes() { $source = ''."\n". - 'PeterMac Calloway'."\n"; + 'PeterMac Calloway'."\n"; $expected = [ 'firstname' => 'Peter', 'lastname' => 'Mac Calloway', - '@gender' => 'M', + '@eye-color' => 'brown', ]; $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); diff --git a/src/Symfony/Component/Translation/IdentityTranslator.php b/src/Symfony/Component/Translation/IdentityTranslator.php index 41807af04a..b15792a9b5 100644 --- a/src/Symfony/Component/Translation/IdentityTranslator.php +++ b/src/Symfony/Component/Translation/IdentityTranslator.php @@ -34,7 +34,7 @@ class IdentityTranslator implements LegacyTranslatorInterface, TranslatorInterfa $this->selector = $selector; if (__CLASS__ !== \get_class($this)) { - @trigger_error(sprintf('Calling "%s()" is deprecated since Symfony 4.2.'), E_USER_DEPRECATED); + @trigger_error(sprintf('Calling "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); } } @@ -45,7 +45,7 @@ class IdentityTranslator implements LegacyTranslatorInterface, TranslatorInterfa */ public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%count%" parameter.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED); if ($this->selector) { return strtr($this->selector->choose((string) $id, $number, $locale ?: $this->getLocale()), $parameters); diff --git a/src/Symfony/Component/Translation/LoggingTranslator.php b/src/Symfony/Component/Translation/LoggingTranslator.php index 62314b309d..d6b711d27e 100644 --- a/src/Symfony/Component/Translation/LoggingTranslator.php +++ b/src/Symfony/Component/Translation/LoggingTranslator.php @@ -64,7 +64,7 @@ class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterfac */ public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%count%" parameter.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED); if ($this->translator instanceof TranslatorInterface) { $trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale); diff --git a/src/Symfony/Component/VarDumper/Caster/IntlCaster.php b/src/Symfony/Component/VarDumper/Caster/IntlCaster.php index 7794d6cbcc..31d5cb395f 100644 --- a/src/Symfony/Component/VarDumper/Caster/IntlCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/IntlCaster.php @@ -132,7 +132,6 @@ class IntlCaster Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(), Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(), Caster::PREFIX_VIRTUAL.'time' => $c->getTime(), - Caster::PREFIX_VIRTUAL.'type' => $c->getType(), Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(), Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(), Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 03502bbd8f..37651816e6 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -500,12 +500,17 @@ return function (root, x) { function showCurrent(state) { - var currentNode = state.current(); + var currentNode = state.current(), currentRect, searchRect; if (currentNode) { reveal(currentNode); highlight(root, currentNode, state.nodes); if ('scrollIntoView' in currentNode) { - currentNode.scrollIntoView(); + currentNode.scrollIntoView(true); + currentRect = currentNode.getBoundingClientRect(); + searchRect = search.getBoundingClientRect(); + if (currentRect.top < (searchRect.top + searchRect.height)) { + window.scrollBy(0, -(searchRect.top + searchRect.height + 5)); + } } } counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count(); @@ -641,6 +646,7 @@ pre.sf-dump { display: block; white-space: pre; padding: 5px; + overflow: initial !important; } pre.sf-dump:after { content: ""; @@ -709,14 +715,16 @@ pre.sf-dump code { border-radius: 3px; } pre.sf-dump .sf-dump-search-hidden { - display: none; + display: none !important; } pre.sf-dump .sf-dump-search-wrapper { - float: right; font-size: 0; white-space: nowrap; - max-width: 100%; - text-align: right; + margin-bottom: 5px; + display: flex; + position: -webkit-sticky; + position: sticky; + top: 5px; } pre.sf-dump .sf-dump-search-wrapper > * { vertical-align: top; @@ -733,10 +741,11 @@ pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input { height: 21px; font-size: 12px; border-right: none; - width: 140px; border-top-left-radius: 3px; border-bottom-left-radius: 3px; color: #000; + min-width: 15px; + width: 100%; } pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next, pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous { diff --git a/src/Symfony/Component/VarDumper/Server/Connection.php b/src/Symfony/Component/VarDumper/Server/Connection.php index 853bf00c22..8b814cb61c 100644 --- a/src/Symfony/Component/VarDumper/Server/Connection.php +++ b/src/Symfony/Component/VarDumper/Server/Connection.php @@ -91,7 +91,5 @@ class Connection } finally { restore_error_handler(); } - - return $socket; } }