From 5196dac7a871c09d8f4b3098eeedeb167e340349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vasseur?= Date: Mon, 3 Dec 2018 11:41:13 +0100 Subject: [PATCH 01/12] Fix HeaderBag::get phpdoc When setting $first to false, the default value is wrapped into an array meaning you need to pass a string as the default value instead of an array of strings. --- src/Symfony/Component/HttpFoundation/HeaderBag.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index 5445e80c8b..230253663c 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 */ From ceb7a68efaf92dae7ac889a503561f8c2cd5f8fc Mon Sep 17 00:00:00 2001 From: knuch Date: Sat, 8 Dec 2018 11:49:49 +0000 Subject: [PATCH 02/12] merge conflicts --- .../DependencyInjection/ServiceLocator.php | 17 +++++++++-------- .../Tests/ServiceLocatorTest.php | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/ServiceLocator.php index bdedc88e8b..10c7c9eb65 100644 --- a/src/Symfony/Component/DependencyInjection/ServiceLocator.php +++ b/src/Symfony/Component/DependencyInjection/ServiceLocator.php @@ -94,39 +94,40 @@ class ServiceLocator implements PsrContainerInterface $class = isset($class[2]['object']) ? \get_class($class[2]['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 $msg; + return implode(' ', $msg); } private function formatAlternatives(array $alternatives = null, $separator = 'and') diff --git a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php index 56fac643eb..aa9790e833 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php @@ -115,6 +115,20 @@ class ServiceLocatorTest extends TestCase $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 = new ServiceLocator(array( From 21c303009259573f78629a7f678f6f2c3369e674 Mon Sep 17 00:00:00 2001 From: Enrico Schultz Date: Mon, 26 Nov 2018 08:11:22 +0100 Subject: [PATCH 03/12] [Security] defer log message in guard authenticator prevent an unneccessary log message if the guard authenticator does not support the current request --- .../Firewall/GuardAuthenticationListener.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php index 02864f3725..2df09577bf 100644 --- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php +++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php @@ -97,13 +97,17 @@ 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))); - } - // abort the execution of the authenticator if it doesn't support the request if ($guardAuthenticator instanceof AuthenticatorInterface) { + if (null !== $this->logger) { + $this->logger->debug('Checking support on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator))); + } + 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; } // as there was a support for given request, @@ -114,6 +118,10 @@ class GuardAuthenticationListener implements ListenerInterface $credentialsCanBeNull = true; } + 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); From 8741d00d6e778dd4073263207c2f9d0aeda41eec Mon Sep 17 00:00:00 2001 From: karser Date: Sat, 8 Dec 2018 13:04:17 +0200 Subject: [PATCH 04/12] [Hackday][Serializer] Deserialization ignores argument type hint from phpdoc for array in constructor argument --- .../Normalizer/AbstractNormalizer.php | 34 +++-- .../Normalizer/AbstractObjectNormalizer.php | 12 ++ .../DeserializeNestedArrayOfObjectsTest.php | 128 ++++++++++++++++++ 3 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 2bdf120ae2..28ebdb656a 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -358,20 +358,9 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N 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(), static::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); - } // 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 ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); @@ -390,6 +379,27 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N 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(), static::class)); + } + $parameterClass = $parameter->getClass()->getName(); + + return $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName)); + } + + return $parameterData; + } catch (\ReflectionException $e) { + throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e); + } + } + /** * @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 aff70ee4ce..1c3f54b60d 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -304,6 +304,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); + } + /** * Sets an attribute and apply the name converter if necessary. * 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; + } +} From 8d4b787dd96e632d44f2f3cf61600aa64cbbac0b Mon Sep 17 00:00:00 2001 From: Mponos George Date: Sat, 1 Dec 2018 18:23:06 +0200 Subject: [PATCH 05/12] [Security] getTargetPath of TargetPathTrait must return string or null --- src/Symfony/Component/Security/Http/Util/TargetPathTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) { From 362339f26ce1d08cfe3a595169f4c70f63ae3a5d Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Mon, 10 Dec 2018 14:11:36 +0100 Subject: [PATCH 06/12] [WebLink] Fixed documentation link --- src/Symfony/Component/WebLink/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 56ab129b9600e854f58c33b2c4a422752056f2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Lang?= Date: Tue, 11 Dec 2018 14:45:34 +0100 Subject: [PATCH 07/12] [Yaml] ensures that the mb_internal_encoding is reset to its initial value --- src/Symfony/Component/Yaml/Inline.php | 52 ++++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 7c9d4e03b5..42b6cb10e7 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -110,35 +110,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) { - return new TaggedValue($tag, $result); - } + if (null !== $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; } /** From 3b9d8efc95a28d750fbc466d12f372bc8598f7f7 Mon Sep 17 00:00:00 2001 From: Samuele Lilli Date: Wed, 31 Oct 2018 16:57:08 +0100 Subject: [PATCH 08/12] Update ValidationListener.php This comment was misleading. It's true that no groups (ie.: `Default`) are setted into validation process but it's not clear from the comment. I suppose that is better to be more explicit about this process. BTW I'm still not sure if `FormValidator` reference is necessary as we can change it and we should remember to update this comment and this does not seems to fit. WDYT, is better to leave `FormValidator` out of this comment? For reference: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php#L46-L92 --- .../Extension/Validator/EventListener/ValidationListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From c3271d9385ced1509db2d97e7fb293c6dd059002 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 12 Dec 2018 08:43:43 -0500 Subject: [PATCH 09/12] [DI] move RegisterServiceSubscribersPass before DecoratorServicePass --- .../Compiler/PassConfig.php | 2 +- .../Tests/Compiler/IntegrationTest.php | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 31104fb1fe..d547c3e95e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -51,12 +51,12 @@ class PassConfig $this->optimizationPasses = array(array( new ResolveChildDefinitionsPass(), new ServiceLocatorTagPass(), + new RegisterServiceSubscribersPass(), new DecoratorServicePass(), new ResolveParameterPlaceHoldersPass(false), new ResolveFactoryClassPass(), new FactoryReturnTypePass($resolveClassPass), new CheckDefinitionValidityPass(), - new RegisterServiceSubscribersPass(), new ResolveNamedArgumentsPass(), new AutowireRequiredMethodsPass(), new ResolveBindingsPass(), diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index 09ba6ab45c..104b39f13f 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. @@ -117,6 +118,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 */ @@ -207,6 +223,18 @@ class IntegrationTest extends TestCase } } +class ServiceSubscriberStub implements ServiceSubscriberInterface +{ + public static function getSubscribedServices() + { + return array(); + } +} + +class DecoratedServiceSubscriber +{ +} + class IntegrationTestStub extends IntegrationTestStubParent { } From a1c612aedffe46589f5cb97501ca89dfc8b2e39f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 12 Dec 2018 18:02:13 +0100 Subject: [PATCH 10/12] [FrameworkBundle] fix describing routes with no controllers --- .../FrameworkBundle/Console/Descriptor/TextDescriptor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 9846a9a90f..d91743e5c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -56,7 +56,7 @@ class TextDescriptor extends Descriptor if ($showControllers) { $controller = $route->getDefault('_controller'); - $row[] = $this->formatCallable($controller); + $row[] = $controller ? $this->formatCallable($controller) : ''; } $tableRows[] = $row; From ffd272243bcc347ec9894dca9116739c81dd16ea Mon Sep 17 00:00:00 2001 From: Thomas Baumgartner Date: Sat, 8 Dec 2018 14:55:24 +0100 Subject: [PATCH 11/12] [TwigBridge][Form] Prevent multiple rendering of form collection prototypes --- .../Bridge/Twig/Resources/views/Form/form_div_layout.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 645b74c98e..e2d70147b8 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 @@ -24,7 +24,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') -}} From d858dad0651c974b6c1ff87d4e946ab42fdcff50 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 12 Dec 2018 21:57:22 +0100 Subject: [PATCH 12/12] [Debug] ignore underscore vs backslash namespaces in DebugClassLoader --- src/Symfony/Component/Debug/DebugClassLoader.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 138b4d38d8..dd2f169ce4 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -219,7 +219,7 @@ class DebugClassLoader $len = 0; $ns = ''; } else { - $ns = \substr($class, 0, $len); + $ns = \str_replace('_', '\\', \substr($class, 0, $len)); } // Detect annotations on the class @@ -250,13 +250,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); } }