diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index f97dcf24a9..4bfd773970 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -213,7 +213,7 @@ abstract class DoctrineType extends AbstractType implements ResetInterface // for equal query builders $queryBuilderNormalizer = function (Options $options, $queryBuilder) { if (\is_callable($queryBuilder)) { - $queryBuilder = \call_user_func($queryBuilder, $options['em']->getRepository($options['class'])); + $queryBuilder = $queryBuilder($options['em']->getRepository($options['class'])); } return $queryBuilder; diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php index fa4176ee18..2adb82fad3 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php @@ -29,7 +29,7 @@ class EntityType extends DoctrineType // for equal query builders $queryBuilderNormalizer = function (Options $options, $queryBuilder) { if (\is_callable($queryBuilder)) { - $queryBuilder = \call_user_func($queryBuilder, $options['em']->getRepository($options['class'])); + $queryBuilder = $queryBuilder($options['em']->getRepository($options['class'])); if (null !== $queryBuilder && !$queryBuilder instanceof QueryBuilder) { throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); diff --git a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php index 6c21a335f0..4c454f1770 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php @@ -102,7 +102,7 @@ class ServerLogHandler extends AbstractHandler { if ($this->processors) { foreach ($this->processors as $processor) { - $record = \call_user_func($processor, $record); + $record = $processor($record); } } diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php index cc68d65058..7b6ce56b0f 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php @@ -43,7 +43,7 @@ class RuntimeInstantiator implements InstantiatorInterface return $this->factory->createProxy( $this->factory->getGenerator()->getProxifiedClass($definition), function (&$wrappedInstance, LazyLoadingInterface $proxy) use ($realInstantiator) { - $wrappedInstance = \call_user_func($realInstantiator); + $wrappedInstance = $realInstantiator(); $proxy->setProxyInitializer(null); diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 32e78d41a1..bbe4bb9cb0 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -28,7 +28,7 @@ {%- endblock form_widget_compound -%} {%- block collection_widget -%} - {% if prototype is defined %} + {% if prototype is defined and not prototype.rendered %} {%- set attr = attr|merge({'data-prototype': form_row(prototype) }) -%} {% endif %} {{- block('form_widget') -}} diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 90cd0e5254..3938a5dc11 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -57,7 +57,7 @@ class TextDescriptor extends Descriptor if ($showControllers) { $controller = $route->getDefault('_controller'); - $row[] = $this->formatCallable($controller); + $row[] = $controller ? $this->formatCallable($controller) : ''; } $tableRows[] = $row; diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index 94a53b87bf..5143dfd173 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -15,7 +15,6 @@ use Doctrine\Common\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -27,6 +26,7 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Templating\EngineInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; use Twig\Environment; /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 46fd22ca7a..8ad78f9f85 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -50,7 +50,7 @@ class RedirectController * @param string $route The route name to redirect to * @param bool $permanent Whether the redirection is permanent * @param bool|array $ignoreAttributes Whether to ignore attributes or an array of attributes to ignore - * @param bool $keepRequestMethod Wheter redirect action should keep HTTP request method + * @param bool $keepRequestMethod Whether redirect action should keep HTTP request method * * @throws HttpException In case the route name is empty */ @@ -94,7 +94,7 @@ class RedirectController * @param string|null $scheme The URL scheme (null to keep the current one) * @param int|null $httpPort The HTTP port (null to keep the current one for the same scheme or the default configured port) * @param int|null $httpsPort The HTTPS port (null to keep the current one for the same scheme or the default configured port) - * @param bool $keepRequestMethod Wheter redirect action should keep HTTP request method + * @param bool $keepRequestMethod Whether redirect action should keep HTTP request method * * @throws HttpException In case the path is empty */ diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 9d0988a833..a67873bb79 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -37,7 +37,6 @@ use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -1602,12 +1601,7 @@ class FrameworkExtension extends Extension $senders[$sender] = new Reference($senderAliases[$sender] ?? $sender); } - $sendersId = 'messenger.senders.'.$message; - $container->register($sendersId, RewindableGenerator::class) - ->setFactory('current') - ->addArgument(array(new IteratorArgument($senders))); - $messageToSendersMapping[$message] = new Reference($sendersId); - + $messageToSendersMapping[$message] = new IteratorArgument($senders); $messagesToSendAndHandle[$message] = $messageConfiguration['send_and_handle']; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index e52b2c7c2e..4a959568f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -651,10 +651,11 @@ abstract class FrameworkExtensionTest extends TestCase ); $this->assertSame($messageToSendAndHandleMapping, $senderLocatorDefinition->getArgument(1)); + $sendersMapping = $senderLocatorDefinition->getArgument(0); $this->assertEquals(array( 'amqp' => new Reference('messenger.transport.amqp'), 'audit' => new Reference('audit'), - ), $container->getDefinition('messenger.senders.'.DummyMessage::class)->getArgument(0)[0]->getValues()); + ), $sendersMapping[DummyMessage::class]->getValues()); } /** diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig index a2091e85aa..6bdfb8839c 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig @@ -1,7 +1,7 @@ {# This file is based on WebProfilerBundle/Resources/views/Profiler/profiler.css.twig. If you make any change in this file, verify the same change is needed in the other file. #} :root { - --font-sans-serif: 'Helvetica, Arial, sans-serif'; + --font-sans-serif: Helvetica, Arial, sans-serif; --page-background: #f9f9f9; --color-text: #222; /* when updating any of these colors, do the same in toolbar.css.twig */ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index dd5b970148..6fdcc77a0e 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -6,7 +6,7 @@ *{-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0} :root { - --font-sans-serif: 'Helvetica, Arial, sans-serif'; + --font-sans-serif: Helvetica, Arial, sans-serif; --page-background: #f9f9f9; --color-text: #222; --color-muted: #999; @@ -42,7 +42,7 @@ .theme-dark { --page-background: #36393e; --color-text: #e0e0e0; - --color-muted: #999; + --color-muted: #777; --tab-background: #555; --tab-color: #ccc; --tab-active-background: #888; @@ -59,7 +59,6 @@ --table-header: #555; --shadow: 0px 0px 1px rgba(32, 32, 32, .2); --border: 1px solid #666; - --color-muted: #777; --base-0: #2e3136; --base-1: #444; --base-2: #666; @@ -80,7 +79,7 @@ body { color: var(--base-6); display: flex; flex-direction: column; - font_family: var(--font-sans-serif); + font-family: var(--font-sans-serif); font-size: 14px; line-height: 1.4; } @@ -157,7 +156,7 @@ code, pre { {# Buttons (the colors of this element don't change based on the selected theme) ------------------------------------------------------------------------- #} button { - font_family: var(--font-sans-serif); + font-family: var(--font-sans-serif); } .btn { background: #777; @@ -296,7 +295,7 @@ table tbody td.num-col { text-align: center; } .font-normal { - font_family: var(--font-sans-serif); + font-family: var(--font-sans-serif); font-size: 14px; } .help { @@ -1158,7 +1157,7 @@ pre.sf-dump, pre.sf-dump .sf-dump-default { {# Search Results page ========================================================================= #} #search-results td { - font_family: var(--font-sans-serif); + font-family: var(--font-sans-serif); vertical-align: middle; } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index 96e63e64e3..1a6898de58 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -146,13 +146,13 @@ class PhpArrayAdapterWrapper extends PhpArrayAdapter public function save(CacheItemInterface $item) { - \call_user_func(\Closure::bind(function () use ($item) { + (\Closure::bind(function () use ($item) { $key = $item->getKey(); $this->keys[$key] = $id = \count($this->values); $this->data[$key] = $this->values[$id] = $item->get(); $this->warmUp($this->data); list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayAdapter::class)); + }, $this, PhpArrayAdapter::class))(); return true; } diff --git a/src/Symfony/Component/Cache/Tests/CacheItemTest.php b/src/Symfony/Component/Cache/Tests/CacheItemTest.php index 6049f3ec9b..395c003bd3 100644 --- a/src/Symfony/Component/Cache/Tests/CacheItemTest.php +++ b/src/Symfony/Component/Cache/Tests/CacheItemTest.php @@ -62,9 +62,9 @@ class CacheItemTest extends TestCase $this->assertSame($item, $item->tag('foo')); $this->assertSame($item, $item->tag(array('bar', 'baz'))); - \call_user_func(\Closure::bind(function () use ($item) { + (\Closure::bind(function () use ($item) { $this->assertSame(array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'), $item->newMetadata[CacheItem::METADATA_TAGS]); - }, $this, CacheItem::class)); + }, $this, CacheItem::class))(); } /** diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php index e0c7285802..724744cb9a 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php @@ -134,11 +134,11 @@ class PhpArrayCacheWrapper extends PhpArrayCache public function set($key, $value, $ttl = null) { - \call_user_func(\Closure::bind(function () use ($key, $value) { + (\Closure::bind(function () use ($key, $value) { $this->data[$key] = $value; $this->warmUp($this->data); list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class)); + }, $this, PhpArrayCache::class))(); return true; } @@ -148,13 +148,13 @@ class PhpArrayCacheWrapper extends PhpArrayCache if (!\is_array($values) && !$values instanceof \Traversable) { return parent::setMultiple($values, $ttl); } - \call_user_func(\Closure::bind(function () use ($values) { + (\Closure::bind(function () use ($values) { foreach ($values as $key => $value) { $this->data[$key] = $value; } $this->warmUp($this->data); list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class)); + }, $this, PhpArrayCache::class))(); return true; } diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index dc9d9590be..a7224d216f 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -96,7 +96,7 @@ trait RedisTrait return 'file:'.($m[1] ?? ''); }, $dsn); - if (false === $params = parse_url($dsn)) { + if (false === $params = parse_url($params)) { throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn)); } diff --git a/src/Symfony/Component/Config/ConfigCacheFactory.php b/src/Symfony/Component/Config/ConfigCacheFactory.php index 1e71ea0fbf..bfb70cb2ce 100644 --- a/src/Symfony/Component/Config/ConfigCacheFactory.php +++ b/src/Symfony/Component/Config/ConfigCacheFactory.php @@ -43,7 +43,7 @@ class ConfigCacheFactory implements ConfigCacheFactoryInterface $cache = new ConfigCache($file, $this->debug); if (!$cache->isFresh()) { - \call_user_func($callback, $cache); + $callback($cache); } return $cache; diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index 3faf01cdda..cddea2dcd2 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -155,15 +155,15 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) { yield EventSubscriberInterface::class; - yield print_r(\call_user_func(array($class->name, 'getSubscribedEvents')), true); + yield print_r($class->name::getSubscribedEvents(), true); } if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) { yield LegacyServiceSubscriberInterface::class; - yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true); + yield print_r(array($class->name, 'getSubscribedServices')(), true); } elseif (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) { yield ServiceSubscriberInterface::class; - yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true); + yield print_r($class->name::getSubscribedServices(), true); } } } diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCacheFactory.php b/src/Symfony/Component/Config/ResourceCheckerConfigCacheFactory.php index 4f45a9153a..8d94a2921d 100644 --- a/src/Symfony/Component/Config/ResourceCheckerConfigCacheFactory.php +++ b/src/Symfony/Component/Config/ResourceCheckerConfigCacheFactory.php @@ -40,7 +40,7 @@ class ResourceCheckerConfigCacheFactory implements ConfigCacheFactoryInterface $cache = new ResourceCheckerConfigCache($file, $this->resourceCheckers); if (!$cache->isFresh()) { - \call_user_func($callback, $cache); + $callback($cache); } return $cache; diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index a2324ea3e3..b29e51e0f6 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -80,7 +80,7 @@ class XmlUtils $e = null; if (\is_callable($schemaOrCallable)) { try { - $valid = \call_user_func($schemaOrCallable, $dom, $internalErrors); + $valid = $schemaOrCallable($dom, $internalErrors); } catch (\Exception $e) { $valid = false; } diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 0e23847379..381c6a299d 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -250,7 +250,7 @@ class Command $input->validate(); if ($this->code) { - $statusCode = \call_user_func($this->code, $input, $output); + $statusCode = ($this->code)($input, $output); } else { $statusCode = $this->execute($input, $output); } diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php index e0720c134e..0eaa370321 100644 --- a/src/Symfony/Component/Console/Helper/ProcessHelper.php +++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php @@ -136,7 +136,7 @@ class ProcessHelper extends Helper $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); if (null !== $callback) { - \call_user_func($callback, $type, $buffer); + $callback($type, $buffer); } }; } diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 38452b06b8..bef87d2b6a 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -496,7 +496,7 @@ final class ProgressBar $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; $callback = function ($matches) { if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { - $text = \call_user_func($formatter, $this, $this->output); + $text = $formatter($this, $this->output); } elseif (isset($this->messages[$matches[1]])) { $text = $this->messages[$matches[1]]; } else { diff --git a/src/Symfony/Component/Console/Helper/ProgressIndicator.php b/src/Symfony/Component/Console/Helper/ProgressIndicator.php index fe516df030..4c12c326cb 100644 --- a/src/Symfony/Component/Console/Helper/ProgressIndicator.php +++ b/src/Symfony/Component/Console/Helper/ProgressIndicator.php @@ -196,7 +196,7 @@ class ProgressIndicator $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) { if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) { - return \call_user_func($formatter, $self); + return $formatter($self); } return $matches[0]; diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 53af6fe92d..59d3dab536 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -381,7 +381,7 @@ class QuestionHelper extends Helper } try { - return \call_user_func($question->getValidator(), $interviewer()); + return $question->getValidator()($interviewer()); } catch (RuntimeException $e) { throw $e; } catch (\Exception $error) { diff --git a/src/Symfony/Component/CssSelector/XPath/Translator.php b/src/Symfony/Component/CssSelector/XPath/Translator.php index 97e4dfba18..6426aeaba5 100644 --- a/src/Symfony/Component/CssSelector/XPath/Translator.php +++ b/src/Symfony/Component/CssSelector/XPath/Translator.php @@ -155,7 +155,7 @@ class Translator implements TranslatorInterface throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName())); } - return \call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this); + return $this->nodeTranslators[$node->getNodeName()]($node, $this); } /** @@ -167,7 +167,7 @@ class Translator implements TranslatorInterface throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner)); } - return \call_user_func($this->combinationTranslators[$combiner], $this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath)); + return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath)); } /** @@ -179,7 +179,7 @@ class Translator implements TranslatorInterface throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName())); } - return \call_user_func($this->functionTranslators[$function->getName()], $xpath, $function); + return $this->functionTranslators[$function->getName()]($xpath, $function); } /** @@ -191,7 +191,7 @@ class Translator implements TranslatorInterface throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass)); } - return \call_user_func($this->pseudoClassTranslators[$pseudoClass], $xpath); + return $this->pseudoClassTranslators[$pseudoClass]($xpath); } /** @@ -203,7 +203,7 @@ class Translator implements TranslatorInterface throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator)); } - return \call_user_func($this->attributeMatchingTranslators[$operator], $xpath, $attribute, $value); + return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value); } /** diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 6d5fc9c2c3..19e80af78f 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -151,7 +151,7 @@ class DebugClassLoader require $file; } } else { - \call_user_func($this->classLoader, $class); + ($this->classLoader)($class); $file = false; } } finally { @@ -218,7 +218,7 @@ class DebugClassLoader $len = 0; $ns = ''; } else { - $ns = \substr($class, 0, $len); + $ns = \str_replace('_', '\\', \substr($class, 0, $len)); } // Detect annotations on the class @@ -249,13 +249,13 @@ class DebugClassLoader if (!isset(self::$checkedClasses[$use])) { $this->checkClass($use); } - if (isset(self::$deprecated[$use]) && \strncmp($ns, $use, $len)) { + if (isset(self::$deprecated[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) { $type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait'); $verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses'); $deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]); } - if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) { + if (isset(self::$internal[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) { $deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class); } } diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index af38e64865..fec4bf03ba 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -562,7 +562,7 @@ class ErrorHandler $this->exceptionHandler = null; try { if (null !== $exceptionHandler) { - return \call_user_func($exceptionHandler, $exception); + return $exceptionHandler($exception); } $handlerException = $handlerException ?: $exception; } catch (\Throwable $handlerException) { diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 259fb54893..1076cf57ef 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -144,7 +144,7 @@ class ExceptionHandler $this->caughtBuffer = null; try { - \call_user_func($this->handler, $exception); + ($this->handler)($exception); $this->caughtLength = $caughtLength; } catch (\Exception $e) { if (!$caughtLength) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index c80871524e..e5fb5b212f 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -52,11 +52,11 @@ class PassConfig new ValidateEnvPlaceholdersPass(), new ResolveChildDefinitionsPass(), new ServiceLocatorTagPass(), + new RegisterServiceSubscribersPass(), new DecoratorServicePass(), new ResolveParameterPlaceHoldersPass(false), new ResolveFactoryClassPass(), new CheckDefinitionValidityPass(), - new RegisterServiceSubscribersPass(), new ResolveNamedArgumentsPass(), new AutowireRequiredMethodsPass(), new ResolveBindingsPass(), diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 0937d0c292..33de5bf21b 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1162,7 +1162,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', \get_class($service))); } - \call_user_func($callable, $service); + $callable($service); } return $service; diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php index 3b0b57ef0f..4d6a9f05a9 100644 --- a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php +++ b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php @@ -28,6 +28,6 @@ class RealServiceInstantiator implements InstantiatorInterface */ public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator) { - return \call_user_func($realInstantiator); + return $realInstantiator(); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php b/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php index 183cacc4d6..939dd7cb7c 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php @@ -35,7 +35,7 @@ class ClosureLoader extends Loader */ public function load($resource, $type = null) { - \call_user_func($resource, $this->container); + $resource($this->container); } /** diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ContainerBagInterface.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ContainerBagInterface.php index 6b0bd20011..1c1227a3e1 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/ContainerBagInterface.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ContainerBagInterface.php @@ -15,6 +15,8 @@ use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; /** + * ContainerBagInterface is the interface implemented by objects that manage service container parameters. + * * @author Nicolas Grekas */ interface ContainerBagInterface extends ContainerInterface diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php index 7386df0648..6a4e0fa4ac 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php @@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; /** - * ParameterBagInterface. + * ParameterBagInterface is the interface implemented by objects that manage service container parameters. * * @author Fabien Potencier */ diff --git a/src/Symfony/Component/DependencyInjection/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/ServiceLocator.php index 83c3b829c4..9261c6546f 100644 --- a/src/Symfony/Component/DependencyInjection/ServiceLocator.php +++ b/src/Symfony/Component/DependencyInjection/ServiceLocator.php @@ -86,39 +86,40 @@ class ServiceLocator implements PsrContainerInterface $class = isset($class[3]['object']) ? \get_class($class[3]['object']) : null; $externalId = $this->externalId ?: $class; - $msg = sprintf('Service "%s" not found: ', $id); + $msg = array(); + $msg[] = sprintf('Service "%s" not found:', $id); if (!$this->container) { $class = null; } elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) { - $msg .= 'even though it exists in the app\'s container, '; + $msg[] = 'even though it exists in the app\'s container,'; } else { try { $this->container->get($id); $class = null; } catch (ServiceNotFoundException $e) { if ($e->getAlternatives()) { - $msg .= sprintf(' did you mean %s? Anyway, ', $this->formatAlternatives($e->getAlternatives(), 'or')); + $msg[] = sprintf('did you mean %s? Anyway,', $this->formatAlternatives($e->getAlternatives(), 'or')); } else { $class = null; } } } if ($externalId) { - $msg .= sprintf('the container inside "%s" is a smaller service locator that %s', $externalId, $this->formatAlternatives()); + $msg[] = sprintf('the container inside "%s" is a smaller service locator that %s', $externalId, $this->formatAlternatives()); } else { - $msg .= sprintf('the current service locator %s', $this->formatAlternatives()); + $msg[] = sprintf('the current service locator %s', $this->formatAlternatives()); } if (!$class) { // no-op } elseif (is_subclass_of($class, ServiceSubscriberInterface::class)) { - $msg .= sprintf(' Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".', preg_replace('/([^\\\\]++\\\\)++/', '', $class)); + $msg[] = sprintf('Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".', preg_replace('/([^\\\\]++\\\\)++/', '', $class)); } else { - $msg .= 'Try using dependency injection instead.'; + $msg[] = 'Try using dependency injection instead.'; } - return new ServiceNotFoundException($id, end($this->loading) ?: null, null, array(), $msg); + return new ServiceNotFoundException($id, end($this->loading) ?: null, null, array(), implode(' ', $msg)); } private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index 1aa4572359..489cc866e4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; /** * This class tests the integration of the different compiler passes. @@ -120,6 +121,21 @@ class IntegrationTest extends TestCase $this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.'); } + public function testCanDecorateServiceSubscriber() + { + $container = new ContainerBuilder(); + $container->register(ServiceSubscriberStub::class) + ->addTag('container.service_subscriber') + ->setPublic(true); + + $container->register(DecoratedServiceSubscriber::class) + ->setDecoratedService(ServiceSubscriberStub::class); + + $container->compile(); + + $this->assertInstanceOf(DecoratedServiceSubscriber::class, $container->get(ServiceSubscriberStub::class)); + } + /** * @dataProvider getYamlCompileTests */ @@ -220,6 +236,18 @@ class IntegrationTest extends TestCase } } +class ServiceSubscriberStub implements ServiceSubscriberInterface +{ + public static function getSubscribedServices() + { + return array(); + } +} + +class DecoratedServiceSubscriber +{ +} + class IntegrationTestStub extends IntegrationTestStubParent { } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php index bf1af4d509..3b5c9bb009 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php @@ -61,6 +61,20 @@ class ServiceLocatorTest extends BaseServiceLocatorTest $subscriber->getFoo(); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException + * @expectedExceptionMessage Service "foo" not found: even though it exists in the app's container, the container inside "foo" is a smaller service locator that is empty... Try using dependency injection instead. + */ + public function testGetThrowsServiceNotFoundException() + { + $container = new Container(); + $container->set('foo', new \stdClass()); + + $locator = new ServiceLocator(array()); + $locator = $locator->withContext('foo', $container); + $locator->get('foo'); + } + public function testInvoke() { $locator = $this->getServiceLocator(array( diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 6f89c64bde..36dd13d9bb 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -110,7 +110,7 @@ class WrappedListener $e = $this->stopwatch->start($this->name, 'event_listener'); - \call_user_func($this->optimizedListener, $event, $eventName, $this->dispatcher ?: $dispatcher); + ($this->optimizedListener)($event, $eventName, $this->dispatcher ?: $dispatcher); if ($e->isStarted()) { $e->stop(); diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 1d7b2322bc..50c5fd5fa4 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -218,7 +218,7 @@ class EventDispatcher implements EventDispatcherInterface if ($event->isPropagationStopped()) { break; } - \call_user_func($listener, $event, $eventName, $this); + $listener($event, $eventName, $this); } } diff --git a/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php b/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php index 77bd3ac873..6359727d88 100644 --- a/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php @@ -51,7 +51,7 @@ class CustomFilterIterator extends \FilterIterator $fileinfo = $this->current(); foreach ($this->filters as $filter) { - if (false === \call_user_func($filter, $fileinfo)) { + if (false === $filter($fileinfo)) { return false; } } diff --git a/src/Symfony/Component/Finder/Iterator/SortableIterator.php b/src/Symfony/Component/Finder/Iterator/SortableIterator.php index 41a8bd1538..56bdcfb1a4 100644 --- a/src/Symfony/Component/Finder/Iterator/SortableIterator.php +++ b/src/Symfony/Component/Finder/Iterator/SortableIterator.php @@ -73,7 +73,7 @@ class SortableIterator implements \IteratorAggregate } elseif (self::SORT_BY_NONE === $sort) { $this->sort = $order; } elseif (\is_callable($sort)) { - $this->sort = $reverseOrder ? function ($a, $b) use ($sort) { return -\call_user_func($sort, $a, $b); } : $sort; + $this->sort = $reverseOrder ? function ($a, $b) use ($sort) { return -$sort($a, $b); } : $sort; } else { throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.'); } diff --git a/src/Symfony/Component/Form/CallbackTransformer.php b/src/Symfony/Component/Form/CallbackTransformer.php index 8155e4dca8..919efabd10 100644 --- a/src/Symfony/Component/Form/CallbackTransformer.php +++ b/src/Symfony/Component/Form/CallbackTransformer.php @@ -41,7 +41,7 @@ class CallbackTransformer implements DataTransformerInterface */ public function transform($data) { - return \call_user_func($this->transform, $data); + return ($this->transform)($data); } /** @@ -57,6 +57,6 @@ class CallbackTransformer implements DataTransformerInterface */ public function reverseTransform($data) { - return \call_user_func($this->reverseTransform, $data); + return ($this->reverseTransform)($data); } } diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index db18f68112..c77882e915 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -155,7 +155,7 @@ class ArrayChoiceList implements ChoiceListInterface $givenValues = array(); foreach ($choices as $i => $givenChoice) { - $givenValues[$i] = (string) \call_user_func($this->valueCallback, $givenChoice); + $givenValues[$i] = (string) ($this->valueCallback)($givenChoice); } return array_intersect($givenValues, array_keys($this->choices)); @@ -202,7 +202,7 @@ class ArrayChoiceList implements ChoiceListInterface continue; } - $choiceValue = (string) \call_user_func($value, $choice); + $choiceValue = (string) $value($choice); $choicesByValues[$choiceValue] = $choice; $keysByValues[$choiceValue] = $key; $structuredValues[$key] = $choiceValue; diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index 5dfe8fcd4d..d5d251a319 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -118,7 +118,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface // $value may be an integer or a string, since it's stored in the array // keys. We want to guarantee it's a string though. $key = $keys[$value]; - $nextIndex = \is_int($index) ? $index++ : \call_user_func($index, $choice, $key, $value); + $nextIndex = \is_int($index) ? $index++ : $index($choice, $key, $value); // BC normalize label to accept a false value if (null === $label) { @@ -127,7 +127,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface } elseif (false !== $label) { // If "choice_label" is set to false and "expanded" is true, the value false // should be passed on to the "label" option of the checkboxes/radio buttons - $dynamicLabel = \call_user_func($label, $choice, $key, $value); + $dynamicLabel = $label($choice, $key, $value); $label = false === $dynamicLabel ? false : (string) $dynamicLabel; } @@ -137,11 +137,11 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface $label, // The attributes may be a callable or a mapping from choice indices // to nested arrays - \is_callable($attr) ? \call_user_func($attr, $choice, $key, $value) : (isset($attr[$key]) ? $attr[$key] : array()) + \is_callable($attr) ? $attr($choice, $key, $value) : (isset($attr[$key]) ? $attr[$key] : array()) ); // $isPreferred may be null if no choices are preferred - if ($isPreferred && \call_user_func($isPreferred, $choice, $key, $value)) { + if ($isPreferred && $isPreferred($choice, $key, $value)) { $preferredViews[$nextIndex] = $view; } else { $otherViews[$nextIndex] = $view; @@ -200,7 +200,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { - $groupLabel = \call_user_func($groupBy, $choice, $keys[$value], $value); + $groupLabel = $groupBy($choice, $keys[$value], $value); if (null === $groupLabel) { // If the callable returns null, don't group the choice diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php index b2825051af..066aaf4f59 100644 --- a/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php +++ b/src/Symfony/Component/Form/ChoiceList/Loader/CallbackChoiceLoader.php @@ -46,7 +46,7 @@ class CallbackChoiceLoader implements ChoiceLoaderInterface return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(\call_user_func($this->callback), $value); + return $this->choiceList = new ArrayChoiceList(($this->callback)(), $value); } /** diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php index f0140814fa..687c0197ae 100644 --- a/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php +++ b/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php @@ -30,11 +30,6 @@ class IntlCallbackChoiceLoader extends CallbackChoiceLoader return array(); } - // If no callable is set, values are the same as choices - if (null === $value) { - return $values; - } - return $this->loadChoiceList($value)->getChoicesForValues($values); } diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php index c6983916d4..8e6867dbcf 100644 --- a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php +++ b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php @@ -135,7 +135,7 @@ class ResizeFormListener implements EventSubscriberInterface /** @var FormInterface $child */ foreach ($form as $name => $child) { $isNew = !isset($previousData[$name]); - $isEmpty = \is_callable($this->deleteEmpty) ? \call_user_func($this->deleteEmpty, $child->getData()) : $child->isEmpty(); + $isEmpty = \is_callable($this->deleteEmpty) ? ($this->deleteEmpty)($child->getData()) : $child->isEmpty(); // $isNew can only be true if allowAdd is true, so we don't // need to check allowAdd again diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index 29c67885a2..c3e381b7c6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -106,11 +106,6 @@ class CountryType extends AbstractType implements ChoiceLoaderInterface return array(); } - // If no callable is set, values are the same as choices - if (null === $value) { - return $values; - } - return $this->loadChoiceList($value)->getChoicesForValues($values); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php index c94ab69310..77ed33b237 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -106,11 +106,6 @@ class CurrencyType extends AbstractType implements ChoiceLoaderInterface return array(); } - // If no callable is set, values are the same as choices - if (null === $value) { - return $values; - } - return $this->loadChoiceList($value)->getChoicesForValues($values); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index 0391e700b9..4ddf80f151 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -106,11 +106,6 @@ class LanguageType extends AbstractType implements ChoiceLoaderInterface return array(); } - // If no callable is set, values are the same as choices - if (null === $value) { - return $values; - } - return $this->loadChoiceList($value)->getChoicesForValues($values); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 4b757813be..6516a692ec 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -106,11 +106,6 @@ class LocaleType extends AbstractType implements ChoiceLoaderInterface return array(); } - // If no callable is set, values are the same as choices - if (null === $value) { - return $values; - } - return $this->loadChoiceList($value)->getChoicesForValues($values); } diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 0a1297d3ab..bf90ac299a 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -73,7 +73,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface $form->submit(null, false); $form->addError(new FormError( - \call_user_func($form->getConfig()->getOption('upload_max_size_message')), + $form->getConfig()->getOption('upload_max_size_message')(), null, array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) )); diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 02f8237a46..000d681580 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -180,7 +180,7 @@ class FormValidator extends ConstraintValidator private static function resolveValidationGroups($groups, FormInterface $form) { if (!\is_string($groups) && \is_callable($groups)) { - $groups = \call_user_func($groups, $form); + $groups = $groups($form); } if ($groups instanceof GroupSequence) { diff --git a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php index 7b95f147d7..cbcc3e3e55 100644 --- a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php @@ -51,7 +51,7 @@ class ValidationListener implements EventSubscriberInterface $form = $event->getForm(); if ($form->isRoot()) { - // Validate the form in group "Default" + // Form groups are validated internally (FormValidator). Here we don't set groups as they are retrieved into the validator. foreach ($this->validator->validate($form) as $violation) { // Allow the "invalid" constraint to be put onto // non-synchronized forms diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php index 54f7db095d..f318f88e79 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php @@ -48,7 +48,7 @@ class UploadValidatorExtension extends AbstractTypeExtension $translationDomain = $this->translationDomain; $resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) { return function () use ($translator, $translationDomain, $message) { - return $translator->trans(\call_user_func($message), array(), $translationDomain); + return $translator->trans($message(), array(), $translationDomain); }; }); } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 26b966c72e..4afda4a207 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -532,11 +532,12 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac $submittedData = null; } elseif (is_scalar($submittedData)) { $submittedData = (string) $submittedData; - } elseif ($this->config->getOption('allow_file_upload')) { - // no-op - } elseif ($this->config->getRequestHandler()->isFileUpload($submittedData)) { + } elseif (!$this->config->getOption('allow_file_upload') && $this->config->getRequestHandler()->isFileUpload($submittedData)) { $submittedData = null; $this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, file upload given.'); + } elseif (\is_array($submittedData) && !$this->config->getCompound() && !$this->config->hasOption('multiple')) { + $submittedData = null; + $this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, array given.'); } $dispatcher = $this->config->getEventDispatcher(); diff --git a/src/Symfony/Component/Form/FormFactoryInterface.php b/src/Symfony/Component/Form/FormFactoryInterface.php index 7014cda159..e945a2eb31 100644 --- a/src/Symfony/Component/Form/FormFactoryInterface.php +++ b/src/Symfony/Component/Form/FormFactoryInterface.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Form; /** + * Allows creating a form based on a name, a class or a property. + * * @author Bernhard Schussek */ interface FormFactoryInterface diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 94210d51e8..13fdf9b2d6 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -78,7 +78,7 @@ class NativeRequestHandler implements RequestHandlerInterface $form->submit(null, false); $form->addError(new FormError( - \call_user_func($form->getConfig()->getOption('upload_max_size_message')), + $form->getConfig()->getOption('upload_max_size_message')(), null, array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) )); diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Loader/IntlCallbackChoiceLoaderTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Loader/IntlCallbackChoiceLoaderTest.php index 03e975dce1..12bfd74632 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Loader/IntlCallbackChoiceLoaderTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Loader/IntlCallbackChoiceLoaderTest.php @@ -84,6 +84,11 @@ class IntlCallbackChoiceLoaderTest extends TestCase ); } + public function testLoadChoicesForValuesDropsNonExistentChoices() + { + $this->assertSame(array(), self::$loader->loadChoicesForValues(array('foo'))); + } + public function testLoadValuesForChoicesLoadsChoiceListOnFirstCall() { $this->assertSame( diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index da527125ef..ddacc35572 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -1081,6 +1081,22 @@ class CompoundFormTest extends AbstractFormTest $this->assertFalse($submit->isSubmitted()); } + public function testArrayTransformationFailureOnSubmit() + { + $this->form->add($this->getBuilder('foo')->setCompound(false)->getForm()); + $this->form->add($this->getBuilder('bar', null, null, array('multiple' => false))->setCompound(false)->getForm()); + + $this->form->submit(array( + 'foo' => array('foo'), + 'bar' => array('bar'), + )); + + $this->assertNull($this->form->get('foo')->getData()); + $this->assertSame('Submitted data was expected to be text or number, array given.', $this->form->get('foo')->getTransformationFailure()->getMessage()); + + $this->assertSame(array('bar'), $this->form->get('bar')->getData()); + } + public function testFileUpload() { $reqHandler = new HttpFoundationRequestHandler(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php index 249f9f918f..05ccd053fb 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\CountryType; use Symfony\Component\Intl\Util\IntlTestHelper; class CountryTypeTest extends BaseTypeTest @@ -80,4 +81,14 @@ class CountryTypeTest extends BaseTypeTest { parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData); } + + /** + * @group legacy + */ + public function testInvalidChoiceValuesAreDropped() + { + $type = new CountryType(); + + $this->assertSame(array(), $type->loadChoicesForValues(array('foo'))); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php index 1a98906fbb..a0f433677c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\CurrencyType; use Symfony\Component\Intl\Util\IntlTestHelper; class CurrencyTypeTest extends BaseTypeTest @@ -61,4 +62,14 @@ class CurrencyTypeTest extends BaseTypeTest { parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData); } + + /** + * @group legacy + */ + public function testInvalidChoiceValuesAreDropped() + { + $type = new CurrencyType(); + + $this->assertSame(array(), $type->loadChoicesForValues(array('foo'))); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php index 7b8e67f626..76e6685d5d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\LanguageType; use Symfony\Component\Intl\Util\IntlTestHelper; class LanguageTypeTest extends BaseTypeTest @@ -73,4 +74,14 @@ class LanguageTypeTest extends BaseTypeTest { parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData); } + + /** + * @group legacy + */ + public function testInvalidChoiceValuesAreDropped() + { + $type = new LanguageType(); + + $this->assertSame(array(), $type->loadChoicesForValues(array('foo'))); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php index cf68da243c..94e22928ff 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\LocaleType; use Symfony\Component\Intl\Util\IntlTestHelper; class LocaleTypeTest extends BaseTypeTest @@ -61,4 +62,14 @@ class LocaleTypeTest extends BaseTypeTest { parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData); } + + /** + * @group legacy + */ + public function testInvalidChoiceValuesAreDropped() + { + $type = new LocaleType(); + + $this->assertSame(array(), $type->loadChoicesForValues(array('foo'))); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php index a72bc985cd..c80a8b7cfb 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php @@ -83,14 +83,6 @@ class UrlTypeTest extends TextTypeTest )); } - public function testSubmitWithNonStringDataDoesNotBreakTheFixUrlProtocolListener() - { - $form = $this->factory->create(static::TESTED_TYPE); - $form->submit(array('domain.com', 'www.domain.com')); - - $this->assertSame(array('domain.com', 'www.domain.com'), $form->getData()); - } - public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expectedData = 'http://empty') { $form = $this->factory->create(static::TESTED_TYPE, null, array( diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 12aff8d8e1..7decfd0604 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -220,7 +220,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase ->getForm(); // Launch transformer - $form->submit(array()); + $form->submit('foo'); $this->expectNoValidate(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php index 296b8baeff..7d1733e20d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php @@ -41,6 +41,6 @@ class UploadValidatorExtensionTest extends TypeTestCase $extension->configureOptions($resolver); $options = $resolver->resolve(); - $this->assertEquals('translated max {{ max }}!', \call_user_func($options['upload_max_size_message'])); + $this->assertEquals('translated max {{ max }}!', $options['upload_max_size_message']()); } } diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index e1a6ae297a..8f51ef9dba 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php @@ -101,9 +101,9 @@ class HeaderBag implements \IteratorAggregate, \Countable /** * Returns a header value by name. * - * @param string $key The header name - * @param string|string[]|null $default The default value - * @param bool $first Whether to return the first value or all header values + * @param string $key The header name + * @param string|null $default The default value + * @param bool $first Whether to return the first value or all header values * * @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise */ diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 51940b8de7..8d458d148d 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1908,7 +1908,7 @@ class Request private static function createRequestFromFactory(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { if (self::$requestFactory) { - $request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content); + $request = (self::$requestFactory)($query, $request, $attributes, $cookies, $files, $server, $content); if (!$request instanceof self) { throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.'); diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index 06d053eadd..d3bcbb79d3 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -111,7 +111,7 @@ class StreamedResponse extends Response throw new \LogicException('The Response callback must not be null.'); } - \call_user_func($this->callback); + ($this->callback)(); return $this; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 0a65eaa8e4..0edda00aa9 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -390,7 +390,7 @@ class MockPdo extends \PDO public function prepare($statement, $driverOptions = array()) { return \is_callable($this->prepareResult) - ? \call_user_func($this->prepareResult, $statement, $driverOptions) + ? ($this->prepareResult)($statement, $driverOptions) : $this->prepareResult; } diff --git a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php index e187022b54..221d33473e 100644 --- a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php +++ b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php @@ -91,7 +91,7 @@ class FileLinkFormatter implements \Serializable if ($this->requestStack && $this->baseDir && $this->urlFormat) { $request = $this->requestStack->getMasterRequest(); if ($request instanceof Request) { - if ($this->urlFormat instanceof \Closure && !$this->urlFormat = \call_user_func($this->urlFormat)) { + if ($this->urlFormat instanceof \Closure && !$this->urlFormat = ($this->urlFormat)()) { return; } diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 1701994297..5a18dd8683 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Messenger\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; @@ -163,11 +162,7 @@ class MessengerPass implements CompilerPassInterface foreach ($handlersByBusAndMessage as $bus => $handlersByMessage) { foreach ($handlersByMessage as $message => $handlerIds) { $handlers = array_map(function (string $handlerId) { return new Reference($handlerId); }, $handlerIds); - $handlersId = "messenger.handlers.$bus.$message"; - $definitions[$handlersId] = (new Definition(RewindableGenerator::class)) - ->setFactory('current') - ->addArgument(array($handlers)); - $handlersLocatorMappingByBus[$bus][$message] = new Reference($handlersId); + $handlersLocatorMappingByBus[$bus][$message] = new IteratorArgument($handlers); } } $container->addDefinitions($definitions); diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 2c219607bf..f88743aea2 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Messenger\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -67,8 +67,8 @@ class MessengerPassTest extends TestCase $this->assertSame(HandlersLocator::class, $handlersLocatorDefinition->getClass()); $this->assertEquals( array( - DummyMessage::class => new Reference("messenger.handlers.$busId.".DummyMessage::class), - SecondMessage::class => new Reference("messenger.handlers.$busId.".SecondMessage::class), + DummyMessage::class => new IteratorArgument(array(new Reference(DummyHandler::class))), + SecondMessage::class => new IteratorArgument(array(new Reference(MissingArgumentTypeHandler::class))), ), $handlersLocatorDefinition->getArgument(0) ); @@ -107,8 +107,8 @@ class MessengerPassTest extends TestCase $this->assertSame(HandlersLocator::class, $commandBusHandlersLocatorDefinition->getClass()); $this->assertEquals( array( - MultipleBusesMessage::class => new Reference("messenger.handlers.$commandBusId.".MultipleBusesMessage::class), - DummyCommand::class => new Reference("messenger.handlers.$commandBusId.".DummyCommand::class), + MultipleBusesMessage::class => new IteratorArgument(array(new Reference(MultipleBusesMessageHandler::class))), + DummyCommand::class => new IteratorArgument(array(new Reference(DummyCommandHandler::class))), ), $commandBusHandlersLocatorDefinition->getArgument(0) ); @@ -117,8 +117,8 @@ class MessengerPassTest extends TestCase $this->assertSame(HandlersLocator::class, $queryBusHandlersLocatorDefinition->getClass()); $this->assertEquals( array( - DummyQuery::class => new Reference("messenger.handlers.$queryBusId.".DummyQuery::class), - MultipleBusesMessage::class => new Reference("messenger.handlers.$queryBusId.".MultipleBusesMessage::class), + DummyQuery::class => new IteratorArgument(array(new Reference(DummyQueryHandler::class))), + MultipleBusesMessage::class => new IteratorArgument(array(new Reference(MultipleBusesMessageHandler::class))), ), $queryBusHandlersLocatorDefinition->getArgument(0) ); @@ -155,13 +155,10 @@ class MessengerPassTest extends TestCase $handlersMapping = $container->getDefinition($busId.'.messenger.handlers_locator')->getArgument(0); $this->assertArrayHasKey(DummyMessage::class, $handlersMapping); - $this->assertEquals(new Reference("messenger.handlers.$busId.".DummyMessage::class), $handlersMapping[DummyMessage::class]); + $this->assertEquals(new IteratorArgument(array(new Reference(HandlerWithMultipleMessages::class))), $handlersMapping[DummyMessage::class]); $this->assertArrayHasKey(SecondMessage::class, $handlersMapping); - $handlersDefinition = $container->getDefinition($handlersMapping[SecondMessage::class]); - - $this->assertSame(RewindableGenerator::class, $handlersDefinition->getClass()); - $this->assertEquals(array(new Reference(PrioritizedHandler::class), new Reference(HandlerWithMultipleMessages::class)), $handlersDefinition->getArgument(0)[0]); + $this->assertEquals(new IteratorArgument(array(new Reference(PrioritizedHandler::class), new Reference(HandlerWithMultipleMessages::class))), $handlersMapping[SecondMessage::class]); } public function testGetClassesAndMethodsAndPrioritiesFromTheSubscriber() @@ -183,13 +180,13 @@ class MessengerPassTest extends TestCase $this->assertArrayHasKey(DummyMessage::class, $handlersMapping); $this->assertArrayHasKey(SecondMessage::class, $handlersMapping); - $dummyHandlerReference = $container->getDefinition($handlersMapping[DummyMessage::class])->getArgument(0)[0][0]; + $dummyHandlerReference = $handlersMapping[DummyMessage::class]->getValues()[0]; $dummyHandlerDefinition = $container->getDefinition($dummyHandlerReference); $this->assertSame('callable', $dummyHandlerDefinition->getClass()); $this->assertEquals(array(new Reference(HandlerMappingMethods::class), 'dummyMethod'), $dummyHandlerDefinition->getArgument(0)); $this->assertSame(array('Closure', 'fromCallable'), $dummyHandlerDefinition->getFactory()); - $secondHandlerReference = $container->getDefinition($handlersMapping[SecondMessage::class])->getArgument(0)[0][1]; + $secondHandlerReference = $handlersMapping[SecondMessage::class]->getValues()[1]; $secondHandlerDefinition = $container->getDefinition($secondHandlerReference); $this->assertSame(PrioritizedHandler::class, $secondHandlerDefinition->getClass()); } @@ -281,11 +278,11 @@ class MessengerPassTest extends TestCase $handlersMapping = $container->getDefinition($busId.'.messenger.handlers_locator')->getArgument(0); $this->assertArrayHasKey(DummyMessage::class, $handlersMapping); - $firstReference = $container->getDefinition($handlersMapping[DummyMessage::class])->getArgument(0)[0][0]; + $firstReference = $handlersMapping[DummyMessage::class]->getValues()[0]; $this->assertEquals(array(new Reference(HandlerWithGenerators::class), 'dummyMethod'), $container->getDefinition($firstReference)->getArgument(0)); $this->assertArrayHasKey(SecondMessage::class, $handlersMapping); - $secondReference = $container->getDefinition($handlersMapping[SecondMessage::class])->getArgument(0)[0][0]; + $secondReference = $handlersMapping[SecondMessage::class]->getValues()[0]; $this->assertEquals(array(new Reference(HandlerWithGenerators::class), 'secondMessage'), $container->getDefinition($secondReference)->getArgument(0)); } @@ -304,13 +301,13 @@ class MessengerPassTest extends TestCase $eventsHandlerMapping = $container->getDefinition($eventsBusId.'.messenger.handlers_locator')->getArgument(0); $this->assertEquals(array(DummyMessage::class), array_keys($eventsHandlerMapping)); - $firstReference = $container->getDefinition($eventsHandlerMapping[DummyMessage::class])->getArgument(0)[0][0]; + $firstReference = $eventsHandlerMapping[DummyMessage::class]->getValues()[0]; $this->assertEquals(array(new Reference(HandlerOnSpecificBuses::class), 'dummyMethodForEvents'), $container->getDefinition($firstReference)->getArgument(0)); $commandsHandlerMapping = $container->getDefinition($commandsBusId.'.messenger.handlers_locator')->getArgument(0); $this->assertEquals(array(DummyMessage::class), array_keys($commandsHandlerMapping)); - $firstReference = $container->getDefinition($commandsHandlerMapping[DummyMessage::class])->getArgument(0)[0][0]; + $firstReference = $commandsHandlerMapping[DummyMessage::class]->getValues()[0]; $this->assertEquals(array(new Reference(HandlerOnSpecificBuses::class), 'dummyMethodForCommands'), $container->getDefinition($firstReference)->getArgument(0)); } diff --git a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php index fb898326a5..3867447a30 100644 --- a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php +++ b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php @@ -47,7 +47,7 @@ class OptionsResolverIntrospector */ public function getDefault(string $option) { - return \call_user_func($this->get, 'defaults', $option, sprintf('No default value was set for the "%s" option.', $option)); + return ($this->get)('defaults', $option, sprintf('No default value was set for the "%s" option.', $option)); } /** @@ -57,7 +57,7 @@ class OptionsResolverIntrospector */ public function getLazyClosures(string $option): array { - return \call_user_func($this->get, 'lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option)); + return ($this->get)('lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option)); } /** @@ -67,7 +67,7 @@ class OptionsResolverIntrospector */ public function getAllowedTypes(string $option): array { - return \call_user_func($this->get, 'allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option)); + return ($this->get)('allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option)); } /** @@ -77,7 +77,7 @@ class OptionsResolverIntrospector */ public function getAllowedValues(string $option): array { - return \call_user_func($this->get, 'allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option)); + return ($this->get)('allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option)); } /** @@ -85,7 +85,7 @@ class OptionsResolverIntrospector */ public function getNormalizer(string $option): \Closure { - return \call_user_func($this->get, 'normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option)); + return ($this->get)('normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option)); } /** @@ -95,6 +95,6 @@ class OptionsResolverIntrospector */ public function getDeprecationMessage(string $option) { - return \call_user_func($this->get, 'deprecated', $option, sprintf('No deprecation was set for the "%s" option.', $option)); + return ($this->get)('deprecated', $option, sprintf('No deprecation was set for the "%s" option.', $option)); } } diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 7ffbacb216..666c109ab2 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -1309,7 +1309,7 @@ class Process implements \IteratorAggregate if ($this->outputDisabled) { return function ($type, $data) use ($callback) { if (null !== $callback) { - return \call_user_func($callback, $type, $data); + return $callback($type, $data); } }; } @@ -1324,7 +1324,7 @@ class Process implements \IteratorAggregate } if (null !== $callback) { - return \call_user_func($callback, $type, $data); + return $callback($type, $data); } }; } diff --git a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php index dd14487ce0..b31eed5a6c 100644 --- a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php +++ b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php @@ -67,7 +67,7 @@ abstract class ObjectRouteLoader extends Loader throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s"', $method, \get_class($loaderObject), $resource)); } - $routeCollection = \call_user_func(array($loaderObject, $method), $this); + $routeCollection = $loaderObject->$method($this); if (!$routeCollection instanceof RouteCollection) { $type = \is_object($routeCollection) ? \get_class($routeCollection) : \gettype($routeCollection); diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php index e84885d907..db02bcd18e 100644 --- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php +++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php @@ -96,14 +96,22 @@ class GuardAuthenticationListener implements ListenerInterface $request = $event->getRequest(); try { if (null !== $this->logger) { - $this->logger->debug('Calling getCredentials() on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator))); + $this->logger->debug('Checking support on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator))); } // abort the execution of the authenticator if it doesn't support the request if (!$guardAuthenticator->supports($request)) { + if (null !== $this->logger) { + $this->logger->debug('Guard authenticator does not support the request.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator))); + } + return; } + if (null !== $this->logger) { + $this->logger->debug('Calling getCredentials() on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator))); + } + // allow the authenticator to fetch authentication info from the request $credentials = $guardAuthenticator->getCredentials($request); diff --git a/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php b/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php index 986adb0c58..87ff333e05 100644 --- a/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php +++ b/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php @@ -38,7 +38,7 @@ trait TargetPathTrait * @param SessionInterface $session * @param string $providerKey The name of your firewall * - * @return string + * @return string|null */ private function getTargetPath(SessionInterface $session, $providerKey) { diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 468d9dc3d9..82d0bbb17f 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -413,25 +413,9 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn unset($data[$key]); continue; } - try { - if (null !== $constructorParameter->getClass()) { - if (!$this->serializer instanceof DenormalizerInterface) { - throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), self::class)); - } - $parameterClass = $constructorParameter->getClass()->getName(); - $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName)); - } - } catch (\ReflectionException $e) { - throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e); - } catch (MissingConstructorArgumentsException $e) { - if (!$constructorParameter->getType()->allowsNull()) { - throw $e; - } - $parameterData = null; - } // Don't run set for a parameter passed to the constructor - $params[] = $parameterData; + $params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); unset($data[$key]); } elseif (array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? array())) { $params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; @@ -454,6 +438,31 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn return new $class(); } + /** + * @internal + */ + protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, $parameterName, $parameterData, array $context, $format = null) + { + try { + if (null !== $parameter->getClass()) { + if (!$this->serializer instanceof DenormalizerInterface) { + throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $parameter->getClass(), self::class)); + } + $parameterClass = $parameter->getClass()->getName(); + $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName)); + } + } catch (\ReflectionException $e) { + throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e); + } catch (MissingConstructorArgumentsException $e) { + if (!$parameter->getType()->allowsNull()) { + throw $e; + } + $parameterData = null; + } + + return $parameterData; + } + /** * @param array $parentContext * @param string $attribute diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 649df9c3a8..8e8edde937 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -94,7 +94,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer $data = array(); $stack = array(); $attributes = $this->getAttributes($object, $format, $context); - $class = $this->objectClassResolver ? \call_user_func($this->objectClassResolver, $object) : \get_class($object); + $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); $attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null; $maxDepthHandler = $context[self::MAX_DEPTH_HANDLER] ?? $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler; @@ -106,7 +106,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer $attributeValue = $this->getAttributeValue($object, $attribute, $format, $context); if ($maxDepthReached) { - $attributeValue = \call_user_func($maxDepthHandler, $attributeValue, $object, $attribute, $format, $context); + $attributeValue = $maxDepthHandler($attributeValue, $object, $attribute, $format, $context); } /** @@ -168,7 +168,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer */ protected function getAttributes($object, $format = null, array $context) { - $class = $this->objectClassResolver ? \call_user_func($this->objectClassResolver, $object) : \get_class($object); + $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); $key = $class.'-'.$context['cache_key']; if (isset($this->attributesCache[$key])) { @@ -363,7 +363,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer return (float) $data; } - if (\call_user_func('is_'.$builtinType, $data)) { + if (('is_'.$builtinType)($data)) { return $data; } } @@ -375,6 +375,18 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer throw new NotNormalizableValueException(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), \gettype($data))); } + /** + * @internal + */ + protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, $parameterName, $parameterData, array $context, $format = null) + { + if (null === $this->propertyTypeExtractor || null === $types = $this->propertyTypeExtractor->getTypes($class->getName(), $parameterName)) { + return parent::denormalizeParameter($class, $parameter, $parameterName, $parameterData, $context, $format); + } + + return $this->validateAndDenormalize($class->getName(), $parameterName, $parameterData, $format, $context); + } + /** * @return Type[]|null */ diff --git a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php index 81e11dcd25..70a8470891 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php @@ -53,7 +53,7 @@ class ArrayDenormalizer implements ContextAwareDenormalizerInterface, Serializer $builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null; foreach ($data as $key => $value) { - if (null !== $builtinType && !\call_user_func('is_'.$builtinType, $key)) { + if (null !== $builtinType && !('is_'.$builtinType)($key)) { throw new NotNormalizableValueException(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, $builtinType, \gettype($key))); } diff --git a/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php b/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php new file mode 100644 index 0000000000..e94c7dc0d8 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Serializer; + +class DeserializeNestedArrayOfObjectsTest extends TestCase +{ + public function provider() + { + return array( + //from property PhpDoc + array(Zoo::class), + //from argument constructor PhpDoc + array(ZooImmutable::class), + ); + } + + /** + * @dataProvider provider + */ + public function testPropertyPhpDoc($class) + { + //GIVEN + $json = << new JsonEncoder())); + //WHEN + /** @var Zoo $zoo */ + $zoo = $serializer->deserialize($json, $class, 'json'); + //THEN + self::assertCount(1, $zoo->getAnimals()); + self::assertInstanceOf(Animal::class, $zoo->getAnimals()[0]); + } +} + +class Zoo +{ + /** @var Animal[] */ + private $animals = array(); + + /** + * @return Animal[] + */ + public function getAnimals() + { + return $this->animals; + } + + /** + * @param Animal[] $animals + */ + public function setAnimals(array $animals) + { + $this->animals = $animals; + } +} + +class ZooImmutable +{ + /** @var Animal[] */ + private $animals = array(); + + /** + * @param Animal[] $animals + */ + public function __construct(array $animals = array()) + { + $this->animals = $animals; + } + + /** + * @return Animal[] + */ + public function getAnimals() + { + return $this->animals; + } +} + +class Animal +{ + /** @var string */ + private $name; + + public function __construct() + { + echo ''; + } + + /** + * @return string|null + */ + public function getName() + { + return $this->name; + } + + /** + * @param string|null $name + */ + public function setName($name) + { + $this->name = $name; + } +} diff --git a/src/Symfony/Component/Templating/PhpEngine.php b/src/Symfony/Component/Templating/PhpEngine.php index 1d24448207..11452c709e 100644 --- a/src/Symfony/Component/Templating/PhpEngine.php +++ b/src/Symfony/Component/Templating/PhpEngine.php @@ -313,13 +313,13 @@ class PhpEngine implements EngineInterface, \ArrayAccess // the performance when the same value is escaped multiple times (e.g. loops) if (is_scalar($value)) { if (!isset(self::$escaperCache[$context][$value])) { - self::$escaperCache[$context][$value] = \call_user_func($this->getEscaper($context), $value); + self::$escaperCache[$context][$value] = $this->getEscaper($context)($value); } return self::$escaperCache[$context][$value]; } - return \call_user_func($this->getEscaper($context), $value); + return $this->getEscaper($context)($value); } /** diff --git a/src/Symfony/Component/Translation/Command/XliffLintCommand.php b/src/Symfony/Component/Translation/Command/XliffLintCommand.php index 67bb7764b5..17e1a72bb4 100644 --- a/src/Symfony/Component/Translation/Command/XliffLintCommand.php +++ b/src/Symfony/Component/Translation/Command/XliffLintCommand.php @@ -242,7 +242,7 @@ EOF }; if (null !== $this->directoryIteratorProvider) { - return \call_user_func($this->directoryIteratorProvider, $directory, $default); + return ($this->directoryIteratorProvider)($directory, $default); } return $default($directory); @@ -255,7 +255,7 @@ EOF }; if (null !== $this->isReadableProvider) { - return \call_user_func($this->isReadableProvider, $fileOrDirectory, $default); + return ($this->isReadableProvider)($fileOrDirectory, $default); } return $default($fileOrDirectory); diff --git a/src/Symfony/Component/Translation/PluralizationRules.php b/src/Symfony/Component/Translation/PluralizationRules.php index 362f6a1f1f..efbfd7f225 100644 --- a/src/Symfony/Component/Translation/PluralizationRules.php +++ b/src/Symfony/Component/Translation/PluralizationRules.php @@ -46,7 +46,7 @@ class PluralizationRules } if (isset(self::$rules[$locale])) { - $return = \call_user_func(self::$rules[$locale], $number); + $return = self::$rules[$locale]($number); if (!\is_int($return) || $return < 0) { return 0; diff --git a/src/Symfony/Component/Validator/Constraints/CallbackValidator.php b/src/Symfony/Component/Validator/Constraints/CallbackValidator.php index a66840eae1..b0ba21acb1 100644 --- a/src/Symfony/Component/Validator/Constraints/CallbackValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CallbackValidator.php @@ -43,7 +43,7 @@ class CallbackValidator extends ConstraintValidator throw new ConstraintDefinitionException(sprintf('%s targeted by Callback constraint is not a valid callable', json_encode($method))); } - \call_user_func($method, $object, $this->context, $constraint->payload); + $method($object, $this->context, $constraint->payload); } elseif (null !== $object) { if (!method_exists($object, $method)) { throw new ConstraintDefinitionException(sprintf('Method "%s" targeted by Callback constraint does not exist in class %s', $method, \get_class($object))); diff --git a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php index 19eae97481..a2635309f0 100644 --- a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php @@ -54,7 +54,7 @@ class ChoiceValidator extends ConstraintValidator ) { throw new ConstraintDefinitionException('The Choice constraint expects a valid callback'); } - $choices = \call_user_func($choices); + $choices = $choices(); } else { $choices = $constraint->choices; } diff --git a/src/Symfony/Component/Validator/Constraints/IbanValidator.php b/src/Symfony/Component/Validator/Constraints/IbanValidator.php index 8f7cb5e910..222ce57442 100644 --- a/src/Symfony/Component/Validator/Constraints/IbanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IbanValidator.php @@ -130,6 +130,7 @@ class IbanValidator extends ConstraintValidator 'TN' => 'TN59\d{2}\d{3}\d{13}\d{2}', // Tunisia 'TR' => 'TR\d{2}\d{5}[\dA-Z]{1}[\dA-Z]{16}', // Turkey 'UA' => 'UA\d{2}\d{6}[\dA-Z]{19}', // Ukraine + 'VA' => 'VA\d{2}\d{3}\d{15}', // Vatican City State 'VG' => 'VG\d{2}[A-Z]{4}\d{16}', // Virgin Islands, British 'WF' => 'FR\d{2}\d{5}\d{5}[\dA-Z]{11}\d{2}', // Wallis and Futuna Islands 'XK' => 'XK\d{2}\d{4}\d{10}\d{2}', // Republic of Kosovo diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php index 7f9ba339cd..e5c63c3654 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IbanValidatorTest.php @@ -156,6 +156,7 @@ class IbanValidatorTest extends ConstraintValidatorTestCase array('TR330006100519786457841326'), //Turkey array('UA213223130000026007233566001'), //Ukraine array('AE260211000000230064016'), //United Arab Emirates + array('VA59001123000012345678'), //Vatican City State ); } @@ -274,6 +275,7 @@ class IbanValidatorTest extends ConstraintValidatorTestCase array('TR3300061005197864578413261'), //Turkey array('UA21AAAA1300000260072335660012'), //Ukraine array('AE2602110000002300640161'), //United Arab Emirates + array('VA590011230000123456781'), //Vatican City State ); } @@ -385,6 +387,7 @@ class IbanValidatorTest extends ConstraintValidatorTestCase array('TR330006100519786457841327'), //Turkey array('UA213223130000026007233566002'), //Ukraine array('AE260211000000230064017'), //United Arab Emirates + array('VA59001123000012345671'), //Vatican City State ); } diff --git a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php index 9e0afe0639..49ebef0c7c 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php @@ -12,6 +12,10 @@ namespace Symfony\Component\Validator\Tests\Validator; use Symfony\Component\Translation\IdentityTranslator; +use Symfony\Component\Validator\Constraints\All; +use Symfony\Component\Validator\Constraints\Collection; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\ConstraintValidatorFactory; use Symfony\Component\Validator\Context\ExecutionContextFactory; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; @@ -95,4 +99,38 @@ class RecursiveValidatorTest extends AbstractTest $validator->validate($entity, null, array()); } + + public function testCollectionConstraintValidateAllGroupsForNestedConstraints() + { + $this->metadata->addPropertyConstraint('data', new Collection(array('fields' => array( + 'one' => array(new NotBlank(array('groups' => 'one')), new Length(array('min' => 2, 'groups' => 'two'))), + 'two' => array(new NotBlank(array('groups' => 'two'))), + )))); + + $entity = new Entity(); + $entity->data = array('one' => 't', 'two' => ''); + + $violations = $this->validator->validate($entity, null, array('one', 'two')); + + $this->assertCount(2, $violations); + $this->assertInstanceOf(Length::class, $violations->get(0)->getConstraint()); + $this->assertInstanceOf(NotBlank::class, $violations->get(1)->getConstraint()); + } + + public function testAllConstraintValidateAllGroupsForNestedConstraints() + { + $this->metadata->addPropertyConstraint('data', new All(array('constraints' => array( + new NotBlank(array('groups' => 'one')), + new Length(array('min' => 2, 'groups' => 'two')), + )))); + + $entity = new Entity(); + $entity->data = array('one' => 't', 'two' => ''); + + $violations = $this->validator->validate($entity, null, array('one', 'two')); + + $this->assertCount(2, $violations); + $this->assertInstanceOf(NotBlank::class, $violations->get(0)->getConstraint()); + $this->assertInstanceOf(Length::class, $violations->get(1)->getConstraint()); + } } diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 964052a341..f040d8cb8e 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Validator; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\Composite; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\ConstraintValidatorFactoryInterface; use Symfony\Component\Validator\Context\ExecutionContext; @@ -788,6 +789,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface if (null !== $cacheKey) { $constraintHash = spl_object_hash($constraint); + if ($constraint instanceof Composite) { + $constraintHash .= $group; + } + if ($context->isConstraintValidated($cacheKey, $constraintHash)) { continue; } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 00519ab4ac..88691609e1 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -231,7 +231,7 @@ abstract class AbstractCloner implements ClonerInterface } if ($this->prevErrorHandler) { - return \call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context); + return ($this->prevErrorHandler)($type, $msg, $file, $line, $context); } return false; diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index abcda1af80..37140b715d 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -164,7 +164,7 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface */ protected function dumpLine($depth) { - \call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad); + ($this->lineDumper)($this->line, $depth, $this->indentPad); $this->line = ''; } diff --git a/src/Symfony/Component/VarDumper/VarDumper.php b/src/Symfony/Component/VarDumper/VarDumper.php index ff0cc948e2..7c302a21ff 100644 --- a/src/Symfony/Component/VarDumper/VarDumper.php +++ b/src/Symfony/Component/VarDumper/VarDumper.php @@ -41,7 +41,7 @@ class VarDumper }; } - return \call_user_func(self::$handler, $var); + return (self::$handler)($var); } public static function setHandler(callable $callable = null) diff --git a/src/Symfony/Component/VarExporter/Internal/Registry.php b/src/Symfony/Component/VarExporter/Internal/Registry.php index 487a8566e2..705722650a 100644 --- a/src/Symfony/Component/VarExporter/Internal/Registry.php +++ b/src/Symfony/Component/VarExporter/Internal/Registry.php @@ -93,15 +93,9 @@ class Registry throw new NotInstantiableTypeException($class); } } - if (null !== $proto && !$proto instanceof \Throwable) { + if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !\method_exists($class, '__sleep')) { try { - if (!$proto instanceof \Serializable && !\method_exists($class, '__sleep')) { - serialize($proto); - } elseif ($instantiableWithoutConstructor) { - serialize($reflector->newInstanceWithoutConstructor()); - } else { - serialize(unserialize(($proto instanceof \Serializable ? 'C:' : 'O:').\strlen($class).':"'.$class.'":0:{}')); - } + serialize($proto); } catch (\Exception $e) { throw new NotInstantiableTypeException($class, $e); } diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php new file mode 100644 index 0000000000..fd4e267101 --- /dev/null +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php @@ -0,0 +1,11 @@ +setBar(234); } } + +class FooSerializable implements \Serializable +{ + private $foo; + + public function __construct(string $foo) + { + $this->foo = $foo; + } + + public function getFoo(): string + { + return $this->foo; + } + + public function serialize(): string + { + return serialize(array($this->getFoo())); + } + + public function unserialize($str) + { + list($this->foo) = unserialize($str); + } +} diff --git a/src/Symfony/Component/WebLink/README.md b/src/Symfony/Component/WebLink/README.md index 61fd3bff67..d246e50754 100644 --- a/src/Symfony/Component/WebLink/README.md +++ b/src/Symfony/Component/WebLink/README.md @@ -11,7 +11,7 @@ It can also be used with extensions defined in the [HTML5 link type extensions w Resources --------- - * [Documentation](https://symfony.com/doc/current/components/weblink/introduction.html) + * [Documentation](https://symfony.com/doc/current/components/web_link.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Yaml/Command/LintCommand.php b/src/Symfony/Component/Yaml/Command/LintCommand.php index 288d73165d..a8cdc318be 100644 --- a/src/Symfony/Component/Yaml/Command/LintCommand.php +++ b/src/Symfony/Component/Yaml/Command/LintCommand.php @@ -232,7 +232,7 @@ EOF }; if (null !== $this->directoryIteratorProvider) { - return \call_user_func($this->directoryIteratorProvider, $directory, $default); + return ($this->directoryIteratorProvider)($directory, $default); } return $default($directory); @@ -245,7 +245,7 @@ EOF }; if (null !== $this->isReadableProvider) { - return \call_user_func($this->isReadableProvider, $fileOrDirectory, $default); + return ($this->isReadableProvider)($fileOrDirectory, $default); } return $default($fileOrDirectory); diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 2d5fda4c8e..bd3e56fde6 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -78,35 +78,37 @@ class Inline mb_internal_encoding('ASCII'); } - $i = 0; - $tag = self::parseTag($value, $i, $flags); - switch ($value[$i]) { - case '[': - $result = self::parseSequence($value, $flags, $i, $references); - ++$i; - break; - case '{': - $result = self::parseMapping($value, $flags, $i, $references); - ++$i; - break; - default: - $result = self::parseScalar($value, $flags, null, $i, null === $tag, $references); - } + try { + $i = 0; + $tag = self::parseTag($value, $i, $flags); + switch ($value[$i]) { + case '[': + $result = self::parseSequence($value, $flags, $i, $references); + ++$i; + break; + case '{': + $result = self::parseMapping($value, $flags, $i, $references); + ++$i; + break; + default: + $result = self::parseScalar($value, $flags, null, $i, null === $tag, $references); + } - if (null !== $tag && '' !== $tag) { - return new TaggedValue($tag, $result); - } + if (null !== $tag && '' !== $tag) { + return new TaggedValue($tag, $result); + } - // some comments are allowed at the end - if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) { - throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename); - } + // some comments are allowed at the end + if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) { + throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename); + } - if (isset($mbEncoding)) { - mb_internal_encoding($mbEncoding); + return $result; + } finally { + if (isset($mbEncoding)) { + mb_internal_encoding($mbEncoding); + } } - - return $result; } /**