From 6331687f65f595b800b2795085e6baacb571c250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 24 Jul 2018 17:28:18 +0200 Subject: [PATCH 01/66] Allow multidimensional collection in property info --- .../Extractor/PhpDocExtractor.php | 24 +++++++++---------- .../Tests/Extractors/PhpDocExtractorTest.php | 2 ++ .../Extractors/ReflectionExtractorTest.php | 2 ++ .../PropertyInfo/Tests/Fixtures/Dummy.php | 10 ++++++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 717baddab2b57..7a7eee65dd0cf 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -319,30 +319,28 @@ private function createType($docType, $nullable) { // Cannot guess if (!$docType || 'mixed' === $docType) { - return; - } - - if ($collection = '[]' === substr($docType, -2)) { - $docType = substr($docType, 0, -2); + return null; } - $docType = $this->normalizeType($docType); - list($phpType, $class) = $this->getPhpTypeAndClass($docType); - - $array = 'array' === $docType; - - if ($collection || $array) { - if ($array || 'mixed' === $docType) { + if ('[]' === substr($docType, -2)) { + if ('mixed[]' === $docType) { $collectionKeyType = null; $collectionValueType = null; } else { $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); - $collectionValueType = new Type($phpType, $nullable, $class); + $collectionValueType = $this->createType(substr($docType, 0, -2), $nullable); } return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyType, $collectionValueType); } + $docType = $this->normalizeType($docType); + list($phpType, $class) = $this->getPhpTypeAndClass($docType); + + if ('array' === $docType) { + return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, null, null); + } + return new Type($phpType, $nullable, $class); } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php index 4110c6b8a5bf4..f251ab11360ae 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -62,6 +62,8 @@ public function typesProvider() array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('mixedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, null)), null, null), + array('nestedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))), null, null), array('a', array(new Type(Type::BUILTIN_TYPE_INT)), 'A.', null), array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), 'B.', null), array('c', array(new Type(Type::BUILTIN_TYPE_BOOL, true)), null, null), diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 2828878ce6cf0..1ac2f019077bb 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -37,6 +37,8 @@ public function testGetProperties() 'bal', 'parent', 'collection', + 'nestedCollection', + 'mixedCollection', 'B', 'Guid', 'g', diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index d358bae13ad61..e56f840a81639 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -46,6 +46,16 @@ class Dummy extends ParentDummy */ public $collection; + /** + * @var string[][] + */ + public $nestedCollection; + + /** + * @var mixed[] + */ + public $mixedCollection; + /** * @var ParentDummy */ From ce49036790e91b6be626cf8a6243ccb75e87125d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 20 Jul 2018 11:22:01 +0200 Subject: [PATCH 02/66] Allow multidimensional collection in property info --- .../Tests/Extractor/PhpDocExtractorTest.php | 6 +++++ .../Extractor/ReflectionExtractorTest.php | 6 +++++ .../PropertyInfo/Tests/Fixtures/Dummy.php | 8 +++++++ .../PropertyInfo/Util/PhpDocTypeHelper.php | 24 +++++++++---------- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index 080df2893a877..6766b249a77d8 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -87,6 +87,8 @@ public function typesProvider() array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('nestedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))), null, null), + array('mixedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, null)), null, null), array('a', array(new Type(Type::BUILTIN_TYPE_INT)), 'A.', null), array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), 'B.', null), array('c', array(new Type(Type::BUILTIN_TYPE_BOOL, true)), null, null), @@ -126,6 +128,8 @@ public function typesWithCustomPrefixesProvider() array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('nestedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))), null, null), + array('mixedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, null)), null, null), array('a', null, 'A.', null), array('b', null, 'B.', null), array('c', array(new Type(Type::BUILTIN_TYPE_BOOL, true)), null, null), @@ -164,6 +168,8 @@ public function typesWithNoPrefixesProvider() array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('nestedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING, false)))), null, null), + array('mixedCollection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, null)), null, null), array('a', null, 'A.', null), array('b', null, 'B.', null), array('c', null, null, null), diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index e7fddf473f37b..24ef06239be59 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -38,6 +38,8 @@ public function testGetProperties() 'bal', 'parent', 'collection', + 'nestedCollection', + 'mixedCollection', 'B', 'Guid', 'g', @@ -77,6 +79,8 @@ public function testGetPropertiesWithCustomPrefixes() 'bal', 'parent', 'collection', + 'nestedCollection', + 'mixedCollection', 'B', 'Guid', 'g', @@ -108,6 +112,8 @@ public function testGetPropertiesWithNoPrefixes() 'bal', 'parent', 'collection', + 'nestedCollection', + 'mixedCollection', 'B', 'Guid', 'g', diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 76c2e1042c604..152de1d8f1840 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -45,6 +45,14 @@ class Dummy extends ParentDummy * @Groups({"a", "b"}) */ public $collection; + /** + * @var string[][] + */ + public $nestedCollection; + /** + * @var mixed[] + */ + public $mixedCollection; /** * @var ParentDummy diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php index e526c62348797..431544b849d46 100644 --- a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php +++ b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php @@ -89,30 +89,28 @@ private function createType($docType, $nullable) { // Cannot guess if (!$docType || 'mixed' === $docType) { - return; + return null; } - if ($collection = '[]' === substr($docType, -2)) { - $docType = substr($docType, 0, -2); - } - - $docType = $this->normalizeType($docType); - list($phpType, $class) = $this->getPhpTypeAndClass($docType); - - $array = 'array' === $docType; - - if ($collection || $array) { - if ($array || 'mixed' === $docType) { + if ('[]' === substr($docType, -2)) { + if ('mixed[]' === $docType) { $collectionKeyType = null; $collectionValueType = null; } else { $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); - $collectionValueType = new Type($phpType, $nullable, $class); + $collectionValueType = $this->createType(substr($docType, 0, -2), $nullable); } return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyType, $collectionValueType); } + $docType = $this->normalizeType($docType); + list($phpType, $class) = $this->getPhpTypeAndClass($docType); + + if ('array' === $docType) { + return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, null, null); + } + return new Type($phpType, $nullable, $class); } From ac0cd15402e8dd46baad8f6ac9ae75c72dc6d5ba Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 27 Jul 2018 17:20:18 +0200 Subject: [PATCH 03/66] Remove the Expires header when calling Response::expire() --- src/Symfony/Component/HttpFoundation/Response.php | 1 + src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 10581146facaa..6b6308e36c2ee 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -675,6 +675,7 @@ public function expire() { if ($this->isFresh()) { $this->headers->set('Age', $this->getMaxAge()); + $this->headers->remove('Expires'); } return $this; diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index 881a68e98b3dd..fa3a40539db9d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -362,6 +362,11 @@ public function testExpire() $response->headers->set('Expires', -1); $response->expire(); $this->assertNull($response->headers->get('Age'), '->expire() does not set the Age when the response is expired'); + + $response = new Response(); + $response->headers->set('Expires', date(DATE_RFC2822, time() + 600)); + $response->expire(); + $this->assertNull($response->headers->get('Expires'), '->expire() removes the Expires header when the response is fresh'); } public function testGetTtl() From e843bb86c88c9a52a6c9d3a98afb11f796624abe Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 24 Jul 2018 11:19:17 +0200 Subject: [PATCH 04/66] [DI] Fix false-positive circular ref leading to wrong exceptions or infinite loops at runtime --- .../ResolveReferencesToAliasesPass.php | 2 +- .../DependencyInjection/Container.php | 2 +- .../DependencyInjection/ContainerBuilder.php | 94 +++++------ .../DependencyInjection/Dumper/PhpDumper.php | 137 +++++++++------- .../Tests/ContainerBuilderTest.php | 6 + .../Tests/Dumper/PhpDumperTest.php | 53 ++---- .../containers/container_almost_circular.php | 46 ++++++ .../php/services_almost_circular_private.php | 125 +++++++++++++- .../php/services_almost_circular_public.php | 155 ++++++++++++++++++ 9 files changed, 474 insertions(+), 146 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php index 8ffb245c12f2c..839af1ae232d3 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php @@ -66,7 +66,7 @@ private function getDefinitionId($id, ContainerBuilder $container) $seen = array(); while ($container->hasAlias($id)) { if (isset($seen[$id])) { - throw new ServiceCircularReferenceException($id, array_keys($seen)); + throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), array($id))); } $seen[$id] = true; $id = $container->normalizeId($container->getAlias($id)); diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 5dfa1da59dc50..4d3e3883d428a 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -294,7 +294,7 @@ public function get($id, $invalidBehavior = /* self::EXCEPTION_ON_INVALID_REFERE } if (isset($this->loading[$id])) { - throw new ServiceCircularReferenceException($id, array_keys($this->loading)); + throw new ServiceCircularReferenceException($id, array_merge(array_keys($this->loading), array($id))); } $this->loading[$id] = true; diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index c2b73e70c84dc..7a66382f6058b 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -122,7 +122,6 @@ class ContainerBuilder extends Container implements TaggedContainerInterface private $autoconfiguredInstanceof = array(); private $removedIds = array(); - private $alreadyLoading = array(); private static $internalTypes = array( 'int' => true, @@ -588,22 +587,32 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV return $this->doGet($id, $invalidBehavior); } - private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = array()) + private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, $isConstructorArgument = false) { $id = $this->normalizeId($id); if (isset($inlineServices[$id])) { return $inlineServices[$id]; } - if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) { - return parent::get($id, $invalidBehavior); + if (null === $inlineServices) { + $isConstructorArgument = true; + $inlineServices = array(); } - if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) { - return $service; + try { + if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) { + return parent::get($id, $invalidBehavior); + } + if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) { + return $service; + } + } catch (ServiceCircularReferenceException $e) { + if ($isConstructorArgument) { + throw $e; + } } if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) { - return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices); + return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices, $isConstructorArgument); } try { @@ -616,16 +625,17 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_ throw $e; } - $loading = isset($this->alreadyLoading[$id]) ? 'loading' : 'alreadyLoading'; - $this->{$loading}[$id] = true; + if ($isConstructorArgument) { + $this->loading[$id] = true; + } try { - $service = $this->createService($definition, $inlineServices, $id); + return $this->createService($definition, $inlineServices, $isConstructorArgument, $id); } finally { - unset($this->{$loading}[$id]); + if ($isConstructorArgument) { + unset($this->loading[$id]); + } } - - return $service; } /** @@ -1092,7 +1102,7 @@ public function findDefinition($id) * @throws RuntimeException When the service is a synthetic service * @throws InvalidArgumentException When configure callable is not callable */ - private function createService(Definition $definition, array &$inlineServices, $id = null, $tryProxy = true) + private function createService(Definition $definition, array &$inlineServices, $isConstructorArgument = false, $id = null, $tryProxy = true) { if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) { return $inlineServices[$h]; @@ -1110,16 +1120,14 @@ private function createService(Definition $definition, array &$inlineServices, $ @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED); } - if ($tryProxy && $definition->isLazy()) { - $proxy = $this - ->getProxyInstantiator() - ->instantiateProxy( - $this, - $definition, - $id, function () use ($definition, &$inlineServices, $id) { - return $this->createService($definition, $inlineServices, $id, false); - } - ); + if ($tryProxy && $definition->isLazy() && !$tryProxy = !($proxy = $this->proxyInstantiator) || $proxy instanceof RealServiceInstantiator) { + $proxy = $proxy->instantiateProxy( + $this, + $definition, + $id, function () use ($definition, &$inlineServices, $id) { + return $this->createService($definition, $inlineServices, true, $id, false); + } + ); $this->shareService($definition, $proxy, $id, $inlineServices); return $proxy; @@ -1131,19 +1139,21 @@ private function createService(Definition $definition, array &$inlineServices, $ require_once $parameterBag->resolveValue($definition->getFile()); } - $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices); - - if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) { - return $this->services[$id]; - } + $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices, $isConstructorArgument); if (null !== $factory = $definition->getFactory()) { if (\is_array($factory)) { - $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices), $factory[1]); + $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices, $isConstructorArgument), $factory[1]); } elseif (!\is_string($factory)) { throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); } + } + if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) { + return $this->services[$id]; + } + + if (null !== $factory) { $service = \call_user_func_array($factory, $arguments); if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) { @@ -1214,11 +1224,11 @@ public function resolveServices($value) return $this->doResolveServices($value); } - private function doResolveServices($value, array &$inlineServices = array()) + private function doResolveServices($value, array &$inlineServices = array(), $isConstructorArgument = false) { if (\is_array($value)) { foreach ($value as $k => $v) { - $value[$k] = $this->doResolveServices($v, $inlineServices); + $value[$k] = $this->doResolveServices($v, $inlineServices, $isConstructorArgument); } } elseif ($value instanceof ServiceClosureArgument) { $reference = $value->getValues()[0]; @@ -1261,9 +1271,9 @@ private function doResolveServices($value, array &$inlineServices = array()) return $count; }); } elseif ($value instanceof Reference) { - $value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices); + $value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices, $isConstructorArgument); } elseif ($value instanceof Definition) { - $value = $this->createService($value, $inlineServices); + $value = $this->createService($value, $inlineServices, $isConstructorArgument); } elseif ($value instanceof Parameter) { $value = $this->getParameter((string) $value); } elseif ($value instanceof Expression) { @@ -1584,20 +1594,6 @@ protected function getEnv($name) } } - /** - * Retrieves the currently set proxy instantiator or instantiates one. - * - * @return InstantiatorInterface - */ - private function getProxyInstantiator() - { - if (!$this->proxyInstantiator) { - $this->proxyInstantiator = new RealServiceInstantiator(); - } - - return $this->proxyInstantiator; - } - private function callMethod($service, $call, array &$inlineServices) { foreach (self::getServiceConditionals($call[1]) as $s) { @@ -1627,7 +1623,7 @@ private function shareService(Definition $definition, $service, $id, array &$inl if (null !== $id && $definition->isShared()) { $this->services[$id] = $service; - unset($this->loading[$id], $this->alreadyLoading[$id]); + unset($this->loading[$id]); } } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 71e776310b270..cf6495b9c66f3 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -138,6 +138,29 @@ public function dump(array $options = array()) $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass); + if ($this->getProxyDumper() instanceof NullDumper) { + (new AnalyzeServiceReferencesPass(true))->process($this->container); + $this->circularReferences = array(); + $checkedNodes = array(); + foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { + $currentPath = array($id => $id); + $this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); + } + foreach ($this->circularReferences as $parent => $ids) { + $path = array($parent); + while (!isset($ids[$parent])) { + foreach ($ids as $id) { + $path[] = $id; + $ids = $this->circularReferences[$id]; + break; + } + } + $path[] = $parent.'". Try running "composer require symfony/proxy-manager-bridge'; + + throw new ServiceCircularReferenceException($parent, $path); + } + } + (new AnalyzeServiceReferencesPass())->process($this->container); $this->circularReferences = array(); $checkedNodes = array(); @@ -286,21 +309,18 @@ private function getProxyDumper() * * @return string */ - private function addServiceLocalTempVariables($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions, \SplObjectStorage $allInlinedDefinitions) + private function addServiceLocalTempVariables($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions, array $serviceCalls, $preInstance = false) { - $allCalls = $calls = $behavior = array(); - - foreach ($allInlinedDefinitions as $def) { - $arguments = array($def->getArguments(), $def->getFactory(), $def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()); - $this->getServiceCallsFromArguments($arguments, $allCalls, false, $cId, $behavior, $allInlinedDefinitions[$def]); - } + $calls = array(); - $isPreInstance = isset($inlinedDefinitions[$definition]) && isset($this->circularReferences[$cId]) && !$this->getProxyDumper()->isProxyCandidate($definition) && $definition->isShared(); foreach ($inlinedDefinitions as $def) { - $this->getServiceCallsFromArguments(array($def->getArguments(), $def->getFactory()), $calls, $isPreInstance, $cId); + if ($preInstance && !$inlinedDefinitions[$def][1]) { + continue; + } + $this->getServiceCallsFromArguments(array($def->getArguments(), $def->getFactory()), $calls, $preInstance, $cId); if ($def !== $definition) { $arguments = array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()); - $this->getServiceCallsFromArguments($arguments, $calls, $isPreInstance && !$this->hasReference($cId, $arguments, true), $cId); + $this->getServiceCallsFromArguments($arguments, $calls, $preInstance && !$this->hasReference($cId, $arguments, true), $cId); } } if (!isset($inlinedDefinitions[$definition])) { @@ -309,23 +329,23 @@ private function addServiceLocalTempVariables($cId, Definition $definition, \Spl } $code = ''; - foreach ($calls as $id => $callCount) { + foreach ($calls as $id => list($callCount)) { if ('service_container' === $id || $id === $cId || isset($this->referenceVariables[$id])) { continue; } - if ($callCount <= 1 && $allCalls[$id] <= 1) { + if ($callCount <= 1 && $serviceCalls[$id][0] <= 1) { continue; } $name = $this->getNextVariableName(); $this->referenceVariables[$id] = new Variable($name); - $reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id] ? new Reference($id, $behavior[$id]) : null; + $reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $serviceCalls[$id][1] ? new Reference($id, $serviceCalls[$id][1]) : null; $code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($id, $reference)); } if ('' !== $code) { - if ($isPreInstance) { + if ($preInstance) { $code .= <<services['$cId'])) { @@ -347,7 +367,7 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre $node = $edge->getDestNode(); $id = $node->getId(); - if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) { + if ($node->getValue() && (($edge->isLazy() && !$this->getProxyDumper() instanceof NullDumper) || $edge->isWeak())) { // no-op } elseif (isset($currentPath[$id])) { foreach (array_reverse($currentPath) as $parentId) { @@ -425,23 +445,21 @@ private function generateProxyClasses() * * @return string */ - private function addServiceInclude($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions) + private function addServiceInclude($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions, array $serviceCalls) { $code = ''; if ($this->inlineRequires && !$this->isHotPath($definition)) { - $lineage = $calls = $behavior = array(); + $lineage = array(); foreach ($inlinedDefinitions as $def) { if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { $this->collectLineage($class, $lineage); } - $arguments = array($def->getArguments(), $def->getFactory(), $def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()); - $this->getServiceCallsFromArguments($arguments, $calls, false, $cId, $behavior, $inlinedDefinitions[$def]); } - foreach ($calls as $id => $callCount) { + foreach ($serviceCalls as $id => list($callCount, $behavior)) { if ('service_container' !== $id && $id !== $cId - && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior[$id] + && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior && $this->container->has($id) && $this->isTrivialInstance($def = $this->container->findDefinition($id)) && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass()) @@ -476,24 +494,24 @@ private function addServiceInclude($cId, Definition $definition, \SplObjectStora * @throws RuntimeException When the factory definition is incomplete * @throws ServiceCircularReferenceException When a circular reference is detected */ - private function addServiceInlinedDefinitions($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, &$isSimpleInstance) + private function addServiceInlinedDefinitions($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, &$isSimpleInstance, $preInstance = false) { $code = ''; foreach ($inlinedDefinitions as $def) { - if ($definition === $def) { + if ($definition === $def || isset($this->definitionVariables[$def])) { continue; } - if ($inlinedDefinitions[$def] <= 1 && !$def->getMethodCalls() && !$def->getProperties() && !$def->getConfigurator() && false === strpos($this->dumpValue($def->getClass()), '$')) { + if ($inlinedDefinitions[$def][0] <= 1 && !$def->getMethodCalls() && !$def->getProperties() && !$def->getConfigurator() && false === strpos($this->dumpValue($def->getClass()), '$')) { continue; } - if (isset($this->definitionVariables[$def])) { - $name = $this->definitionVariables[$def]; - } else { - $name = $this->getNextVariableName(); - $this->definitionVariables[$def] = new Variable($name); + if ($preInstance && !$inlinedDefinitions[$def][1]) { + continue; } + $name = $this->getNextVariableName(); + $this->definitionVariables[$def] = new Variable($name); + // a construct like: // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a); // this is an indication for a wrong implementation, you can circumvent this problem @@ -502,7 +520,7 @@ private function addServiceInlinedDefinitions($id, Definition $definition, \SplO // $a = new ServiceA(ServiceB $b); // $b->setServiceA(ServiceA $a); if (isset($inlinedDefinitions[$definition]) && $this->hasReference($id, array($def->getArguments(), $def->getFactory()))) { - throw new ServiceCircularReferenceException($id, array($id)); + throw new ServiceCircularReferenceException($id, array($id, '...', $id)); } $code .= $this->addNewInstance($def, '$'.$name, ' = ', $id); @@ -558,6 +576,7 @@ private function addServiceInstance($id, Definition $definition, $isSimpleInstan } $code = $this->addNewInstance($definition, $return, $instantiation, $id); + $this->referenceVariables[$id] = new Variable('instance'); if (!$isSimpleInstance) { $code .= "\n"; @@ -657,8 +676,6 @@ private function addServiceProperties(Definition $definition, $variableName = 'i */ private function addServiceInlinedDefinitionsSetup($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, $isSimpleInstance) { - $this->referenceVariables[$id] = new Variable('instance'); - $code = ''; foreach ($inlinedDefinitions as $def) { if ($definition === $def || !$this->hasReference($id, array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()), true)) { @@ -668,7 +685,7 @@ private function addServiceInlinedDefinitionsSetup($id, Definition $definition, // if the instance is simple, the return statement has already been generated // so, the only possible way to get there is because of a circular reference if ($isSimpleInstance) { - throw new ServiceCircularReferenceException($id, array($id)); + throw new ServiceCircularReferenceException($id, array($id, '...', $id)); } $name = (string) $this->definitionVariables[$def]; @@ -805,6 +822,7 @@ protected function {$methodName}($lazyInitialization) $inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition)); $constructorDefinitions = $this->getDefinitionsFromArguments(array($definition->getArguments(), $definition->getFactory())); $otherDefinitions = new \SplObjectStorage(); + $serviceCalls = array(); foreach ($inlinedDefinitions as $def) { if ($def === $definition || isset($constructorDefinitions[$def])) { @@ -812,16 +830,21 @@ protected function {$methodName}($lazyInitialization) } else { $otherDefinitions[$def] = $inlinedDefinitions[$def]; } + $arguments = array($def->getArguments(), $def->getFactory(), $def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()); + $this->getServiceCallsFromArguments($arguments, $serviceCalls, false, $id); } $isSimpleInstance = !$definition->getProperties() && !$definition->getMethodCalls() && !$definition->getConfigurator(); + $preInstance = isset($this->circularReferences[$id]) && !$this->getProxyDumper()->isProxyCandidate($definition) && $definition->isShared(); $code .= - $this->addServiceInclude($id, $definition, $inlinedDefinitions). - $this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions, $inlinedDefinitions). - $this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance). + $this->addServiceInclude($id, $definition, $inlinedDefinitions, $serviceCalls). + $this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions, $serviceCalls, $preInstance). + $this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance, $preInstance). $this->addServiceInstance($id, $definition, $isSimpleInstance). - $this->addServiceLocalTempVariables($id, $definition, $otherDefinitions, $inlinedDefinitions). + $this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions->offsetUnset($definition) ?: $constructorDefinitions, $serviceCalls). + $this->addServiceLocalTempVariables($id, $definition, $otherDefinitions, $serviceCalls). + $this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance). $this->addServiceInlinedDefinitions($id, $definition, $otherDefinitions, $isSimpleInstance). $this->addServiceInlinedDefinitionsSetup($id, $definition, $inlinedDefinitions, $isSimpleInstance). $this->addServiceProperties($definition). @@ -1558,30 +1581,29 @@ private function getServiceConditionals($value) /** * Builds service calls from arguments. + * + * Populates $calls with "referenced id" => ["reference count", "invalid behavior"] pairs. */ - private function getServiceCallsFromArguments(array $arguments, array &$calls, $isPreInstance, $callerId, array &$behavior = array(), $step = 1) + private function getServiceCallsFromArguments(array $arguments, array &$calls, $preInstance, $callerId) { foreach ($arguments as $argument) { if (\is_array($argument)) { - $this->getServiceCallsFromArguments($argument, $calls, $isPreInstance, $callerId, $behavior, $step); + $this->getServiceCallsFromArguments($argument, $calls, $preInstance, $callerId); } elseif ($argument instanceof Reference) { $id = $this->container->normalizeId($argument); if (!isset($calls[$id])) { - $calls[$id] = (int) ($isPreInstance && isset($this->circularReferences[$callerId][$id])); - } - if (!isset($behavior[$id])) { - $behavior[$id] = $argument->getInvalidBehavior(); + $calls[$id] = array((int) ($preInstance && isset($this->circularReferences[$callerId][$id])), $argument->getInvalidBehavior()); } else { - $behavior[$id] = min($behavior[$id], $argument->getInvalidBehavior()); + $calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior()); } - $calls[$id] += $step; + ++$calls[$id][0]; } } } - private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null) + private function getDefinitionsFromArguments(array $arguments, $isConstructorArgument = true, \SplObjectStorage $definitions = null) { if (null === $definitions) { $definitions = new \SplObjectStorage(); @@ -1589,22 +1611,23 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage foreach ($arguments as $argument) { if (\is_array($argument)) { - $this->getDefinitionsFromArguments($argument, $definitions); + $this->getDefinitionsFromArguments($argument, $isConstructorArgument, $definitions); } elseif (!$argument instanceof Definition) { // no-op } elseif (isset($definitions[$argument])) { - $definitions[$argument] = 1 + $definitions[$argument]; + $def = $definitions[$argument]; + $definitions[$argument] = array(1 + $def[0], $isConstructorArgument || $def[1]); } else { - $definitions[$argument] = 1; - $this->getDefinitionsFromArguments($argument->getArguments(), $definitions); - $this->getDefinitionsFromArguments(array($argument->getFactory()), $definitions); - $this->getDefinitionsFromArguments($argument->getProperties(), $definitions); - $this->getDefinitionsFromArguments($argument->getMethodCalls(), $definitions); - $this->getDefinitionsFromArguments(array($argument->getConfigurator()), $definitions); + $definitions[$argument] = array(1, $isConstructorArgument); + $this->getDefinitionsFromArguments($argument->getArguments(), $isConstructorArgument, $definitions); + $this->getDefinitionsFromArguments(array($argument->getFactory()), $isConstructorArgument, $definitions); + $this->getDefinitionsFromArguments($argument->getProperties(), false, $definitions); + $this->getDefinitionsFromArguments($argument->getMethodCalls(), false, $definitions); + $this->getDefinitionsFromArguments(array($argument->getConfigurator()), false, $definitions); // move current definition last in the list - $nbOccurences = $definitions[$argument]; + $def = $definitions[$argument]; unset($definitions[$argument]); - $definitions[$argument] = $nbOccurences; + $definitions[$argument] = $def; } } @@ -1640,7 +1663,7 @@ private function hasReference($id, array $arguments, $deep = false, array &$visi return true; } - if (!$deep || isset($visited[$argumentId]) || !isset($this->circularReferences[$id][$argumentId])) { + if (!$deep || isset($visited[$argumentId]) || !isset($this->circularReferences[$argumentId])) { continue; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 1d2640e7878f1..f3f762c3ad500 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -1355,6 +1355,12 @@ public function testAlmostCircular($visibility) $foo5 = $container->get('foo5'); $this->assertSame($foo5, $foo5->bar->foo); + + $manager = $container->get('manager'); + $this->assertEquals(new \stdClass(), $manager); + + $manager = $container->get('manager2'); + $this->assertEquals(new \stdClass(), $manager); } public function provideAlmostCircular() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index e90edd50283b4..b876bf48da95d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -23,6 +23,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; @@ -530,50 +531,22 @@ public function testCircularReferenceAllowanceForLazyServices() $container->compile(); $dumper = new PhpDumper($container); + $dumper->setProxyDumper(new \DummyProxyDumper()); $dumper->dump(); $this->addToAssertionCount(1); - } - - public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices() - { - /* - * test graph: - * [connection] -> [event_manager] --> [entity_manager](lazy) - * | - * --(call)- addEventListener ("@lazy_service") - * - * [lazy_service](lazy) -> [entity_manager](lazy) - * - */ - - $container = new ContainerBuilder(); - - $eventManagerDefinition = new Definition('stdClass'); - - $connectionDefinition = $container->register('connection', 'stdClass')->setPublic(true); - $connectionDefinition->addArgument($eventManagerDefinition); - - $container->register('entity_manager', 'stdClass') - ->setPublic(true) - ->setLazy(true) - ->addArgument(new Reference('connection')); - - $lazyServiceDefinition = $container->register('lazy_service', 'stdClass'); - $lazyServiceDefinition->setPublic(true); - $lazyServiceDefinition->setLazy(true); - $lazyServiceDefinition->addArgument(new Reference('entity_manager')); - - $eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service'))); - - $container->compile(); $dumper = new PhpDumper($container); - $dumper->setProxyDumper(new \DummyProxyDumper()); - $dumper->dump(); + $message = 'Circular reference detected for service "bar", path: "bar -> foo -> bar". Try running "composer require symfony/proxy-manager-bridge".'; + if (method_exists($this, 'expectException')) { + $this->expectException(ServiceCircularReferenceException::class); + $this->expectExceptionMessage($message); + } else { + $this->setExpectedException(ServiceCircularReferenceException::class, $message); + } - $this->addToAssertionCount(1); + $dumper->dump(); } public function testDedupLazyProxy() @@ -851,6 +824,12 @@ public function testAlmostCircular($visibility) $foo5 = $container->get('foo5'); $this->assertSame($foo5, $foo5->bar->foo); + + $manager = $container->get('manager'); + $this->assertEquals(new \stdClass(), $manager); + + $manager = $container->get('manager2'); + $this->assertEquals(new \stdClass(), $manager); } public function provideAlmostCircular() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php index dff937ccdbb7f..2079e136b74b3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php @@ -55,4 +55,50 @@ ->addArgument(new Reference('foo5')) ->setProperty('foo', new Reference('foo5')); +// doctrine-like event system + some extra + +$container->register('manager', 'stdClass')->setPublic(true) + ->addArgument(new Reference('connection')); + +$container->register('logger', 'stdClass')->setPublic(true) + ->addArgument(new Reference('connection')) + ->setProperty('handler', (new Definition('stdClass'))->addArgument(new Reference('manager'))) +; +$container->register('connection', 'stdClass')->setPublic(true) + ->addArgument(new Reference('dispatcher')) + ->addArgument(new Reference('config')); + +$container->register('config', 'stdClass')->setPublic(false) + ->setProperty('logger', new Reference('logger')); + +$container->register('dispatcher', 'stdClass')->setPublic($public) + ->setLazy($public) + ->setProperty('subscriber', new Reference('subscriber')); + +$container->register('subscriber', 'stdClass')->setPublic(true) + ->addArgument(new Reference('manager')); + +// doctrine-like event system + some extra (bis) + +$container->register('manager2', 'stdClass')->setPublic(true) + ->addArgument(new Reference('connection2')); + +$container->register('logger2', 'stdClass')->setPublic(false) + ->addArgument(new Reference('connection2')) + ->setProperty('handler2', (new Definition('stdClass'))->addArgument(new Reference('manager2'))) +; +$container->register('connection2', 'stdClass')->setPublic(true) + ->addArgument(new Reference('dispatcher2')) + ->addArgument(new Reference('config2')); + +$container->register('config2', 'stdClass')->setPublic(false) + ->setProperty('logger2', new Reference('logger2')); + +$container->register('dispatcher2', 'stdClass')->setPublic($public) + ->setLazy($public) + ->setProperty('subscriber2', new Reference('subscriber2')); + +$container->register('subscriber2', 'stdClass')->setPublic(false) + ->addArgument(new Reference('manager2')); + return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php index 45fb2432c33c9..f0ad8ef31c00a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php @@ -25,10 +25,16 @@ public function __construct() $this->methodMap = array( 'bar2' => 'getBar2Service', 'bar3' => 'getBar3Service', + 'connection' => 'getConnectionService', + 'connection2' => 'getConnection2Service', 'foo' => 'getFooService', 'foo2' => 'getFoo2Service', 'foo5' => 'getFoo5Service', 'foobar4' => 'getFoobar4Service', + 'logger' => 'getLoggerService', + 'manager' => 'getManagerService', + 'manager2' => 'getManager2Service', + 'subscriber' => 'getSubscriberService', ); $this->aliases = array(); @@ -41,10 +47,16 @@ public function getRemovedIds() 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, 'bar' => true, 'bar5' => true, + 'config' => true, + 'config2' => true, + 'dispatcher' => true, + 'dispatcher2' => true, 'foo4' => true, 'foobar' => true, 'foobar2' => true, 'foobar3' => true, + 'logger2' => true, + 'subscriber2' => true, ); } @@ -95,6 +107,49 @@ protected function getBar3Service() return $instance; } + /** + * Gets the public 'connection' shared service. + * + * @return \stdClass + */ + protected function getConnectionService() + { + $a = new \stdClass(); + + $b = new \stdClass(); + + $this->services['connection'] = $instance = new \stdClass($a, $b); + + $a->subscriber = ${($_ = isset($this->services['subscriber']) ? $this->services['subscriber'] : $this->getSubscriberService()) && false ?: '_'}; + $b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'}; + + return $instance; + } + + /** + * Gets the public 'connection2' shared service. + * + * @return \stdClass + */ + protected function getConnection2Service() + { + $a = new \stdClass(); + + $b = new \stdClass(); + + $this->services['connection2'] = $instance = new \stdClass($a, $b); + + $c = ${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}; + + $d = new \stdClass($instance); + + $a->subscriber2 = new \stdClass($c); + $d->handler2 = new \stdClass($c); + $b->logger2 = $d; + + return $instance; + } + /** * Gets the public 'foo' shared service. * @@ -136,7 +191,7 @@ protected function getFoo5Service() { $this->services['foo5'] = $instance = new \stdClass(); - $a = new \stdClass(${($_ = isset($this->services['foo5']) ? $this->services['foo5'] : $this->getFoo5Service()) && false ?: '_'}); + $a = new \stdClass($instance); $a->foo = $instance; @@ -160,4 +215,72 @@ protected function getFoobar4Service() return $instance; } + + /** + * Gets the public 'logger' shared service. + * + * @return \stdClass + */ + protected function getLoggerService() + { + $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; + + if (isset($this->services['logger'])) { + return $this->services['logger']; + } + + $this->services['logger'] = $instance = new \stdClass($a); + + $instance->handler = new \stdClass(${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}); + + return $instance; + } + + /** + * Gets the public 'manager' shared service. + * + * @return \stdClass + */ + protected function getManagerService() + { + $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; + + if (isset($this->services['manager'])) { + return $this->services['manager']; + } + + return $this->services['manager'] = new \stdClass($a); + } + + /** + * Gets the public 'manager2' shared service. + * + * @return \stdClass + */ + protected function getManager2Service() + { + $a = ${($_ = isset($this->services['connection2']) ? $this->services['connection2'] : $this->getConnection2Service()) && false ?: '_'}; + + if (isset($this->services['manager2'])) { + return $this->services['manager2']; + } + + return $this->services['manager2'] = new \stdClass($a); + } + + /** + * Gets the public 'subscriber' shared service. + * + * @return \stdClass + */ + protected function getSubscriberService() + { + $a = ${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}; + + if (isset($this->services['subscriber'])) { + return $this->services['subscriber']; + } + + return $this->services['subscriber'] = new \stdClass($a); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php index be18eb183abd0..784346b9242fa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php @@ -26,6 +26,10 @@ public function __construct() 'bar' => 'getBarService', 'bar3' => 'getBar3Service', 'bar5' => 'getBar5Service', + 'connection' => 'getConnectionService', + 'connection2' => 'getConnection2Service', + 'dispatcher' => 'getDispatcherService', + 'dispatcher2' => 'getDispatcher2Service', 'foo' => 'getFooService', 'foo2' => 'getFoo2Service', 'foo4' => 'getFoo4Service', @@ -34,6 +38,10 @@ public function __construct() 'foobar2' => 'getFoobar2Service', 'foobar3' => 'getFoobar3Service', 'foobar4' => 'getFoobar4Service', + 'logger' => 'getLoggerService', + 'manager' => 'getManagerService', + 'manager2' => 'getManager2Service', + 'subscriber' => 'getSubscriberService', ); $this->aliases = array(); @@ -45,6 +53,10 @@ public function getRemovedIds() 'Psr\\Container\\ContainerInterface' => true, 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, 'bar2' => true, + 'config' => true, + 'config2' => true, + 'logger2' => true, + 'subscriber2' => true, ); } @@ -115,6 +127,81 @@ protected function getBar5Service() return $instance; } + /** + * Gets the public 'connection' shared service. + * + * @return \stdClass + */ + protected function getConnectionService() + { + $a = ${($_ = isset($this->services['dispatcher']) ? $this->services['dispatcher'] : $this->getDispatcherService()) && false ?: '_'}; + + if (isset($this->services['connection'])) { + return $this->services['connection']; + } + + $b = new \stdClass(); + + $this->services['connection'] = $instance = new \stdClass($a, $b); + + $b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'}; + + return $instance; + } + + /** + * Gets the public 'connection2' shared service. + * + * @return \stdClass + */ + protected function getConnection2Service() + { + $a = ${($_ = isset($this->services['dispatcher2']) ? $this->services['dispatcher2'] : $this->getDispatcher2Service()) && false ?: '_'}; + + if (isset($this->services['connection2'])) { + return $this->services['connection2']; + } + + $b = new \stdClass(); + + $this->services['connection2'] = $instance = new \stdClass($a, $b); + + $c = new \stdClass($instance); + + $c->handler2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}); + $b->logger2 = $c; + + return $instance; + } + + /** + * Gets the public 'dispatcher' shared service. + * + * @return \stdClass + */ + protected function getDispatcherService($lazyLoad = true) + { + $this->services['dispatcher'] = $instance = new \stdClass(); + + $instance->subscriber = ${($_ = isset($this->services['subscriber']) ? $this->services['subscriber'] : $this->getSubscriberService()) && false ?: '_'}; + + return $instance; + } + + /** + * Gets the public 'dispatcher2' shared service. + * + * @return \stdClass + */ + protected function getDispatcher2Service($lazyLoad = true) + { + $this->services['dispatcher2'] = $instance = new \stdClass(); + + $instance->subscriber2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}); + + return $instance; + } + /** * Gets the public 'foo' shared service. * @@ -232,4 +319,72 @@ protected function getFoobar4Service() return $instance; } + + /** + * Gets the public 'logger' shared service. + * + * @return \stdClass + */ + protected function getLoggerService() + { + $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; + + if (isset($this->services['logger'])) { + return $this->services['logger']; + } + + $this->services['logger'] = $instance = new \stdClass($a); + + $instance->handler = new \stdClass(${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}); + + return $instance; + } + + /** + * Gets the public 'manager' shared service. + * + * @return \stdClass + */ + protected function getManagerService() + { + $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; + + if (isset($this->services['manager'])) { + return $this->services['manager']; + } + + return $this->services['manager'] = new \stdClass($a); + } + + /** + * Gets the public 'manager2' shared service. + * + * @return \stdClass + */ + protected function getManager2Service() + { + $a = ${($_ = isset($this->services['connection2']) ? $this->services['connection2'] : $this->getConnection2Service()) && false ?: '_'}; + + if (isset($this->services['manager2'])) { + return $this->services['manager2']; + } + + return $this->services['manager2'] = new \stdClass($a); + } + + /** + * Gets the public 'subscriber' shared service. + * + * @return \stdClass + */ + protected function getSubscriberService() + { + $a = ${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}; + + if (isset($this->services['subscriber'])) { + return $this->services['subscriber']; + } + + return $this->services['subscriber'] = new \stdClass($a); + } } From 15835bc7dfb3bcad3deb9d11f66ba8eff942e3d8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:12:10 +0200 Subject: [PATCH 05/66] updated CHANGELOG for 2.8.44 --- CHANGELOG-2.8.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 4db4bfd7cb1e7..4760af369f84f 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,14 @@ in 2.8 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1 +* 2.8.44 (2018-08-01) + + * security #cve-2018-14774 [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer (nicolas-grekas) + * security #cve-2018-14773 [HttpFoundation] Remove support for legacy and risky HTTP headers (nicolas-grekas) + * bug #28003 [HttpKernel] Fixes invalid REMOTE_ADDR in inline subrequest when configuring trusted proxy with subnet (netiul) + * bug #28045 [HttpFoundation] Fix Cookie::isCleared (ro0NL) + * bug #28080 [HttpFoundation] fixed using _method parameter with invalid type (Phobetor) + * 2.8.43 (2018-07-23) * bug #28005 [HttpKernel] Fixed templateExists on parse error of the template name (yceruto) From 282e062226e26ffc43fda998ad55935b49710c39 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:12:26 +0200 Subject: [PATCH 06/66] update CONTRIBUTORS for 2.8.44 --- CONTRIBUTORS.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b6eef0b63198c..bf391b7ee79ce 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -32,10 +32,10 @@ Symfony is the result of the work of many people who made the code better - Lukas Kahwe Smith (lsmith) - Martin Hasoň (hason) - Jeremy Mikola (jmikola) + - Samuel ROZE (sroze) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - - Samuel ROZE (sroze) - Jules Pietri (heah) - Eriksen Costa (eriksencosta) - Guilhem Niot (energetick) @@ -67,8 +67,8 @@ Symfony is the result of the work of many people who made the code better - Bilal Amarni (bamarni) - Jérémy DERUSSÉ (jderusse) - Florin Patan (florinpatan) - - Mathieu Piot (mpiot) - Gábor Egyed (1ed) + - Mathieu Piot (mpiot) - Michel Weimerskirch (mweimerskirch) - Titouan Galopin (tgalopin) - Andrej Hudec (pulzarraider) @@ -101,9 +101,9 @@ Symfony is the result of the work of many people who made the code better - Paráda József (paradajozsef) - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER + - Grégoire Paris (greg0ire) - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - - Grégoire Paris (greg0ire) - Brice BERNARD (brikou) - Valentin Udaltsov (vudaltsov) - gadelat (gadelat) @@ -159,6 +159,7 @@ Symfony is the result of the work of many people who made the code better - Vyacheslav Pavlov - Richard van Laak (rvanlaak) - Richard Shank (iampersistent) + - Jannik Zschiesche (apfelbox) - Thomas Rabaix (rande) - Rouven Weßling (realityking) - Clemens Tolboom @@ -170,7 +171,6 @@ Symfony is the result of the work of many people who made the code better - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba - - Jannik Zschiesche (apfelbox) - GDIBass - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - James Halsall (jaitsu) @@ -284,6 +284,7 @@ Symfony is the result of the work of many people who made the code better - Andreas Schempp (aschempp) - jdhoek - Pavel Batanov (scaytrase) + - Massimiliano Arione (garak) - Bob den Otter (bopp) - Nikita Konstantinov - Wodor Wodorski @@ -332,7 +333,6 @@ Symfony is the result of the work of many people who made the code better - Adrian Rudnik (kreischweide) - Francesc Rosàs (frosas) - Romain Pierre (romain-pierre) - - Massimiliano Arione (garak) - Julien Galenski (ruian) - Bongiraud Dominique - janschoenherr @@ -407,6 +407,7 @@ Symfony is the result of the work of many people who made the code better - Karoly Negyesi (chx) - Ivan Kurnosov - Xavier HAUSHERR + - David Prévot - Albert Jessurum (ajessu) - Laszlo Korte - Miha Vrhovnik @@ -438,6 +439,7 @@ Symfony is the result of the work of many people who made the code better - Mihai Stancu - Olivier Dolbeau (odolbeau) - Jan Rosier (rosier) + - Alessandro Lai (jean85) - Arturs Vonda - Josip Kruslin - Asmir Mustafic (goetas) @@ -565,7 +567,6 @@ Symfony is the result of the work of many people who made the code better - Disquedur - Michiel Boeckaert (milio) - Geoffrey Tran (geoff) - - David Prévot - Jan Behrens - Mantas Var (mvar) - Sebastian Krebs @@ -584,7 +585,6 @@ Symfony is the result of the work of many people who made the code better - Max Rath (drak3) - Stéphane Escandell (sescandell) - Konstantin S. M. Möllers (ksmmoellers) - - Alessandro Lai (jean85) - James Johnston - Sinan Eldem - Alexandre Dupuy (satchette) @@ -713,6 +713,7 @@ Symfony is the result of the work of many people who made the code better - Yuen-Chi Lian - Besnik Br - Jose Gonzalez + - Oleksii Zhurbytskyi - Dariusz Ruminski - Joshua Nye - Claudio Zizza @@ -882,6 +883,7 @@ Symfony is the result of the work of many people who made the code better - datibbaw - Erik Saunier (snickers) - Rootie + - Kyle - Raul Fraile (raulfraile) - sensio - Sebastien Morel (plopix) @@ -1382,6 +1384,7 @@ Symfony is the result of the work of many people who made the code better - Matt Wells - Nicolas Appriou - stloyd + - Andreas - Chris Tickner - Andrew Coulton - Jeremy Benoist @@ -1432,7 +1435,6 @@ Symfony is the result of the work of many people who made the code better - Nicolas Bastien (nicolas_bastien) - Denis (yethee) - Andrew Zhilin (zhil) - - Oleksii Zhurbytskyi - Andy Stanberry - Felix Marezki - Normunds @@ -1973,7 +1975,6 @@ Symfony is the result of the work of many people who made the code better - fh-github@fholzhauer.de - AbdElKader Bouadjadja - DSeemiller - - Kyle - Jan Emrich - Mark Topper - Xavier REN @@ -2001,3 +2002,4 @@ Symfony is the result of the work of many people who made the code better - Matej Žilák (teo_sk) - Vladislav Vlastovskiy (vlastv) - RENAUDIN Xavier (xorrox) + - Yannick Vanhaeren (yvh) From 4abd3a8eb02458f5f8ac474e9968af9ec7e7e461 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:12:31 +0200 Subject: [PATCH 07/66] updated VERSION for 2.8.44 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e07787699bcb2..f9b22f7700e19 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.44-DEV'; + const VERSION = '2.8.44'; const VERSION_ID = 20844; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 44; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 3ff6e333dd004d3898e9cf832f01a8ac784331b5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:46:30 +0200 Subject: [PATCH 08/66] bumped Symfony version to 2.8.45 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f9b22f7700e19..32a90578342e7 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.44'; - const VERSION_ID = 20844; + const VERSION = '2.8.45-DEV'; + const VERSION_ID = 20845; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 44; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 45; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 22cb50a7ad3ce954411b03aaa6c7ce4e245d76e5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:47:43 +0200 Subject: [PATCH 09/66] updated CHANGELOG for 3.4.14 --- CHANGELOG-3.4.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index 94bbcf155cd1a..f0cde9e267b62 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,16 @@ in 3.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.4.0...v3.4.1 +* 3.4.14 (2018-08-01) + + * security #cve-2018-14774 [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer (nicolas-grekas) + * security #cve-2018-14773 [HttpFoundation] Remove support for legacy and risky HTTP headers (nicolas-grekas) + * bug #28003 [HttpKernel] Fixes invalid REMOTE_ADDR in inline subrequest when configuring trusted proxy with subnet (netiul) + * bug #28007 [FrameworkBundle] fixed guard event names for transitions (destillat) + * bug #28045 [HttpFoundation] Fix Cookie::isCleared (ro0NL) + * bug #28080 [HttpFoundation] fixed using _method parameter with invalid type (Phobetor) + * bug #28052 [HttpKernel] Fix merging bindings for controllers' locators (nicolas-grekas) + * 3.4.13 (2018-07-23) * bug #28005 [HttpKernel] Fixed templateExists on parse error of the template name (yceruto) From 2aa9ef0b4867a30a81e11e9c719c9ece6e4a6d59 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:47:47 +0200 Subject: [PATCH 10/66] updated VERSION for 3.4.14 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0093048618a69..0684f22a03232 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.14-DEV'; + const VERSION = '3.4.14'; const VERSION_ID = 30414; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; const RELEASE_VERSION = 14; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 9d7d3e71243610e83d6e6ae0ea6ba1e1c94156e8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 16:55:31 +0200 Subject: [PATCH 11/66] bumped Symfony version to 3.4.15 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0684f22a03232..0f4eeeb58abe1 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.14'; - const VERSION_ID = 30414; + const VERSION = '3.4.15-DEV'; + const VERSION_ID = 30415; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 14; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 15; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 83dcbe9096f9b7aebdda17de5ec17850c720c1b6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 23 Jul 2018 19:52:59 +0200 Subject: [PATCH 12/66] [DoctrineBridge] allow dev versions of Doctrine again --- composer.json | 4 ++-- src/Symfony/Bridge/Doctrine/composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index e0a1c53c4f158..6d5065d4d3084 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^5.5.9|>=7.0.8", "ext-xml": "*", - "doctrine/common": "~2.4@stable", + "doctrine/common": "~2.4", "fig/link-util": "^1.0", "twig/twig": "^1.35|^2.4.4", "psr/cache": "~1.0", @@ -92,7 +92,7 @@ "doctrine/cache": "~1.6", "doctrine/data-fixtures": "1.0.*", "doctrine/dbal": "~2.4", - "doctrine/orm": "~2.4,>=2.4.5,<=2.7.0", + "doctrine/orm": "~2.4,>=2.4.5", "doctrine/doctrine-bundle": "~1.4", "monolog/monolog": "~1.11", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 1535f8f42b8f8..420535b7516fd 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^5.5.9|>=7.0.8", - "doctrine/common": "~2.4@stable", + "doctrine/common": "~2.4", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, From 75ece97d37118ba26e29cd8e889732b31001f077 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Aug 2018 17:34:03 +0200 Subject: [PATCH 13/66] bumped Symfony version to 4.1.4 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 21ea5b06b1deb..00ac083e50024 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -63,12 +63,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.1.3'; - const VERSION_ID = 40103; + const VERSION = '4.1.4-DEV'; + const VERSION_ID = 40104; const MAJOR_VERSION = 4; const MINOR_VERSION = 1; - const RELEASE_VERSION = 3; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 4; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2019'; const END_OF_LIFE = '07/2019'; From 44dbea63308ae8ac29b26d4e5ce9416c08870751 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 1 Aug 2018 16:08:30 +0200 Subject: [PATCH 14/66] [Security] Call AccessListener after LogoutListener --- .../Tests/Functional/LogoutTest.php | 10 +++++++ .../Functional/app/LogoutAccess/bundles.php | 18 +++++++++++++ .../Functional/app/LogoutAccess/config.yml | 26 +++++++++++++++++++ .../Functional/app/LogoutAccess/routing.yml | 5 ++++ .../Bundle/SecurityBundle/composer.json | 2 +- .../Component/Security/Http/Firewall.php | 13 ++++++++++ .../Security/Http/Tests/FirewallTest.php | 2 +- 7 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/bundles.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/config.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/routing.yml diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php index d3c3b77fd5d61..15131290b4ee3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php @@ -49,4 +49,14 @@ public function testCsrfTokensAreClearedOnLogout() $this->assertFalse($client->getContainer()->get('security.csrf.token_storage')->hasToken('foo')); } + + public function testAccessControlDoesNotApplyOnLogout() + { + $client = $this->createClient(array('test_case' => 'LogoutAccess', 'root_config' => 'config.yml')); + + $client->request('POST', '/login', array('_username' => 'johannes', '_password' => 'test')); + $client->request('GET', '/logout'); + + $this->assertRedirect($client->getResponse(), '/'); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/bundles.php new file mode 100644 index 0000000000000..c934b52aee7c0 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\SecurityBundle\SecurityBundle; + +return array( + new FrameworkBundle(), + new SecurityBundle(), +); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/config.yml new file mode 100644 index 0000000000000..2e20735b80236 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/config.yml @@ -0,0 +1,26 @@ +imports: +- { resource: ./../config/framework.yml } + +security: + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + providers: + in_memory: + memory: + users: + johannes: { password: test, roles: [ROLE_USER] } + + firewalls: + default: + form_login: + check_path: login + remember_me: true + require_previous_session: false + logout: ~ + anonymous: ~ + stateless: true + + access_control: + - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: .*, roles: IS_AUTHENTICATED_FULLY } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/routing.yml new file mode 100644 index 0000000000000..1dddfca2f8154 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/routing.yml @@ -0,0 +1,5 @@ +login: + path: /login + +logout: + path: /logout diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index c0508ea29b02b..5e8d9458e6eca 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.9", "ext-xml": "*", - "symfony/security": "^2.8.42|^3.4.12", + "symfony/security": "^2.8.45|^3.4.15", "symfony/security-acl": "~2.7|~3.0.0", "symfony/http-kernel": "~2.7|~3.0.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php index b0a58e9a23852..f089c04abeb8c 100644 --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Security\Http\Firewall\AccessListener; /** * Firewall uses a FirewallMap to register security listeners for the given @@ -58,8 +59,16 @@ public function onKernelRequest(GetResponseEvent $event) $exceptionListener->register($this->dispatcher); } + $accessListener = null; + // initiate the listener chain foreach ($authenticationListeners as $listener) { + if ($listener instanceof AccessListener) { + $accessListener = $listener; + + continue; + } + $listener->handle($event); if ($event->hasResponse()) { @@ -70,6 +79,10 @@ public function onKernelRequest(GetResponseEvent $event) if (null !== $logoutListener) { $logoutListener->handle($event); } + + if (!$event->hasResponse() && null !== $accessListener) { + $accessListener->handle($event); + } } public function onKernelFinishRequest(FinishRequestEvent $event) diff --git a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php index bd475bb4e5b1f..66dad46152c02 100644 --- a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php +++ b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php @@ -79,7 +79,7 @@ public function testOnKernelRequestStopsWhenThereIsAResponse() ->getMock() ; $event - ->expects($this->once()) + ->expects($this->at(0)) ->method('hasResponse') ->will($this->returnValue(true)) ; From da2af57e060dbec032a7bb5e392795ed9fbe8efe Mon Sep 17 00:00:00 2001 From: Ahmed Abdulrahman Date: Thu, 2 Aug 2018 11:24:26 +0200 Subject: [PATCH 15/66] :bug: Fix typo --- .../Component/VarDumper/Resources/css/htmlDescriptor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css b/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css index 4277c6809bc32..65da8137fc156 100644 --- a/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css +++ b/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css @@ -102,7 +102,7 @@ pre.sf-dump { margin-bottom: 0; } .hidden { - display: none; !important + display: none !important; } .dumped-tag > .sf-dump { display: inline-block; From 1483c87aab39d6370d45d5ba621f1d4a0089fca9 Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Thu, 2 Aug 2018 11:42:21 +0200 Subject: [PATCH 16/66] Add help texts for checkboxes in horizontal bootstrap 4 forms --- .../bootstrap_4_horizontal_layout.html.twig | 1 + ...AbstractBootstrap4HorizontalLayoutTest.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig index ca40981ec8524..7fcea4b0ecd25 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig @@ -81,6 +81,7 @@ col-sm-10
{#--#}
{{- form_widget(form) -}} + {{- form_help(form) -}} {{- form_errors(form) -}}
{#--#} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php index 9d216e38194f2..588c9a422bc5c 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php @@ -214,4 +214,24 @@ public function testCheckboxRow() $this->assertMatchesXpath($html, '/div[@class="form-group row"]/div[@class="col-sm-2" or @class="col-sm-10"]', 2); } + + public function testCheckboxRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType'); + $view = $form->createView(); + $html = $this->renderRow($view, array('label' => 'foo', 'help' => 'really helpful text')); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group row"] + [ + ./div[@class="col-sm-2" or @class="col-sm-10"] + /following-sibling::div[@class="col-sm-2" or @class="col-sm-10"] + [ + ./small[text() = "[trans]really helpful text[/trans]"] + ] + ] +' + ); + } } From 01e7fe4fb03aab19345a35f243aae8be8139f98a Mon Sep 17 00:00:00 2001 From: Mickael GOETZ Date: Thu, 2 Aug 2018 13:27:22 +0200 Subject: [PATCH 17/66] [Form] Remove extra .form-group wrapper around file widget in bootstrap 4 This is a follow-up to https://github.com/symfony/symfony/pull/27958 and https://github.com/symfony/symfony/pull/27919. It fixes an extra space between the help text of a FileType widget and the widget itself. The extra space was cause by a .form-group wrapper in the file_widget block. --- .../views/Form/bootstrap_4_layout.html.twig | 20 ++++++------ .../AbstractBootstrap4LayoutTest.php | 32 +++++++------------ 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig index 8f790fdd19450..5030264c127bb 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig @@ -115,17 +115,15 @@ {%- endblock percent_widget %} {% block file_widget -%} -
- <{{ element|default('div') }} class="custom-file"> - {%- set type = type|default('file') -%} - {{- block('form_widget_simple') -}} - - -
+ <{{ element|default('div') }} class="custom-file"> + {%- set type = type|default('file') -%} + {{- block('form_widget_simple') -}} + + {% endblock %} {% block form_widget_simple -%} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php index 1336405bdd30e..5710a2d486c00 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php @@ -942,17 +942,13 @@ public function testFile() $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'n/a', 'attr' => array('class' => 'my&class form-control-file')), '/div - [@class="form-group"] + [@class="custom-file"] [ - ./div - [@class="custom-file"] - [ - ./input - [@type="file"] - [@name="name"] - /following-sibling::label - [@for="name"] - ] + ./input + [@type="file"] + [@name="name"] + /following-sibling::label + [@for="name"] ] ' ); @@ -964,17 +960,13 @@ public function testFileWithPlaceholder() $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'n/a', 'attr' => array('class' => 'my&class form-control-file', 'placeholder' => 'Custom Placeholder')), '/div - [@class="form-group"] + [@class="custom-file"] [ - ./div - [@class="custom-file"] - [ - ./input - [@type="file"] - [@name="name"] - /following-sibling::label - [@for="name" and text() = "[trans]Custom Placeholder[/trans]"] - ] + ./input + [@type="file"] + [@name="name"] + /following-sibling::label + [@for="name" and text() = "[trans]Custom Placeholder[/trans]"] ] ' ); From 2d7fdff021cf50130cfd9f9a058f60ee774ce534 Mon Sep 17 00:00:00 2001 From: Jaroslav Kuba Date: Thu, 2 Aug 2018 20:11:33 +0200 Subject: [PATCH 18/66] [Routing] Fixed scheme redirecting for root path --- .../Routing/Matcher/Dumper/PhpMatcherDumper.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher0.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher1.php | 2 +- .../Tests/Fixtures/dumper/url_matcher10.php | 2 +- .../Tests/Fixtures/dumper/url_matcher11.php | 2 +- .../Tests/Fixtures/dumper/url_matcher12.php | 2 +- .../Tests/Fixtures/dumper/url_matcher13.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher2.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher3.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher4.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher5.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher6.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher7.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher8.php | 2 +- .../Routing/Tests/Fixtures/dumper/url_matcher9.php | 2 +- .../Tests/Matcher/RedirectableUrlMatcherTest.php | 14 ++++++++++++++ 16 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index a1052195a0cc8..14e5cc341e807 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -194,7 +194,7 @@ private function compileRoutes(RouteCollection $routes, bool $matchHost): string } // used to display the Welcome Page in apps that don't define a homepage - $code .= " if ('/' === \$pathinfo && !\$allow) {\n"; + $code .= " if ('/' === \$pathinfo && !\$allow && !\$allowSchemes) {\n"; $code .= " throw new Symfony\Component\Routing\Exception\NoConfigurationException();\n"; $code .= " }\n"; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher0.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher0.php index 0a56bf1735a13..e7c0765003b2f 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher0.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher0.php @@ -26,7 +26,7 @@ public function match($rawPathinfo) $canonicalMethod = 'GET'; } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php index c91066a46d281..68e7741b52189 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php @@ -238,7 +238,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php index 81ded3417cdd3..2f5cc3fc5aa5a 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php @@ -2821,7 +2821,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php index c0bbc582d4dd2..173cc15279f2b 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php @@ -142,7 +142,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php index 02f6ac949eb20..eba4c8ace32a2 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php @@ -91,7 +91,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher13.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher13.php index b4457d7cdc7e7..5cda7753dac61 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher13.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher13.php @@ -60,7 +60,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php index a711dbaf61263..5aec5db0179ad 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php @@ -275,7 +275,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php index df4e2208c6392..6f1c45aa9e8d1 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php @@ -103,7 +103,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php index 795feaf531bbb..418f8e0b14ab5 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php @@ -75,7 +75,7 @@ public function match($rawPathinfo) return $ret; } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php index f3f1fc167142b..976a25fbee621 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php @@ -145,7 +145,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php index 784c0fcafa6a4..9cebf2d929d00 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php @@ -122,7 +122,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php index caf04cc3776e7..b2b707213555d 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php @@ -157,7 +157,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php index 0f2ce53fed0b9..38bbfa2249379 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php @@ -79,7 +79,7 @@ public function match($rawPathinfo) $offset += strlen($m); } } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher9.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher9.php index d9035392b272f..cfcd1d440c9a7 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher9.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher9.php @@ -44,7 +44,7 @@ public function match($rawPathinfo) break; } - if ('/' === $pathinfo && !$allow) { + if ('/' === $pathinfo && !$allow && !$allowSchemes) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php index 0ae5ff1be9cd9..e36796224b451 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php @@ -93,6 +93,20 @@ public function testSchemeRedirectWithParams() $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'redirect' => 'value'), $matcher->match('/foo/baz')); } + public function testSchemeRedirectForRoot() + { + $coll = new RouteCollection(); + $coll->add('foo', new Route('/', array(), array(), array(), '', array('https'))); + + $matcher = $this->getUrlMatcher($coll); + $matcher + ->expects($this->once()) + ->method('redirect') + ->with('/', 'foo', 'https') + ->will($this->returnValue(array('redirect' => 'value'))); + $this->assertEquals(array('_route' => 'foo', 'redirect' => 'value'), $matcher->match('/')); + } + public function testSlashRedirectWithParams() { $coll = new RouteCollection(); From fe482ccdb1284284611ba439004412e87fb0eb13 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 10:56:54 +0200 Subject: [PATCH 19/66] fix merge --- .../Component/PropertyInfo/Tests/Fixtures/Dummy.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 18ce6ef9c2a1a..5b82209e1d417 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -45,14 +45,6 @@ class Dummy extends ParentDummy * @Groups({"a", "b"}) */ public $collection; - /** - * @var string[][] - */ - public $nestedCollection; - /** - * @var mixed[] - */ - public $mixedCollection; /** * @var string[][] From 9857ca07aa76d747416de89fe8ae50586b507666 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 Aug 2018 08:56:36 +0200 Subject: [PATCH 20/66] [travis] merge "same Symfony version" jobs in one --- .travis.yml | 130 ++++++++++-------- .../Tests/phpt/decorate_exception_hander.phpt | 3 +- .../Component/Process/Tests/ProcessTest.php | 6 - 3 files changed, 76 insertions(+), 63 deletions(-) diff --git a/.travis.yml b/.travis.yml index c0367f10720bd..a1eb5e5e59f9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,9 +22,7 @@ matrix: sudo: required group: edge - php: 5.4 - - php: 5.5 - - php: 5.6 - - php: 7.0 + env: php_extra="5.5 5.6 7.0" - php: 7.1 env: deps=high - php: 7.2 @@ -42,15 +40,26 @@ services: mongodb before_install: - | # General configuration + set -e stty cols 120 - PHP=$TRAVIS_PHP_VERSION [ -d ~/.composer ] || mkdir ~/.composer cp .composer/* ~/.composer/ export PHPUNIT=$(readlink -f ./phpunit) export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" export COMPOSER_UP='composer update --no-progress --no-suggest --ansi' + export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n') + find ~/.phpenv -name xdebug.ini -delete + + if [[ $TRAVIS_PHP_VERSION = 5.* || $TRAVIS_PHP_VERSION = hhvm* ]]; then + composer () { + $HOME/.phpenv/versions/7.1/bin/composer config platform.php $(echo ' > $INI - echo memory_limit = -1 >> $INI - echo session.gc_probability = 0 >> $INI - echo opcache.enable_cli = 1 >> $INI - echo hhvm.jit = 0 >> $INI - echo apc.enable_cli = 1 >> $INI - [[ $PHP = 5.* ]] && echo extension = memcache.so >> $INI - if [[ $PHP = 5.* ]]; then - echo extension = mongo.so >> $INI - fi - # tpecl is a helper to compile and cache php extensions tpecl () { local ext_name=$1 @@ -114,6 +105,7 @@ before_install: if [[ -e $ext_cache/$ext_so ]]; then echo extension = $ext_cache/$ext_so >> $INI else + rm ~/.pearrc /tmp/pear 2>/dev/null || true mkdir -p $ext_cache echo yes | pecl install -f $ext_name && cp $ext_dir/$ext_so $ext_cache @@ -121,38 +113,62 @@ before_install: } export -f tpecl - # Matrix lines for intermediate PHP versions are skipped for pull requests - if [[ ! $deps && ! $PHP = ${MIN_PHP%.*} && ! $PHP = hhvm* && $TRAVIS_PULL_REQUEST != false ]]; then - deps=skip - skip=1 - else - COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n') - fi - - | # Install sigchild-enabled PHP to test the Process component on the lowest PHP matrix line - if [[ ! $deps && $PHP = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then + if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj && (cd php-$MIN_PHP && ./configure --enable-sigchild --enable-pcntl && make -j2) fi + - | + # php.ini configuration + for PHP in $TRAVIS_PHP_VERSION $php_extra; do + if [[ $PHP = hhvm* ]]; then + INI=/etc/hhvm/php.ini + else + phpenv global $PHP 2>/dev/null || (cd / && wget https://s3.amazonaws.com/travis-php-archives/binaries/ubuntu/14.04/x86_64/php-$PHP.tar.bz2 -O - | tar -xj) + INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini + fi + echo date.timezone = Europe/Paris >> $INI + echo memory_limit = -1 >> $INI + echo session.gc_probability = 0 >> $INI + echo opcache.enable_cli = 1 >> $INI + echo hhvm.jit = 0 >> $INI + echo apc.enable_cli = 1 >> $INI + [[ $PHP = 5.* ]] && echo extension = memcache.so >> $INI + if [[ $PHP = 5.* ]]; then + echo extension = mongo.so >> $INI + fi + done + - | # Install extra PHP extensions - if [[ ! $skip && $PHP = 5.* ]]; then - ([[ $deps ]] || tfold ext.symfony_debug 'cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo extension = $(pwd)/modules/symfony_debug.so >> '"$INI") - tfold ext.memcached tpecl memcached-2.1.0 memcached.so $INI - tfold ext.apcu tpecl apcu-4.0.11 apcu.so $INI - elif [[ ! $skip && $PHP = 7.* ]]; then - tfold ext.apcu tpecl apcu-5.1.6 apcu.so $INI - tfold ext.mongodb tpecl mongodb-1.5.0 mongodb.so $INI - fi + for PHP in $TRAVIS_PHP_VERSION $php_extra; do + if [[ $PHP = hhvm* ]]; then + continue + fi + export PHP=$PHP + phpenv global $PHP + INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini + if [[ $PHP = 5.* ]]; then + tfold ext.memcached tpecl memcached-2.1.0 memcached.so $INI + tfold ext.apcu tpecl apcu-4.0.11 apcu.so $INI + [[ $deps ]] && continue + ext_cache=~/php-ext/$(php -r "echo basename(ini_get('extension_dir'));")/symfony_debug.so + [[ -e $ext_cache ]] || (tfold ext.symfony_debug "cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && mv modules/symfony_debug.so $ext_cache && phpize --clean") + echo extension = $ext_cache >> $INI + elif [[ $PHP = 7.* ]]; then + tfold ext.apcu tpecl apcu-5.1.6 apcu.so $INI + tfold ext.mongodb tpecl mongodb-1.5.0 mongodb.so $INI + fi + done install: - | # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components if [[ ! $deps ]]; then php .github/build-packages.php HEAD^ src/Symfony/Bridge/PhpUnit - elif [[ ! $skip ]]; then + else export SYMFONY_DEPRECATIONS_HELPER=weak && cp composer.json composer.json.orig && echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json && @@ -168,7 +184,7 @@ install: git fetch origin $SYMFONY_VERSION && git checkout -m FETCH_HEAD && COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n') - elif [[ ! $skip ]]; then + else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*') fi @@ -177,24 +193,27 @@ install: [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]] && LEGACY=,legacy export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - if [[ ! $skip && $deps ]]; then mv composer.json.phpunit composer.json; fi - - if [[ ! $skip && $PHP = 7.* ]]; then - ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) - fi + if [[ $deps ]]; then mv composer.json.phpunit composer.json; fi - - if [[ ! $skip ]]; then $COMPOSER_UP; fi - - if [[ ! $skip ]]; then ./phpunit install; fi - | # phpinfo - if [[ ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi + if [[ ! $TRAVIS_PHP_VERSION = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi - | run_tests () { set -e - if [[ $skip ]]; then + export PHP=$1 + if [[ $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m" - elif [[ $deps = high ]]; then + break + fi + phpenv global ${PHP/hhvm*/hhvm} + tfold 'composer update' $COMPOSER_UP + tfold 'phpunit install' ./phpunit install + if [[ $PHP = 7.* ]]; then + ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) + fi + if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" elif [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% "tfold {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT_X'" @@ -202,12 +221,13 @@ install: $PHPUNIT --exclude-group no-hhvm,benchmark,intl-data else echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}" - tfold tty-group $PHPUNIT --group tty + tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty if [[ $PHP = ${MIN_PHP%.*} ]]; then + export PHP=$MIN_PHP echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/" fi fi } script: - - (run_tests) + - for PHP in $TRAVIS_PHP_VERSION $php_extra; do (run_tests $PHP); done diff --git a/src/Symfony/Component/Debug/Tests/phpt/decorate_exception_hander.phpt b/src/Symfony/Component/Debug/Tests/phpt/decorate_exception_hander.phpt index 74cf2e9171001..7211afbdf85ea 100644 --- a/src/Symfony/Component/Debug/Tests/phpt/decorate_exception_hander.phpt +++ b/src/Symfony/Component/Debug/Tests/phpt/decorate_exception_hander.phpt @@ -38,8 +38,7 @@ Did you forget a "use" statement for another namespace?" ["line":protected]=> int(%d) ["trace":"Exception":private]=> - array(0) { - } + array(%d) {%A} ["previous":"Exception":private]=> NULL ["severity":protected]=> diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index eea9efa93bda8..8afff96727fbd 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -439,9 +439,6 @@ public function testExitCodeCommandFailed() $this->assertGreaterThan(0, $process->getExitCode()); } - /** - * @group tty - */ public function testTTYCommand() { if ('\\' === \DIRECTORY_SEPARATOR) { @@ -457,9 +454,6 @@ public function testTTYCommand() $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus()); } - /** - * @group tty - */ public function testTTYCommandExitCode() { if ('\\' === \DIRECTORY_SEPARATOR) { From 88181244687543259ab946733bf8c44eb871cfb6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 12:58:53 +0200 Subject: [PATCH 21/66] fix merge --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cf0006ea295c6..c0c48d933d596 100644 --- a/.travis.yml +++ b/.travis.yml @@ -245,6 +245,7 @@ install: tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty if [[ $PHP = ${MIN_PHP%.*} ]]; then export PHP=$MIN_PHP + echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/" fi fi } From 0a450d72c55edb659a07d05f0a55fed7a8d9dfd7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 13:10:36 +0200 Subject: [PATCH 22/66] [travis] fix CI for sigchild+Process --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a1eb5e5e59f9f..d51b72b429d09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -224,7 +224,7 @@ install: tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty if [[ $PHP = ${MIN_PHP%.*} ]]; then export PHP=$MIN_PHP - echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/" + echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} SYMFONY_DEPRECATIONS_HELPER=weak ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/" fi fi } From ed36e64bd44af223f54518318bba777db1cf5ae0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 13:22:40 +0200 Subject: [PATCH 23/66] fix merge --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d3a7907c37e5..8da248d9803df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -207,9 +207,7 @@ install: phpenv global $PHP tfold 'composer update' $COMPOSER_UP tfold 'phpunit install' ./phpunit install - if [[ $PHP = 7.* ]]; then - ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) - fi + ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" elif [[ $deps = low ]]; then From 613ca3c19c139f17ae06672b91158e600e3e767c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 14:33:19 +0200 Subject: [PATCH 24/66] [travis] test with latest PHP 7.1 to hopefully get rid of segfaults --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8da248d9803df..09de0860fe1b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ env: matrix: include: - - php: 7.1.3 + - php: 7.1 - php: 7.1 env: deps=high - php: 7.2 @@ -113,7 +113,7 @@ before_install: - | # Install sigchild-enabled PHP to test the Process component on the lowest PHP matrix line - if [[ ! $deps && $TRAVIS_PHP_VERSION = $MIN_PHP && ! -d php-$MIN_PHP/sapi ]]; then + if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://php.net/get/php-$MIN_PHP.tar.bz2/from/this/mirror -O - | tar -xj && (cd php-$MIN_PHP && ./configure --enable-sigchild --enable-pcntl && make -j2) fi @@ -215,7 +215,8 @@ install: else echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}" tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty - if [[ $PHP = $MIN_PHP ]]; then + if [[ $PHP = ${MIN_PHP%.*} ]]; then + export PHP=$MIN_PHP tfold src/Symfony/Component/Process.sigchild SYMFONY_DEPRECATIONS_HELPER=weak php-$MIN_PHP/sapi/cli/php ./phpunit --colors=always src/Symfony/Component/Process/ fi fi From f50ee9b3dcdd19000e15c256091c3d7fcf4fb323 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 14:53:54 +0200 Subject: [PATCH 25/66] [travis] fix requiring mongodb/mongodb before composer up --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d51b72b429d09..390621f402566 100644 --- a/.travis.yml +++ b/.travis.yml @@ -208,11 +208,11 @@ install: break fi phpenv global ${PHP/hhvm*/hhvm} - tfold 'composer update' $COMPOSER_UP - tfold 'phpunit install' ./phpunit install if [[ $PHP = 7.* ]]; then ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) fi + tfold 'composer update' $COMPOSER_UP + tfold 'phpunit install' ./phpunit install if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" elif [[ $deps = low ]]; then From 6cb792c9d6705be5ae50d58b2e1e64185b2b1085 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Aug 2018 15:09:12 +0200 Subject: [PATCH 26/66] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 390621f402566..882701f0dbdf2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -209,7 +209,7 @@ install: fi phpenv global ${PHP/hhvm*/hhvm} if [[ $PHP = 7.* ]]; then - ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) + ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.5.0; composer require --dev --no-update mongodb/mongodb) fi tfold 'composer update' $COMPOSER_UP tfold 'phpunit install' ./phpunit install From 7f895abbddff7282c69d022c3641034422ad16fe Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Sun, 5 Aug 2018 16:25:16 +0200 Subject: [PATCH 27/66] Update validators.nl.xlf --- .../Validator/Resources/translations/validators.nl.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 413a97eb17c6f..bee0ab3b55a8f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -316,7 +316,7 @@ This is not a valid UUID. - Deze waarde is geen geldige UUID waarde. + Dit is geen geldige UUID. From 67f3e3ff4e123e6b2d9b8ec53683fa302534dbd7 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 5 Aug 2018 19:43:29 +0200 Subject: [PATCH 28/66] [Security] Remove wrong sentence about ACL --- src/Symfony/Component/Security/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/README.md b/src/Symfony/Component/Security/README.md index b8bba12f20362..f55f8a10eab98 100644 --- a/src/Symfony/Component/Security/README.md +++ b/src/Symfony/Component/Security/README.md @@ -6,7 +6,7 @@ application. It ships with facilities for authenticating using HTTP basic or digest authentication, interactive form login or X.509 certificate login, but also allows you to implement your own authentication strategies. Furthermore, the component provides ways to authorize authenticated users based on their -roles, and it contains an advanced ACL system. +roles. Resources --------- From 6089290543bcc8dac5abe6db7e33e08166765020 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 6 Aug 2018 17:30:25 +0200 Subject: [PATCH 29/66] [HttpFoundation] fix false-positive ConflictingHeadersException --- .../Component/HttpFoundation/Request.php | 21 ++++++-- .../HttpFoundation/Tests/RequestTest.php | 51 ++++++++++++++++++- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 9cc6a9773b5ea..6dc9bbe81e75b 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1943,10 +1943,13 @@ private function getTrustedValues($type, $ip = null) if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); - $forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array(); + $forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array(); if (self::HEADER_CLIENT_PORT === $type) { foreach ($forwardedValues as $k => $v) { - $forwardedValues[$k] = substr_replace($v, '0.0.0.0', 0, strrpos($v, ':')); + if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) { + $v = $this->isSecure() ? ':443' : ':80'; + } + $forwardedValues[$k] = '0.0.0.0'.$v; } } } @@ -1981,9 +1984,17 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip) $firstTrustedIp = null; foreach ($clientIps as $key => $clientIp) { - // Remove port (unfortunately, it does happen) - if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) { - $clientIps[$key] = $clientIp = $match[1]; + if (strpos($clientIp, '.')) { + // Strip :port from IPv4 addresses. This is allowed in Forwarded + // and may occur in X-Forwarded-For. + $i = strpos($clientIp, ':'); + if ($i) { + $clientIps[$key] = $clientIp = substr($clientIp, 0, $i); + } + } elseif ('[' == $clientIp[0]) { + // Strip brackets and :port from IPv6 addresses. + $i = strpos($clientIp, ']', 1); + $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); } if (!filter_var($clientIp, FILTER_VALIDATE_IP)) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index b7eceef9bca7c..0ee92aab1ba19 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -967,7 +967,7 @@ public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwar 'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor, ); - Request::setTrustedProxies(array('88.88.88.88')); + Request::setTrustedProxies(array('88.88.88.88'), -1); $request->initialize(array(), array(), array(), array(), array(), $server); @@ -2071,6 +2071,55 @@ public function testNonstandardRequests($requestUri, $queryString, $expectedPath $this->assertEquals($expectedBaseUrl, $request->getBaseUrl()); $this->assertEquals($expectedBasePath, $request->getBasePath()); } + + public function testTrustedHost() + { + Request::setTrustedProxies(array('1.1.1.1'), -1); + + $request = Request::create('/'); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Forwarded', 'host=localhost:8080'); + $request->headers->set('X-Forwarded-Host', 'localhost:8080'); + + $this->assertSame('localhost:8080', $request->getHttpHost()); + $this->assertSame(8080, $request->getPort()); + + $request = Request::create('/'); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Forwarded', 'host="[::1]:443"'); + $request->headers->set('X-Forwarded-Host', '[::1]:443'); + $request->headers->set('X-Forwarded-Port', 443); + + $this->assertSame('[::1]:443', $request->getHttpHost()); + $this->assertSame(443, $request->getPort()); + } + + public function testTrustedPort() + { + Request::setTrustedProxies(array('1.1.1.1'), -1); + + $request = Request::create('/'); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Forwarded', 'host=localhost:8080'); + $request->headers->set('X-Forwarded-Port', 8080); + + $this->assertSame(8080, $request->getPort()); + + $request = Request::create('/'); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Forwarded', 'host=localhost'); + $request->headers->set('X-Forwarded-Port', 80); + + $this->assertSame(80, $request->getPort()); + + $request = Request::create('/'); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Forwarded', 'host="[::1]"'); + $request->headers->set('X-Forwarded-Proto', 'https'); + $request->headers->set('X-Forwarded-Port', 443); + + $this->assertSame(443, $request->getPort()); + } } class RequestContentProxy extends Request From caaa74cd9be80a9c29ebcd98832da6c339278cb5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 6 Aug 2018 22:01:26 +0200 Subject: [PATCH 30/66] [travis] cache composer.lock files for deps=low --- .github/rm-invalid-lowest-lock-files.php | 80 ++++++++++++++++++++++++ .travis.yml | 6 +- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 .github/rm-invalid-lowest-lock-files.php diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php new file mode 100644 index 0000000000000..85d582fe621e2 --- /dev/null +++ b/.github/rm-invalid-lowest-lock-files.php @@ -0,0 +1,80 @@ + Date: Fri, 20 Jul 2018 16:08:49 +0200 Subject: [PATCH 31/66] [Filesystem] Add test to prevent regression when using array|resource with dumpFile --- .../Filesystem/Tests/FilesystemTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 35811d3d983a4..6a7fad69ed54e 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1201,6 +1201,31 @@ public function testDumpFile() $this->assertStringEqualsFile($filename, 'bar'); } + public function testDumpFileWithArray() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; + + $this->filesystem->dumpFile($filename, array('bar')); + + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'bar'); + } + + public function testDumpFileWithResource() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; + + $resource = fopen('php://memory', 'rw'); + fwrite($resource, 'bar'); + fseek($resource, 0); + + $this->filesystem->dumpFile($filename, $resource); + + fclose($resource); + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'bar'); + } + /** * @group legacy */ From 02c69b1658900086b9bf5434b8220b3a48f32809 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Aug 2018 14:36:19 +0200 Subject: [PATCH 32/66] [Translation] fix perf of lint:xliff command --- .../Component/Translation/Command/XliffLintCommand.php | 8 ++++---- .../Resources/schemas/xliff-core-1.2-strict.xsd | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Translation/Command/XliffLintCommand.php b/src/Symfony/Component/Translation/Command/XliffLintCommand.php index 7979e51da1a4d..378788f5b8b9c 100644 --- a/src/Symfony/Component/Translation/Command/XliffLintCommand.php +++ b/src/Symfony/Component/Translation/Command/XliffLintCommand.php @@ -130,10 +130,10 @@ private function validate($content, $file = null) $document->schemaValidate(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd'); foreach (libxml_get_errors() as $xmlError) { $errors[] = array( - 'line' => $xmlError->line, - 'column' => $xmlError->column, - 'message' => trim($xmlError->message), - ); + 'line' => $xmlError->line, + 'column' => $xmlError->column, + 'message' => trim($xmlError->message), + ); } libxml_clear_errors(); diff --git a/src/Symfony/Component/Translation/Resources/schemas/xliff-core-1.2-strict.xsd b/src/Symfony/Component/Translation/Resources/schemas/xliff-core-1.2-strict.xsd index dface628ce3e4..4102d6472d1f6 100644 --- a/src/Symfony/Component/Translation/Resources/schemas/xliff-core-1.2-strict.xsd +++ b/src/Symfony/Component/Translation/Resources/schemas/xliff-core-1.2-strict.xsd @@ -30,7 +30,7 @@ Jan-10-2006 --> - + From a540aee35c8bb45037a6ad333e07b7d82f453d70 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Aug 2018 17:19:50 +0200 Subject: [PATCH 33/66] [travis] ignore ordering when validating composer.lock files for deps=low --- .github/rm-invalid-lowest-lock-files.php | 27 +++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index 85d582fe621e2..5515238d9ace1 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -3,7 +3,7 @@ array_shift($_SERVER['argv']); $dirs = $_SERVER['argv']; -function getContentHash($composerJson) +function getRelevantContent(array $composerJson) { $relevantKeys = array( 'name', @@ -27,12 +27,18 @@ function getContentHash($composerJson) $relevantContent['config']['platform'] = $composerJson['config']['platform']; } + return $relevantContent; +} + +function getContentHash(array $composerJson) +{ + $relevantContent = getRelevantContent($composerJson); ksort($relevantContent); return md5(json_encode($relevantContent)); } -$composerLocks = array(); +$composerJsons = array(); foreach ($dirs as $dir) { if (!file_exists($dir.'/composer.lock') || !$composerLock = @json_decode(file_get_contents($dir.'/composer.lock'), true)) { @@ -50,28 +56,29 @@ function getContentHash($composerJson) @unlink($dir.'/composer.lock'); continue; } - $composerLocks[$composerJson['name']] = array($dir, $composerLock, $composerJson); + $composerJsons[$composerJson['name']] = array($dir, $composerLock['packages'], getRelevantContent($composerJson)); } -foreach ($composerLocks as list($dir, $composerLock)) { - foreach ($composerLock['packages'] as $composerJson) { - if (0 !== strpos($version = $composerJson['version'], 'dev-') && '-dev' !== substr($version, -4)) { +foreach ($composerJsons as list($dir, $lockedPackages)) { + foreach ($lockedPackages as $lockedJson) { + if (0 !== strpos($version = $lockedJson['version'], 'dev-') && '-dev' !== substr($version, -4)) { continue; } - if (!isset($composerLocks[$name = $composerJson['name']])) { + if (!isset($composerJsons[$name = $lockedJson['name']])) { echo "$dir/composer.lock references missing $name.\n"; @unlink($dir.'/composer.lock'); continue 2; } foreach (array('minimum-stability', 'prefer-stable', 'repositories') as $key) { - if (array_key_exists($key, $composerLocks[$name][2])) { - $composerJson[$key] = $composerLocks[$name][2][$key]; + if (array_key_exists($key, $composerJsons[$name][2])) { + $lockedJson[$key] = $composerJsons[$name][2][$key]; } } - if (getContentHash($composerJson) !== $composerLocks[$name][1]['content-hash']) { + // use weak comparison to ignore ordering + if (getRelevantContent($lockedJson) != $composerJsons[$name][2]) { echo "$dir/composer.lock is not in sync with $name.\n"; @unlink($dir.'/composer.lock'); continue 2; From 6b413ab49d1984017870ac840c38435ea6cf1a8f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Aug 2018 08:37:38 +0200 Subject: [PATCH 34/66] [Config] minor fix that removes a PHP 7.3 deprecation --- src/Symfony/Component/Config/Definition/BaseNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php index f9cf829e4e7bd..61e75eb5895ba 100644 --- a/src/Symfony/Component/Config/Definition/BaseNode.php +++ b/src/Symfony/Component/Config/Definition/BaseNode.php @@ -499,7 +499,7 @@ private static function resolvePlaceholderValue($value) return self::$placeholders[$value]; } - if (0 === strpos($value, self::$placeholderUniquePrefix)) { + if (self::$placeholderUniquePrefix && 0 === strpos($value, self::$placeholderUniquePrefix)) { return array(); } } From b79d097c2af2f348e94ac99ca7cef2794baf5b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Wed, 8 Aug 2018 13:02:30 +0200 Subject: [PATCH 35/66] [DI] Fix autowire inner service --- .../Compiler/AutowirePass.php | 7 +++--- .../Tests/Compiler/AutowirePassTest.php | 23 +++++++++++++++++++ .../Fixtures/includes/autowiring_classes.php | 7 ++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 2d937f2840835..e858d14fa1c5a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -144,11 +144,12 @@ private function doProcessValue($value, $isRoot = false) */ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot): array { + $this->decoratedId = null; + $this->decoratedClass = null; + $this->getPreviousValue = null; + if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && $this->container->has($this->decoratedId = $definition->innerServiceId)) { $this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass(); - } else { - $this->decoratedId = null; - $this->decoratedClass = null; } foreach ($this->methodCalls as $i => $call) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index cbbd8867865fc..366583aba10d8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -834,6 +834,29 @@ public function testAutowireDecorator() $this->assertSame(Decorator::class.'.inner', (string) $definition->getArgument(1)); } + public function testAutowireDecoratorChain() + { + $container = new ContainerBuilder(); + $container->register(LoggerInterface::class, NullLogger::class); + $container->register(Decorated::class, Decorated::class); + $container + ->register(Decorator::class, Decorator::class) + ->setDecoratedService(Decorated::class) + ->setAutowired(true) + ; + $container + ->register(DecoratedDecorator::class, DecoratedDecorator::class) + ->setDecoratedService(Decorated::class) + ->setAutowired(true) + ; + + (new DecoratorServicePass())->process($container); + (new AutowirePass())->process($container); + + $definition = $container->getDefinition(DecoratedDecorator::class); + $this->assertSame(DecoratedDecorator::class.'.inner', (string) $definition->getArgument(0)); + } + public function testAutowireDecoratorRenamedId() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index d806f294ddaa9..93eab8c50f9a7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -373,6 +373,13 @@ public function __construct(LoggerInterface $logger, DecoratorInterface $decorat } } +class DecoratedDecorator implements DecoratorInterface +{ + public function __construct(DecoratorInterface $decorator) + { + } +} + class NonAutowirableDecorator implements DecoratorInterface { public function __construct(LoggerInterface $logger, DecoratorInterface $decorated1, DecoratorInterface $decorated2) From 4e92d10b40faf71f90e1164c96d2792054fa81da Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Aug 2018 13:42:34 +0200 Subject: [PATCH 36/66] [DI] fix analyzing lazy refs involved in circular loops --- .../Compiler/AnalyzeServiceReferencesPass.php | 6 ++-- .../DependencyInjection/Dumper/PhpDumper.php | 31 +++++++------------ .../Tests/Dumper/PhpDumperTest.php | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php index 19f01b8536cb4..aeebbf0bf18c4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php @@ -34,15 +34,17 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe private $graph; private $currentDefinition; private $onlyConstructorArguments; + private $hasProxyDumper; private $lazy; private $expressionLanguage; /** * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls */ - public function __construct($onlyConstructorArguments = false) + public function __construct($onlyConstructorArguments = false, $hasProxyDumper = true) { $this->onlyConstructorArguments = (bool) $onlyConstructorArguments; + $this->hasProxyDumper = (bool) $hasProxyDumper; } /** @@ -97,7 +99,7 @@ protected function processValue($value, $isRoot = false) $targetId, $targetDefinition, $value, - $this->lazy || ($targetDefinition && $targetDefinition->isLazy()), + $this->lazy || ($this->hasProxyDumper && $targetDefinition && $targetDefinition->isLazy()), ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() ); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index cf6495b9c66f3..5530912c90a9e 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; +use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -139,29 +140,19 @@ public function dump(array $options = array()) $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass); if ($this->getProxyDumper() instanceof NullDumper) { - (new AnalyzeServiceReferencesPass(true))->process($this->container); - $this->circularReferences = array(); - $checkedNodes = array(); - foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { - $currentPath = array($id => $id); - $this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); - } - foreach ($this->circularReferences as $parent => $ids) { - $path = array($parent); - while (!isset($ids[$parent])) { - foreach ($ids as $id) { - $path[] = $id; - $ids = $this->circularReferences[$id]; - break; - } - } - $path[] = $parent.'". Try running "composer require symfony/proxy-manager-bridge'; + (new AnalyzeServiceReferencesPass(true, false))->process($this->container); + try { + (new CheckCircularReferencesPass())->process($this->container); + } catch (ServiceCircularReferenceException $e) { + $path = $e->getPath(); + end($path); + $path[key($path)] .= '". Try running "composer require symfony/proxy-manager-bridge'; - throw new ServiceCircularReferenceException($parent, $path); + throw new ServiceCircularReferenceException($e->getServiceId(), $path); } } - (new AnalyzeServiceReferencesPass())->process($this->container); + (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container); $this->circularReferences = array(); $checkedNodes = array(); foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { @@ -367,7 +358,7 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre $node = $edge->getDestNode(); $id = $node->getId(); - if ($node->getValue() && (($edge->isLazy() && !$this->getProxyDumper() instanceof NullDumper) || $edge->isWeak())) { + if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) { // no-op } elseif (isset($currentPath[$id])) { foreach (array_reverse($currentPath) as $parentId) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b876bf48da95d..9c1b80cdedc9b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -538,7 +538,7 @@ public function testCircularReferenceAllowanceForLazyServices() $dumper = new PhpDumper($container); - $message = 'Circular reference detected for service "bar", path: "bar -> foo -> bar". Try running "composer require symfony/proxy-manager-bridge".'; + $message = 'Circular reference detected for service "foo", path: "foo -> bar -> foo". Try running "composer require symfony/proxy-manager-bridge".'; if (method_exists($this, 'expectException')) { $this->expectException(ServiceCircularReferenceException::class); $this->expectExceptionMessage($message); From bd8c844843c3114d010f3fe474cee69988705350 Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Thu, 9 Aug 2018 14:43:33 +0200 Subject: [PATCH 37/66] Remove the HTML5 validation from the profiler URL search form We do not have to write a complete URL to do a search. Only some keywords are necessary. --- .../WebProfilerBundle/Resources/views/Profiler/search.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/search.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/search.html.twig index 71059ed2352c7..7494b4ec7f279 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/search.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/search.html.twig @@ -22,7 +22,7 @@
- +
From a7672bd18777cb55a2cff1f14fc1d795a1c16a26 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 10 Aug 2018 09:34:36 +0200 Subject: [PATCH 38/66] clean up unused code --- src/Symfony/Component/Yaml/Parser.php | 36 --------------------------- 1 file changed, 36 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 284af1f9f932b..36c9f1d913702 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -549,11 +549,6 @@ private function getCurrentLineIndentation() private function getNextEmbedBlock($indentation = null, $inSequence = false) { $oldLineIndentation = $this->getCurrentLineIndentation(); - $blockScalarIndentations = array(); - - if ($this->isBlockScalarHeader()) { - $blockScalarIndentations[] = $oldLineIndentation; - } if (!$this->moveToNextLine()) { return; @@ -612,30 +607,9 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); - if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { - $blockScalarIndentations[] = $this->getCurrentLineIndentation(); - } - - $previousLineIndentation = $this->getCurrentLineIndentation(); - while ($this->moveToNextLine()) { $indent = $this->getCurrentLineIndentation(); - // terminate all block scalars that are more indented than the current line - if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && '' !== trim($this->currentLine)) { - foreach ($blockScalarIndentations as $key => $blockScalarIndentation) { - if ($blockScalarIndentation >= $indent) { - unset($blockScalarIndentations[$key]); - } - } - } - - if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) { - $blockScalarIndentations[] = $indent; - } - - $previousLineIndentation = $indent; - if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { $this->moveToPreviousLine(); break; @@ -1054,16 +1028,6 @@ private function isStringUnIndentedCollectionItem() return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- '); } - /** - * Tests whether or not the current line is the header of a block scalar. - * - * @return bool - */ - private function isBlockScalarHeader() - { - return (bool) self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine); - } - /** * A local wrapper for `preg_match` which will throw a ParseException if there * is an internal error in the PCRE engine. From d67b86b9e76c874f179985d0b654886c4305c60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 11 Aug 2018 21:30:31 +0200 Subject: [PATCH 39/66] Add missing stderr redirection This seems to have been overlooked in 6c0e6af47a5f36b906892537f5b2fbf15dab30b2, and results in the test suite being polluted on machines where phpdbg is not installed. I updated the code to mimic other occurences of exec in this file. --- src/Symfony/Bridge/PhpUnit/Tests/CoverageListenerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/CoverageListenerTest.php b/src/Symfony/Bridge/PhpUnit/Tests/CoverageListenerTest.php index ce8f62d2c53c0..6674feb94a88e 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/CoverageListenerTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/CoverageListenerTest.php @@ -16,7 +16,7 @@ public function test() $this->markTestSkipped('This test cannot be run on HHVM.'); } - exec('type phpdbg', $output, $returnCode); + exec('type phpdbg 2> /dev/null', $output, $returnCode); if (\PHP_VERSION_ID >= 70000 && 0 === $returnCode) { $php = 'phpdbg -qrr'; From 51b6e9eb96ec6bce0557c268d71e143550171287 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Fri, 17 Aug 2018 14:07:19 +0200 Subject: [PATCH 40/66] Make the `message_bus` alias public --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 2 +- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index b08f1bbde2068..19f62d8dc74e2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1488,7 +1488,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $container->register($busId, MessageBus::class)->addArgument(array())->addTag('messenger.bus'); if ($busId === $config['default_bus']) { - $container->setAlias('message_bus', $busId); + $container->setAlias('message_bus', $busId)->setPublic(true); $container->setAlias(MessageBusInterface::class, $busId); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 47a496ad247b6..b3dc2cc163f1e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -528,6 +528,7 @@ public function testMessenger() { $container = $this->createContainerFromFile('messenger'); $this->assertTrue($container->hasAlias('message_bus')); + $this->assertTrue($container->getAlias('message_bus')->isPublic()); $this->assertFalse($container->hasDefinition('messenger.transport.amqp.factory')); $this->assertTrue($container->hasDefinition('messenger.transport_factory')); $this->assertSame(TransportFactory::class, $container->getDefinition('messenger.transport_factory')->getClass()); From 45754515a5d4c177270503bd261d3a0cf314b8bc Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 Aug 2018 19:53:24 +0200 Subject: [PATCH 41/66] fix type error handling when writing values --- .../PropertyAccess/PropertyAccessor.php | 7 +++++- .../Tests/Fixtures/ReturnTyped.php | 5 ++++ .../Tests/PropertyAccessorTest.php | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 3d1885a857278..d639506ef3f9f 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -231,7 +231,12 @@ public static function handleError($type, $message, $file, $line, $context) private static function throwInvalidArgumentException($message, $trace, $i) { - if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && isset($trace[$i]['args'][0])) { + // the type mismatch is not caused by invalid arguments (but e.g. by an incompatible return type hint of the writer method) + if (0 !== strpos($message, 'Argument ')) { + return; + } + + if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && array_key_exists(0, $trace[$i]['args'])) { $pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface ')); $pos += \strlen($delim); $type = $trace[$i]['args'][0]; diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/ReturnTyped.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/ReturnTyped.php index b6a9852715d79..71c4a574c0ecf 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/ReturnTyped.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/ReturnTyped.php @@ -28,4 +28,9 @@ public function addFoo(\DateTime $dateTime) public function removeFoo(\DateTime $dateTime) { } + + public function setName($name): self + { + return 'This does not respect the return type on purpose.'; + } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index ec314a6e69bc2..b05672910a0bb 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -538,6 +538,17 @@ public function testThrowTypeError() $this->propertyAccessor->setValue($object, 'date', 'This is a string, \DateTime expected.'); } + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected argument of type "DateTime", "NULL" given + */ + public function testThrowTypeErrorWithNullArgument() + { + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'date', null); + } + public function testSetTypeHint() { $date = new \DateTime(); @@ -579,4 +590,16 @@ public function testDoNotDiscardReturnTypeError() $this->propertyAccessor->setValue($object, 'foos', array(new \DateTime())); } + + /** + * @requires PHP 7 + * + * @expectedException \TypeError + */ + public function testDoNotDiscardReturnTypeErrorWhenWriterMethodIsMisconfigured() + { + $object = new ReturnTyped(); + + $this->propertyAccessor->setValue($object, 'name', 'foo'); + } } From 940ec8f2d5c562bc1b2424f67ab0cbd1f3c59e51 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Aug 2018 11:06:16 +0200 Subject: [PATCH 42/66] [travis][appveyor] use symfony/flex to accelerate builds --- .travis.yml | 11 ++++++++++- appveyor.yml | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 007101fcc4d9c..173e3792af344 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ before_install: if [[ $TRAVIS_PHP_VERSION = 5.* || $TRAVIS_PHP_VERSION = hhvm* ]]; then composer () { - $HOME/.phpenv/versions/7.1/bin/composer config platform.php $(echo ' =2.3' + else + export SYMFONY_REQUIRE=">=$SYMFONY_VERSION" + fi + composer global require symfony/flex dev-master + - | # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]] && LEGACY=,legacy diff --git a/appveyor.yml b/appveyor.yml index e23696c240fc2..d5d23ed3ddfc0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,6 +10,7 @@ init: - SET PATH=c:\php;%PATH% - SET COMPOSER_NO_INTERACTION=1 - SET SYMFONY_DEPRECATIONS_HELPER=strict + - SET "SYMFONY_REQUIRE=>=2.8" - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_VERSION=4.8 - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f @@ -51,9 +52,10 @@ install: - copy /Y php.ini-min php.ini - echo extension=php_openssl.dll >> php.ini - cd c:\projects\symfony - - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.3.0/composer.phar) + - IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/1.7.1/composer.phar) - php composer.phar self-update - copy /Y .composer\* %APPDATA%\Composer\ + - php composer.phar global require --no-progress symfony/flex dev-master - php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - php composer.phar config platform.php 5.3.9 From ff93f1ab2ae64b42497c45760cc8313c6a290f1a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 18 Aug 2018 18:54:38 +0200 Subject: [PATCH 43/66] fix merge --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 40ad6d2a30564..9a8f623e74bbd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ init: - SET PATH=c:\php;%PATH% - SET COMPOSER_NO_INTERACTION=1 - SET SYMFONY_DEPRECATIONS_HELPER=strict - - SET "SYMFONY_REQUIRE=>=3.4" + - SET "SYMFONY_REQUIRE=>=4.1" - SET ANSICON=121x90 (121x90) - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f From 2ebc75b9a18551b0eb5f2ae5bfd27c8d25094150 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 18 Aug 2018 22:38:48 +0200 Subject: [PATCH 44/66] [Security\Http] Restore laziness of listener iterator --- .../Component/Security/Http/Firewall.php | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php index b9d83b49cdef4..a0a2aa8411ca0 100644 --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php @@ -50,31 +50,38 @@ public function onKernelRequest(GetResponseEvent $event) // register listeners for this firewall $listeners = $this->map->getListeners($event->getRequest()); - $accessListener = null; - $authenticationListeners = array(); - - foreach ($listeners[0] as $listener) { - if ($listener instanceof AccessListener) { - $accessListener = $listener; - } else { - $authenticationListeners[] = $listener; - } - } + $authenticationListeners = $listeners[0]; + $exceptionListener = $listeners[1]; + $logoutListener = isset($listeners[2]) ? $listeners[2] : null; - if (null !== $exceptionListener = $listeners[1]) { + if (null !== $exceptionListener) { $this->exceptionListeners[$event->getRequest()] = $exceptionListener; $exceptionListener->register($this->dispatcher); } - if (null !== $logoutListener = isset($listeners[2]) ? $listeners[2] : null) { - $authenticationListeners[] = $logoutListener; - } + $authenticationListeners = function () use ($authenticationListeners, $logoutListener) { + $accessListener = null; - if (null !== $accessListener) { - $authenticationListeners[] = $accessListener; - } + foreach ($authenticationListeners as $listener) { + if ($listener instanceof AccessListener) { + $accessListener = $listener; + + continue; + } + + yield $listener; + } + + if (null !== $logoutListener) { + yield $logoutListener; + } + + if (null !== $accessListener) { + yield $accessListener; + } + }; - $this->handleRequest($event, $authenticationListeners); + $this->handleRequest($event, $authenticationListeners()); } public function onKernelFinishRequest(FinishRequestEvent $event) From 02e3ec0539b2ec5a870eeb428cd5b3d12f8cd8b3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Aug 2018 10:02:31 +0200 Subject: [PATCH 45/66] [travis] fix composer.lock invalidation for deps=low --- .github/rm-invalid-lowest-lock-files.php | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index 5515238d9ace1..81f58ccdd48b0 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -1,5 +1,11 @@ $dirsByCommit) { + $chs[] = $ch = array(curl_init(), fopen($_SERVER['HOME'].'/.cache/composer/repo/https---repo.packagist.org/provider-'.strtr($name, '/', '$').'.json', 'wb')); + curl_setopt($ch[0], CURLOPT_URL, 'https://repo.packagist.org/p/'.$name.'.json'); + curl_setopt($ch[0], CURLOPT_FILE, $ch[1]); + curl_setopt($ch[0], CURLOPT_SHARE, $sh); + curl_multi_add_handle($mh, $ch[0]); +} + +do { + curl_multi_exec($mh, $active); + curl_multi_select($mh); +} while ($active); + +foreach ($chs as list($ch, $fd)) { + curl_multi_remove_handle($mh, $ch); + curl_close($ch); + fclose($fd); +} + +foreach ($referencedCommits as $name => $dirsByCommit) { + $repo = file_get_contents($_SERVER['HOME'].'/.cache/composer/repo/https---repo.packagist.org/provider-'.strtr($name, '/', '$').'.json'); + $repo = json_decode($repo, true); + + foreach ($repo['packages'][$name] as $version) { + unset($referencedCommits[$name][$version['source']['reference']]); + } +} + +foreach ($referencedCommits as $name => $dirsByCommit) { + foreach ($dirsByCommit as $dirs) { + foreach ($dirs as $dir) { + echo "$dir/composer.lock references old commit for $name.\n"; + @unlink($dir.'/composer.lock'); + } } } From 13a5101502573c60dd77d7f7ae0aa32c89f74f93 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Aug 2018 10:40:01 +0200 Subject: [PATCH 46/66] minor fix for travis --- .github/rm-invalid-lowest-lock-files.php | 8 +++++--- .travis.yml | 2 +- appveyor.yml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index 81f58ccdd48b0..2b037519cf757 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -96,7 +96,7 @@ function getContentHash(array $composerJson) } } -if (!$referencedCommits || (isset($_SERVER['TRAVIS_PULL_REQUEST']) && 'false' === $_SERVER['TRAVIS_PULL_REQUEST'])) { +if (!$referencedCommits || (isset($_SERVER['TRAVIS_PULL_REQUEST']) && 'false' !== $_SERVER['TRAVIS_PULL_REQUEST'])) { // cached commits cannot be stale for PRs return; } @@ -142,8 +142,10 @@ function getContentHash(array $composerJson) foreach ($referencedCommits as $name => $dirsByCommit) { foreach ($dirsByCommit as $dirs) { foreach ($dirs as $dir) { - echo "$dir/composer.lock references old commit for $name.\n"; - @unlink($dir.'/composer.lock'); + if (file_exists($dir.'/composer.lock')) { + echo "$dir/composer.lock references old commit for $name.\n"; + @unlink($dir.'/composer.lock'); + } } } } diff --git a/.travis.yml b/.travis.yml index 173e3792af344..6896ac7a16e7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -195,7 +195,7 @@ install: else export SYMFONY_REQUIRE=">=$SYMFONY_VERSION" fi - composer global require symfony/flex dev-master + composer global require --no-progress --no-scripts --no-plugins symfony/flex dev-master - | # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one diff --git a/appveyor.yml b/appveyor.yml index d5d23ed3ddfc0..8d335c600d716 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,7 +55,7 @@ install: - IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/1.7.1/composer.phar) - php composer.phar self-update - copy /Y .composer\* %APPDATA%\Composer\ - - php composer.phar global require --no-progress symfony/flex dev-master + - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex dev-master - php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - php composer.phar config platform.php 5.3.9 From 48c531c09a6ef8b05b0ca5822e707f9a4d15320e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Aug 2018 14:57:42 +0200 Subject: [PATCH 47/66] [travis] fix composer.lock invalidation for PRs patching several components --- .github/rm-invalid-lowest-lock-files.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index 2b037519cf757..aca35ca64db33 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -79,7 +79,13 @@ function getContentHash(array $composerJson) continue 2; } - foreach (array('minimum-stability', 'prefer-stable', 'repositories') as $key) { + if (isset($composerJsons[$name][2]['repositories']) && !isset($lockedJson[$key]['repositories'])) { + // the locked package has been patched locally but the lock references a commit, + // which means the referencing package itself is not modified + continue; + } + + foreach (array('minimum-stability', 'prefer-stable') as $key) { if (array_key_exists($key, $composerJsons[$name][2])) { $lockedJson[$key] = $composerJsons[$name][2][$key]; } @@ -92,7 +98,9 @@ function getContentHash(array $composerJson) continue 2; } - $referencedCommits[$name][$lockedJson['source']['reference']][] = $dir; + if ($lockedJson['dist']['reference']) { + $referencedCommits[$name][$lockedJson['dist']['reference']][] = $dir; + } } } From 5bdc755d73a7d6a9304afac35f0576a10014209f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 19 Aug 2018 18:51:04 +0200 Subject: [PATCH 48/66] fix data mapper return type in docblock --- src/Symfony/Component/Form/FormConfigInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/FormConfigInterface.php b/src/Symfony/Component/Form/FormConfigInterface.php index e66570cf5f1e6..b7083544a436b 100644 --- a/src/Symfony/Component/Form/FormConfigInterface.php +++ b/src/Symfony/Component/Form/FormConfigInterface.php @@ -99,7 +99,7 @@ public function getModelTransformers(); /** * Returns the data mapper of the form. * - * @return DataMapperInterface The data mapper + * @return DataMapperInterface|null The data mapper */ public function getDataMapper(); From 92953485a50d8cf99690499f8b353b57d8818b94 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Aug 2018 17:17:35 +0200 Subject: [PATCH 49/66] [HttpKernel] fix forwarding trusted headers as server parameters --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- .../Component/HttpFoundation/Tests/RequestTest.php | 6 +++--- .../HttpKernel/HttpCache/SubRequestHandler.php | 10 +++++++--- .../Tests/Fragment/InlineFragmentRendererTest.php | 11 +++++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 6dc9bbe81e75b..a29037279a698 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1991,7 +1991,7 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip) if ($i) { $clientIps[$key] = $clientIp = substr($clientIp, 0, $i); } - } elseif ('[' == $clientIp[0]) { + } elseif (0 === strpos($clientIp, '[')) { // Strip brackets and :port from IPv6 addresses. $i = strpos($clientIp, ']', 1); $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 0ee92aab1ba19..26335db903dd0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -868,7 +868,7 @@ public function getClientIpsForwardedProvider() public function getClientIpsProvider() { - // $expected $remoteAddr $httpForwardedFor $trustedProxies + // $expected $remoteAddr $httpForwardedFor $trustedProxies return array( // simple IPv4 array(array('88.88.88.88'), '88.88.88.88', null, null), @@ -882,8 +882,8 @@ public function getClientIpsProvider() // forwarded for with remote IPv4 addr not trusted array(array('127.0.0.1'), '127.0.0.1', '88.88.88.88', null), - // forwarded for with remote IPv4 addr trusted - array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1')), + // forwarded for with remote IPv4 addr trusted + comma + array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88,', array('127.0.0.1')), // forwarded for with remote IPv4 and all FF addrs trusted array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1', '88.88.88.88')), // forwarded for with remote IPv4 range trusted diff --git a/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php b/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php index c050256025ce7..21928c1a58a3e 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php @@ -43,6 +43,7 @@ public static function handle(HttpKernelInterface $kernel, Request $request, $ty if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) { foreach (array_filter($trustedHeaders) as $name) { $request->headers->remove($name); + $request->server->remove('HTTP_'.strtoupper(str_replace('-', '_', $name))); } } @@ -61,13 +62,16 @@ public static function handle(HttpKernelInterface $kernel, Request $request, $ty // set trusted values, reusing as much as possible the global trusted settings if ($name = $trustedHeaders[Request::HEADER_FORWARDED]) { $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); - $request->headers->set($name, implode(', ', $trustedValues)); + $request->headers->set($name, $v = implode(', ', $trustedValues)); + $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); } if ($name = $trustedHeaders[Request::HEADER_CLIENT_IP]) { - $request->headers->set($name, implode(', ', $trustedIps)); + $request->headers->set($name, $v = implode(', ', $trustedIps)); + $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); } if (!$name && !$trustedHeaders[Request::HEADER_FORWARDED]) { - $request->headers->set('X-Forwarded-For', implode(', ', $trustedIps)); + $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); + $request->server->set('HTTP_X_FORWARDED_FOR', $v); Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index a955da20aa83c..197a720439253 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -60,6 +60,8 @@ public function testRenderWithObjectsAsAttributes() $subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en')); $subRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $subRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); + $subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); + $subRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http'); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest)); @@ -91,6 +93,7 @@ public function testRenderWithTrustedHeaderDisabled() $expectedSubRequest = Request::create('/'); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); $this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent()); @@ -178,8 +181,10 @@ public function testESIHeaderIsKeptInSubrequest() $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"'); if (Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)) { $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); } $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); + $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http'); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); @@ -203,6 +208,8 @@ public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest() $expectedSubRequest = Request::create('/'); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); + $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http'); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); $request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*')); @@ -216,6 +223,8 @@ public function testFirstTrustedProxyIsSetAsRemote() $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1'); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); + $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http'); Request::setTrustedProxies(array('1.1.1.1')); @@ -235,6 +244,8 @@ public function testIpAddressOfRangedTrustedProxyIsSetAsRemote() $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1'); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); + $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http'); Request::setTrustedProxies(array('1.1.1.1/24')); From 8b59d177db2373e28f5c73de38da168a5cc2fc11 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 23 Aug 2018 17:01:50 +0200 Subject: [PATCH 50/66] [Cache] enable Memcached::OPT_TCP_NODELAY to fix perf of misses --- .../Component/Cache/Tests/Adapter/MemcachedAdapterTest.php | 1 + src/Symfony/Component/Cache/Traits/MemcachedTrait.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php index 76e0608006173..d1f87903406fe 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php @@ -89,6 +89,7 @@ public function testDefaultOptions() $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION)); $this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL)); + $this->assertSame(1, $client->getOption(\Memcached::OPT_TCP_NODELAY)); $this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE)); } diff --git a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php index 7e36164293842..5983d9ebd1da5 100644 --- a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php +++ b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php @@ -134,6 +134,7 @@ public static function createConnection($servers, array $options = array()) $options = array_change_key_case($options, CASE_UPPER); $client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); $client->setOption(\Memcached::OPT_NO_BLOCK, true); + $client->setOption(\Memcached::OPT_TCP_NODELAY, true); if (!array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) { $client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true); } From f245df404f9ffbc3f2a647a660eeee6dc267b050 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 23 Aug 2018 23:19:02 +0200 Subject: [PATCH 51/66] [travis] enable Redis cluster --- .travis.yml | 7 ++++ .../Tests/Adapter/RedisClusterAdapterTest.php | 27 ++++++++++++++ .../Tests/Simple/RedisClusterCacheTest.php | 27 ++++++++++++++ .../Component/Lock/Store/RedisStore.php | 6 ++-- .../Tests/Store/RedisClusterStoreTest.php | 35 +++++++++++++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Simple/RedisClusterCacheTest.php create mode 100644 src/Symfony/Component/Lock/Tests/Store/RedisClusterStoreTest.php diff --git a/.travis.yml b/.travis.yml index 68b36579f4473..9690c4a934b34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,15 @@ services: - memcached - mongodb - redis-server + - docker before_install: + - | + # Start Redis cluster + docker pull grokzen/redis-cluster:4.0.8 + docker run -d -p 7000:7000 -p 7001:7001 -p 7002:7002 -p 7003:7003 -p 7004:7004 -p 7005:7005 --name redis-cluster grokzen/redis-cluster:4.0.8 + export REDIS_CLUSTER_HOSTS='localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' + - | # General configuration set -e diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php new file mode 100644 index 0000000000000..852079c00ce79 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +class RedisClusterAdapterTest extends AbstractRedisAdapterTest +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisCluster')) { + self::markTestSkipped('The RedisCluster class is required.'); + } + if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + + self::$redis = new \RedisCluster(null, explode(' ', $hosts)); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Simple/RedisClusterCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/RedisClusterCacheTest.php new file mode 100644 index 0000000000000..99d4e518fb409 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Simple/RedisClusterCacheTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Simple; + +class RedisClusterCacheTest extends AbstractRedisCacheTest +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisCluster')) { + self::markTestSkipped('The RedisCluster class is required.'); + } + if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + + self::$redis = new \RedisCluster(null, explode(' ', $hosts)); + } +} diff --git a/src/Symfony/Component/Lock/Store/RedisStore.php b/src/Symfony/Component/Lock/Store/RedisStore.php index a65e8cb8f5000..e3b1500532376 100644 --- a/src/Symfony/Component/Lock/Store/RedisStore.php +++ b/src/Symfony/Component/Lock/Store/RedisStore.php @@ -54,8 +54,10 @@ public function save(Key $key) $script = ' if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("PEXPIRE", KEYS[1], ARGV[2]) + elseif redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) then + return 1 else - return redis.call("set", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) + return 0 end '; @@ -144,7 +146,7 @@ private function evaluate($script, $resource, array $args) return \call_user_func_array(array($this->redis, 'eval'), array_merge(array($script, 1, $resource), $args)); } - throw new InvalidArgumentException(sprintf('%s() expects been initialized with a Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($this->redis) ? \get_class($this->redis) : \gettype($this->redis))); + throw new InvalidArgumentException(sprintf('%s() expects being initialized with a Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($this->redis) ? \get_class($this->redis) : \gettype($this->redis))); } /** diff --git a/src/Symfony/Component/Lock/Tests/Store/RedisClusterStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/RedisClusterStoreTest.php new file mode 100644 index 0000000000000..2ee17888eb6d3 --- /dev/null +++ b/src/Symfony/Component/Lock/Tests/Store/RedisClusterStoreTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + * + * @requires extension redis + */ +class RedisClusterStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisCluster')) { + self::markTestSkipped('The RedisCluster class is required.'); + } + if (!getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + } + + protected function getRedisConnection() + { + return new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); + } +} From 2ac883a99bb543f776ce3dfc49d002fa853ab99b Mon Sep 17 00:00:00 2001 From: David Maicher Date: Thu, 23 Aug 2018 21:04:06 +0200 Subject: [PATCH 52/66] [DoctrineBridge] support __toString as documented for UniqueEntityValidator --- .../Tests/Validator/Constraints/UniqueEntityValidatorTest.php | 2 +- .../Doctrine/Validator/Constraints/UniqueEntityValidator.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index a26ce98107f60..d8b55eb808fc2 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -482,7 +482,7 @@ public function testAssociatedEntity() $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity") identified by (id => 1)') + ->setParameter('{{ value }}', 'foo') ->setInvalidValue($entity1) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->setCause(array($associated, $associated2)) diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 2015e7fb3acc6..161a187ff98ab 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -186,6 +186,10 @@ private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, return $this->formatValue($value, self::PRETTY_DATE); } + if (\method_exists($value, '__toString')) { + return (string) $value; + } + if ($class->getName() !== $idClass = \get_class($value)) { // non unique value might be a composite PK that consists of other entity objects if ($em->getMetadataFactory()->hasMetadataFor($idClass)) { From b6c2c46865143597193b01841ba5fa575f97d8cc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 24 Aug 2018 13:47:58 +0200 Subject: [PATCH 53/66] fix typo --- .../Transport/Serialization/SerializerConfigurationTest.php | 2 +- .../Middleware/Configuration/ValidationConfigurationTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Asynchronous/Transport/Serialization/SerializerConfigurationTest.php b/src/Symfony/Component/Messenger/Tests/Asynchronous/Transport/Serialization/SerializerConfigurationTest.php index 6ebcc8ddfa0ca..a5faf45b13f61 100644 --- a/src/Symfony/Component/Messenger/Tests/Asynchronous/Transport/Serialization/SerializerConfigurationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Asynchronous/Transport/Serialization/SerializerConfigurationTest.php @@ -20,7 +20,7 @@ */ class SerializerConfigurationTest extends TestCase { - public function testSerialiazable() + public function testSerializable() { $config = new SerializerConfiguration(array(ObjectNormalizer::GROUPS => array('Default', 'Extra'))); diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/Configuration/ValidationConfigurationTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/Configuration/ValidationConfigurationTest.php index 6fd6962994f4f..b4ccf614b23b6 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/Configuration/ValidationConfigurationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/Configuration/ValidationConfigurationTest.php @@ -29,7 +29,7 @@ public function testConfig() $this->assertSame($groups, $config->getGroups()); } - public function testSerialiazable() + public function testSerializable() { $this->assertTrue(is_subclass_of(ValidationConfiguration::class, \Serializable::class, true)); $this->assertEquals($config = new ValidationConfiguration(array('Default', 'Extra')), unserialize(serialize($config))); From 41ffba19160f803e6b75e5d8ad4ec5dad008e475 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 24 Aug 2018 14:02:08 +0200 Subject: [PATCH 54/66] [travis] fix composer.lock invalidation for deps=low --- .github/rm-invalid-lowest-lock-files.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index aca35ca64db33..c71463262171a 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -48,7 +48,6 @@ function getContentHash(array $composerJson) foreach ($dirs as $dir) { if (!file_exists($dir.'/composer.lock') || !$composerLock = @json_decode(file_get_contents($dir.'/composer.lock'), true)) { - echo "$dir/composer.lock not found or invalid.\n"; @unlink($dir.'/composer.lock'); continue; } @@ -62,7 +61,8 @@ function getContentHash(array $composerJson) @unlink($dir.'/composer.lock'); continue; } - $composerJsons[$composerJson['name']] = array($dir, $composerLock['packages'], getRelevantContent($composerJson)); + $composerLock += array('packages' => array(), 'packages-dev' => array()); + $composerJsons[$composerJson['name']] = array($dir, $composerLock['packages'] + $composerLock['packages-dev'], getRelevantContent($composerJson)); } $referencedCommits = array(); From d2ecea0b6e8c654cc5e4985bd3dc44b40b6fa1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20Perrin?= Date: Thu, 23 Aug 2018 12:06:54 -0500 Subject: [PATCH 55/66] [HttpFoundation] Allow RedisCluster class for RedisSessionHandler --- .../Storage/Handler/RedisSessionHandler.php | 12 +++++-- .../AbstractRedisSessionHandlerTestCase.php | 18 +++-------- .../PredisClusterSessionHandlerTest.php | 2 +- .../RedisClusterSessionHandlerTest.php | 31 +++++++++++++++++++ 4 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php index 05983623955cd..36adf2424d618 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php @@ -33,14 +33,20 @@ class RedisSessionHandler extends AbstractSessionHandler * List of available options: * * prefix: The prefix to use for the keys in order to avoid collision on the Redis server. * - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redis - * @param array $options An associative array of options + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|RedisProxy $redis + * @param array $options An associative array of options * * @throws \InvalidArgumentException When unsupported client or options are passed */ public function __construct($redis, array $options = array()) { - if (!$redis instanceof \Redis && !$redis instanceof \RedisArray && !$redis instanceof \Predis\Client && !$redis instanceof RedisProxy) { + if ( + !$redis instanceof \Redis && + !$redis instanceof \RedisArray && + !$redis instanceof \RedisCluster && + !$redis instanceof \Predis\Client && + !$redis instanceof RedisProxy + ) { throw new \InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis))); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php index bcf622e6db17a..2712c579cd9b9 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php @@ -32,11 +32,6 @@ abstract class AbstractRedisSessionHandlerTestCase extends TestCase */ protected $redisClient; - /** - * @var \Redis - */ - protected $validator; - /** * @return \Redis|\RedisArray|\RedisCluster|\Predis\Client */ @@ -52,9 +47,6 @@ protected function setUp() $host = getenv('REDIS_HOST') ?: 'localhost'; - $this->validator = new \Redis(); - $this->validator->connect($host); - $this->redisClient = $this->createRedisClient($host); $this->storage = new RedisSessionHandler( $this->redisClient, @@ -154,24 +146,24 @@ public function getOptionFixtures(): array protected function setFixture($key, $value, $ttl = null) { if (null !== $ttl) { - $this->validator->setex($key, $ttl, $value); + $this->redisClient->setex($key, $ttl, $value); } else { - $this->validator->set($key, $value); + $this->redisClient->set($key, $value); } } protected function getFixture($key) { - return $this->validator->get($key); + return $this->redisClient->get($key); } protected function hasFixture($key): bool { - return $this->validator->exists($key); + return $this->redisClient->exists($key); } protected function fixtureTtl($key): int { - return $this->validator->ttl($key); + return $this->redisClient->ttl($key); } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php index ffb2d41a536ce..458100101c4ab 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php @@ -17,6 +17,6 @@ class PredisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCas { protected function createRedisClient(string $host): Client { - return new Client(array(array('host' => $host))); + return new Client(array(array('host' => $host))); } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php new file mode 100644 index 0000000000000..7d85a59ee7739 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; + +class RedisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisCluster')) { + self::markTestSkipped('The RedisCluster class is required.'); + } + + if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + } + + protected function createRedisClient(string $host): \RedisCluster + { + return new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); + } +} From 620dfdec1318b8c87715991d075fed5a3b08e5ae Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 26 Aug 2018 10:29:34 +0200 Subject: [PATCH 56/66] [HttpFoundation] cleanup test case --- .../AbstractRedisSessionHandlerTestCase.php | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php index 2712c579cd9b9..a2bf168de444f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php @@ -74,8 +74,8 @@ public function testCloseSession() public function testReadSession() { - $this->setFixture(self::PREFIX.'id1', null); - $this->setFixture(self::PREFIX.'id2', 'abc123'); + $this->redisClient->set(self::PREFIX.'id1', null); + $this->redisClient->set(self::PREFIX.'id2', 'abc123'); $this->assertEquals('', $this->storage->read('id1')); $this->assertEquals('abc123', $this->storage->read('id2')); @@ -85,14 +85,14 @@ public function testWriteSession() { $this->assertTrue($this->storage->write('id', 'data')); - $this->assertTrue($this->hasFixture(self::PREFIX.'id')); - $this->assertEquals('data', $this->getFixture(self::PREFIX.'id')); + $this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id')); + $this->assertEquals('data', $this->redisClient->get(self::PREFIX.'id')); } public function testUseSessionGcMaxLifetimeAsTimeToLive() { $this->storage->write('id', 'data'); - $ttl = $this->fixtureTtl(self::PREFIX.'id'); + $ttl = $this->redisClient->ttl(self::PREFIX.'id'); $this->assertLessThanOrEqual(ini_get('session.gc_maxlifetime'), $ttl); $this->assertGreaterThanOrEqual(0, $ttl); @@ -100,11 +100,11 @@ public function testUseSessionGcMaxLifetimeAsTimeToLive() public function testDestroySession() { - $this->setFixture(self::PREFIX.'id', 'foo'); + $this->redisClient->set(self::PREFIX.'id', 'foo'); - $this->assertTrue($this->hasFixture(self::PREFIX.'id')); + $this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id')); $this->assertTrue($this->storage->destroy('id')); - $this->assertFalse($this->hasFixture(self::PREFIX.'id')); + $this->assertFalse((bool) $this->redisClient->exists(self::PREFIX.'id')); } public function testGcSession() @@ -114,12 +114,12 @@ public function testGcSession() public function testUpdateTimestamp() { - $lowTTL = 10; + $lowTtl = 10; - $this->setFixture(self::PREFIX.'id', 'foo', $lowTTL); + $this->redisClient->setex(self::PREFIX.'id', $lowTtl, 'foo'); $this->storage->updateTimestamp('id', array()); - $this->assertGreaterThan($lowTTL, $this->fixtureTtl(self::PREFIX.'id')); + $this->assertGreaterThan($lowTtl, $this->redisClient->ttl(self::PREFIX.'id')); } /** @@ -142,28 +142,4 @@ public function getOptionFixtures(): array array(array('prefix' => 'sfs', 'foo' => 'bar'), false), ); } - - protected function setFixture($key, $value, $ttl = null) - { - if (null !== $ttl) { - $this->redisClient->setex($key, $ttl, $value); - } else { - $this->redisClient->set($key, $value); - } - } - - protected function getFixture($key) - { - return $this->redisClient->get($key); - } - - protected function hasFixture($key): bool - { - return $this->redisClient->exists($key); - } - - protected function fixtureTtl($key): int - { - return $this->redisClient->ttl($key); - } } From c1bf1918ecdf7c0a1d67a2537fe5d0a14869597a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Aug 2018 11:36:50 +0200 Subject: [PATCH 57/66] [Cache] minor code update to leverage PHP 7.1 --- src/Symfony/Component/Cache/Adapter/AbstractAdapter.php | 3 ++- src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 426d6e8a5743a..ac6a56095a27a 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -52,7 +52,7 @@ function ($key, $value, $isHit) use ($defaultLifetime) { null, CacheItem::class ); - $getId = function ($key) { return $this->getId((string) $key); }; + $getId = \Closure::fromCallable(array($this, 'getId')); $this->mergeByLifetime = \Closure::bind( function ($deferred, $namespace, &$expiredIds) use ($getId) { $byLifetime = array(); @@ -60,6 +60,7 @@ function ($deferred, $namespace, &$expiredIds) use ($getId) { $expiredIds = array(); foreach ($deferred as $key => $item) { + $key = (string) $key; if (null === $item->expiry) { $byLifetime[0 < $item->defaultLifetime ? $item->defaultLifetime : 0][$getId($key)] = $item->value; } elseif ($item->expiry > $now) { diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php index 62f815e0171ad..9110511b9aa7a 100644 --- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php @@ -36,7 +36,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R private $knownTagVersions = array(); private $knownTagVersionsTtl; - public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, $knownTagVersionsTtl = 0.15) + public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15) { $this->pool = $itemsPool; $this->tags = $tagsPool ?: $itemsPool; From dba8687a5dda71a14676d376f790ba6ba92ab950 Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 26 Aug 2018 12:16:17 -0400 Subject: [PATCH 58/66] Instantiate $offset and $maxlen at definition --- .../Component/HttpFoundation/BinaryFileResponse.php | 4 ++-- .../HttpFoundation/Tests/BinaryFileResponseTest.php | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index b18a3ecbdc629..c0fd95ea6b661 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -31,8 +31,8 @@ class BinaryFileResponse extends Response * @var File */ protected $file; - protected $offset; - protected $maxlen; + protected $offset = 0; + protected $maxlen = -1; protected $deleteFileAfterSend = false; /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index e41a2372b9df8..031c9bbca3f22 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -206,6 +206,19 @@ public function provideFullFileRanges() ); } + public function testUnpreparedResponseSendsFullFile() + { + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200); + + $data = file_get_contents(__DIR__.'/File/Fixtures/test.gif'); + + $this->expectOutputString($data); + $response = clone $response; + $response->sendContent(); + + $this->assertEquals(200, $response->getStatusCode()); + } + /** * @dataProvider provideInvalidRanges */ From 28492a7bb1f37b9f3070b73be1af4280106e369f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Aug 2018 17:17:06 +0200 Subject: [PATCH 59/66] [PhpUnitBridge] keep compat with composer 1.0 --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 197650915fe91..bcfc432f8a139 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -101,7 +101,8 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ } $prevRoot = getenv('COMPOSER_ROOT_VERSION'); putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); - $exit = proc_close(proc_open("$COMPOSER install --no-dev --prefer-dist --no-suggest --no-progress --ansi", array(), $p, getcwd(), null, array('bypass_shell' => true))); + // --no-suggest is not in the list to keep compat with composer 1.0, which is shipped with Ubuntu 16.04LTS + $exit = proc_close(proc_open("$COMPOSER install --no-dev --prefer-dist --no-progress --ansi", array(), $p, getcwd(), null, array('bypass_shell' => true))); putenv('COMPOSER_ROOT_VERSION'.(false !== $prevRoot ? '='.$prevRoot : '')); if ($exit) { exit($exit); From 0aee31fcd80ec0e42b3cd383a7868acd2178f56d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 27 Aug 2018 19:33:04 +0200 Subject: [PATCH 60/66] updated CHANGELOG for 2.8.45 --- CHANGELOG-2.8.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 4760af369f84f..7921dc3bcfa9b 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,16 @@ in 2.8 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1 +* 2.8.45 (2018-08-27) + + * bug #28278 [HttpFoundation] Fix unprepared BinaryFileResponse sends empty file (wackymole) + * bug #28241 [HttpKernel] fix forwarding trusted headers as server parameters (nicolas-grekas) + * bug #28220 [PropertyAccess] fix type error handling when writing values (xabbuh) + * bug #28100 [Security] Call AccessListener after LogoutListener (chalasr) + * bug #28144 [HttpFoundation] fix false-positive ConflictingHeadersException (nicolas-grekas) + * bug #28055 [PropertyInfo] Allow nested collections (jderusse) + * bug #28083 Remove the Expires header when calling Response::expire() (javiereguiluz) + * 2.8.44 (2018-08-01) * security #cve-2018-14774 [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer (nicolas-grekas) From 97e425cdcbbb502da98f2ada7775cd2fc720dcb2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 27 Aug 2018 19:33:31 +0200 Subject: [PATCH 61/66] update CONTRIBUTORS for 2.8.45 --- CONTRIBUTORS.md | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bf391b7ee79ce..629d8b80c98a3 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -24,8 +24,8 @@ Symfony is the result of the work of many people who made the code better - Hugo Hamon (hhamon) - Abdellatif Ait boudad (aitboudad) - Romain Neutron (romain) - - Pascal Borreli (pborreli) - Roland Franssen (ro0) + - Pascal Borreli (pborreli) - Wouter De Jong (wouterj) - Joseph Bielawski (stloyd) - Karma Dordrak (drak) @@ -52,9 +52,9 @@ Symfony is the result of the work of many people who made the code better - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - Bulat Shakirzyanov (avalanche123) + - Dany Maillard (maidmaid) - Peter Rehm (rpet) - Matthias Pigulla (mpdude) - - Dany Maillard (maidmaid) - Saša Stamenković (umpirsky) - Kevin Bond (kbond) - Tobias Nyholm (tobias) @@ -63,9 +63,9 @@ Symfony is the result of the work of many people who made the code better - Miha Vrhovnik - Diego Saint Esteben (dii3g0) - Alexander M. Turek (derrabus) + - Jérémy DERUSSÉ (jderusse) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - - Jérémy DERUSSÉ (jderusse) - Florin Patan (florinpatan) - Gábor Egyed (1ed) - Mathieu Piot (mpiot) @@ -75,9 +75,9 @@ Symfony is the result of the work of many people who made the code better - Eric Clemmons (ericclemmons) - Jáchym Toušek (enumag) - Charles Sarrazin (csarrazi) + - David Maicher (dmaicher) - Konstantin Myakshin (koc) - Christian Raue - - David Maicher (dmaicher) - Arnout Boks (aboks) - Deni - Henrik Westphal (snc) @@ -99,9 +99,9 @@ Symfony is the result of the work of many people who made the code better - Fran Moreno (franmomu) - Antoine Hérault (herzult) - Paráda József (paradajozsef) + - Grégoire Paris (greg0ire) - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER - - Grégoire Paris (greg0ire) - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - Brice BERNARD (brikou) @@ -124,6 +124,7 @@ Symfony is the result of the work of many people who made the code better - Fabien Pennequin (fabienpennequin) - Gordon Franke (gimler) - Eric GELOEN (gelo) + - Sebastiaan Stok (sstok) - Lars Strojny (lstrojny) - Daniel Wehner (dawehner) - Tugdual Saunier (tucksaun) @@ -131,7 +132,6 @@ Symfony is the result of the work of many people who made the code better - Théo FIDRY (theofidry) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) - - Sebastiaan Stok (sstok) - Stefano Sala (stefano.sala) - Jérôme Vasseur (jvasseur) - Evgeniy (ewgraf) @@ -144,6 +144,7 @@ Symfony is the result of the work of many people who made the code better - Hidenori Goto (hidenorigoto) - Chris Wilkinson (thewilkybarkid) - Arnaud Kleinpeter (nanocom) + - Jannik Zschiesche (apfelbox) - Guilherme Blanco (guilhermeblanco) - Pablo Godel (pgodel) - Jérémie Augustin (jaugustin) @@ -159,7 +160,6 @@ Symfony is the result of the work of many people who made the code better - Vyacheslav Pavlov - Richard van Laak (rvanlaak) - Richard Shank (iampersistent) - - Jannik Zschiesche (apfelbox) - Thomas Rabaix (rande) - Rouven Weßling (realityking) - Clemens Tolboom @@ -192,6 +192,7 @@ Symfony is the result of the work of many people who made the code better - SpacePossum - Benjamin Dulau (dbenjamin) - Mathieu Lemoine (lemoinem) + - Thomas Calvet (fancyweb) - Christian Schmidt - Andreas Hucks (meandmymonkey) - Noel Guilbert (noel) @@ -200,6 +201,7 @@ Symfony is the result of the work of many people who made the code better - bronze1man - sun (sun) - Larry Garfield (crell) + - Michaël Perrin (michael.perrin) - Martin Schuhfuß (usefulthink) - apetitpa - Matthieu Bontemps (mbontemps) @@ -221,7 +223,6 @@ Symfony is the result of the work of many people who made the code better - Tom Van Looy (tvlooy) - Sven Paulus (subsven) - Yanick Witschi (toflar) - - Thomas Calvet (fancyweb) - Rui Marinho (ruimarinho) - Alessandro Chitolina - Eugene Wissner @@ -230,7 +231,6 @@ Symfony is the result of the work of many people who made the code better - Leo Feyer - Tristan Darricau (nicofuma) - Nikolay Labinskiy (e-moe) - - Michaël Perrin (michael.perrin) - Marcel Beerta (mazen) - Albert Casademont (acasademont) - Loïc Faugeron @@ -253,6 +253,7 @@ Symfony is the result of the work of many people who made the code better - Ruben Gonzalez (rubenrua) - Adam Prager (padam87) - Benoît Burnichon (bburnichon) + - Florent Mata (fmata) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) - Mickaël Andrieu (mickaelandrieu) @@ -297,7 +298,6 @@ Symfony is the result of the work of many people who made the code better - Roumen Damianoff (roumen) - Antonio J. García Lagar (ajgarlag) - Kim Hemsø Rasmussen (kimhemsoe) - - Florent Mata (fmata) - Wouter Van Hecke - Jérôme Parmentier (lctrs) - Michael Babker (mbabker) @@ -310,6 +310,7 @@ Symfony is the result of the work of many people who made the code better - Chad Sikorra (chadsikorra) - Chris Smith (cs278) - Florian Klein (docteurklein) + - Gary PEGEOT (gary-p) - Manuel Kiessling (manuelkiessling) - Atsuhiro KUBO (iteman) - Andrew Moore (finewolf) @@ -343,6 +344,7 @@ Symfony is the result of the work of many people who made the code better - Thierry Thuon (lepiaf) - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) + - Colin O'Dell (colinodell) - Gennady Telegin (gtelegin) - Ben Davies (bendavies) - Erin Millard @@ -380,7 +382,7 @@ Symfony is the result of the work of many people who made the code better - Grzegorz (Greg) Zdanowski (kiler129) - Kirill chEbba Chebunin (chebba) - Greg Thornton (xdissent) - - Gary PEGEOT (gary-p) + - Sullivan SENECHAL (soullivaneuh) - Costin Bereveanu (schniper) - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) @@ -432,7 +434,6 @@ Symfony is the result of the work of many people who made the code better - Christopher Davis (chrisguitarguy) - Jan Schumann - Niklas Fiekas - - Colin O'Dell (colinodell) - Markus Bachmann (baachi) - lancergr - Zan Baldwin @@ -486,7 +487,6 @@ Symfony is the result of the work of many people who made the code better - Haralan Dobrev (hkdobrev) - Sebastian Bergmann - Miroslav Sustek - - Sullivan SENECHAL (soullivaneuh) - Pablo Díez (pablodip) - Martin Hujer (martinhujer) - Kevin McBride @@ -510,6 +510,7 @@ Symfony is the result of the work of many people who made the code better - Markus Lanthaler (lanthaler) - Remi Collet - Vicent Soria Durá (vicentgodella) + - Michael Moravec - Anthony Ferrara - Ioan Negulescu - Jakub Škvára (jskvara) @@ -652,6 +653,7 @@ Symfony is the result of the work of many people who made the code better - Szijarto Tamas - Robin Lehrmann (robinlehrmann) - Catalin Dan + - Jaroslav Kuba - Stephan Vock - Benjamin Zikarsky (bzikarsky) - Simon Schick (simonsimcity) @@ -738,7 +740,6 @@ Symfony is the result of the work of many people who made the code better - Marc Morera (mmoreram) - Saif Eddin Gmati (azjezz) - Smaine Milianni (ismail1432) - - Michael Moravec - Andrew Hilobok (hilobok) - Noah Heck (myesain) - Christian Soronellas (theunic) @@ -788,6 +789,7 @@ Symfony is the result of the work of many people who made the code better - Sofiane HADDAG (sofhad) - frost-nzcr4 - Bozhidar Hristov + - Ivan Nikolaev (destillat) - andrey1s - Abhoryo - Fabian Vogler (fabian) @@ -913,6 +915,7 @@ Symfony is the result of the work of many people who made the code better - Michael Tibben - Billie Thompson - Sander Marechal + - ProgMiner - Oleg Golovakhin (doc_tr) - Icode4Food (icode4food) - Radosław Benkel @@ -1001,6 +1004,7 @@ Symfony is the result of the work of many people who made the code better - Denis Kop - Jean-Guilhem Rouel (jean-gui) - jfcixmedia + - Dominic Tubach - Nikita Konstantinov - Martijn Evers - Benjamin Paap (benjaminpaap) @@ -1043,6 +1047,7 @@ Symfony is the result of the work of many people who made the code better - Alexander Cheprasov - Rodrigo Díez Villamuera (rodrigodiez) - e-ivanov + - Einenlum - Jochen Bayer (jocl) - Alex Bowers - Jeremy Bush @@ -1062,7 +1067,6 @@ Symfony is the result of the work of many people who made the code better - David Otton - Will Donohoe - peter - - Jaroslav Kuba - Jérémy Jourdin (jjk801) - BRAMILLE Sébastien (oktapodia) - Artem Kolesnikov (tyomo4ka) @@ -1168,6 +1172,7 @@ Symfony is the result of the work of many people who made the code better - Saem Ghani - Clément LEFEBVRE - Conrad Kleinespel + - Zacharias Luiten - Sebastian Utz - Adrien Gallou (agallou) - Maks Rafalko (bornfree) @@ -1233,6 +1238,7 @@ Symfony is the result of the work of many people who made the code better - WedgeSama - Felds Liscia - Chihiro Adachi (chihiro-adachi) + - Emanuele Panzeri (thepanz) - Tadcka - Beth Binkovitz - Gonzalo Míguez @@ -1305,6 +1311,7 @@ Symfony is the result of the work of many people who made the code better - Benjamin Bender - Jared Farrish - karl.rixon + - raplider - Konrad Mohrfeldt - Lance Chen - Ciaran McNulty (ciaranmcnulty) @@ -1373,12 +1380,12 @@ Symfony is the result of the work of many people who made the code better - Harold Iedema - Arnau González (arnaugm) - Simon Bouland (bouland) - - Ivan Nikolaev (destillat) - Matthew Foster (mfoster) - Paul Seiffert (seiffert) - Vasily Khayrulin (sirian) - Stefan Koopmanschap (skoop) - Stefan Hüsges (tronsha) + - Vlad Gregurco (vgregurco) - Jake Bishop (yakobeyak) - Dan Blows - Matt Wells @@ -1386,6 +1393,7 @@ Symfony is the result of the work of many people who made the code better - stloyd - Andreas - Chris Tickner + - BoShurik - Andrew Coulton - Jeremy Benoist - Michal Gebauer @@ -1399,7 +1407,9 @@ Symfony is the result of the work of many people who made the code better - Luis Muñoz - Matthew Donadio - Houziaux mike + - Phobetor - Andreas + - Markus - Thomas Chmielowiec - shdev - Andrey Ryaguzov @@ -1407,6 +1417,7 @@ Symfony is the result of the work of many people who made the code better - Peter Bex - Manatsawin Hanmongkolchai - Gunther Konig + - Mickael GOETZ - Maciej Schmidt - Greg ORIOL - Dennis Væversted @@ -1418,6 +1429,7 @@ Symfony is the result of the work of many people who made the code better - Mike Francis - Christoph Nissle (derstoffel) - Ionel Scutelnicu (ionelscutelnicu) + - Grenier Kévin (mcsky_biig) - Nicolas Tallefourtané (nicolab) - Botond Dani (picur) - Thierry Marianne (thierrymarianne) @@ -1815,6 +1827,7 @@ Symfony is the result of the work of many people who made the code better - jspee - David Soria Parra - Sergiy Sokolenko + - Ahmed Abdulrahman - dinitrol - Penny Leach - Yurii K From 7e0a16cf2f0b822343b9ddf9edbc0206f0fe3c68 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 27 Aug 2018 19:33:38 +0200 Subject: [PATCH 62/66] updated VERSION for 2.8.45 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 32a90578342e7..276b2a1516b57 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.45-DEV'; + const VERSION = '2.8.45'; const VERSION_ID = 20845; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 45; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From a8b16054e7de14cf92a933ea5e014895a8720ca2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 27 Aug 2018 19:44:28 +0200 Subject: [PATCH 63/66] bumped Symfony version to 2.8.46 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 276b2a1516b57..15425cdf92726 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.45'; - const VERSION_ID = 20845; + const VERSION = '2.8.46-DEV'; + const VERSION_ID = 20846; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 45; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 46; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 4623fe74ca2bd58605f426d74ebb82f238e5e318 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Aug 2018 20:13:17 +0200 Subject: [PATCH 64/66] [travis] disable symfony/flex during phpunit install --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6896ac7a16e7f..f646b2997118c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -221,7 +221,11 @@ install: ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.5.0; composer require --dev --no-update mongodb/mongodb) fi tfold 'composer update' $COMPOSER_UP - tfold 'phpunit install' ./phpunit install + if [[ $TRAVIS_PHP_VERSION = 5.* || $TRAVIS_PHP_VERSION = hhvm* ]]; then + tfold 'phpunit install' 'composer global remove symfony/flex && ./phpunit install && composer global require --no-progress --no-scripts --no-plugins symfony/flex dev-master' + else + tfold 'phpunit install' ./phpunit install + fi if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" elif [[ $deps = low ]]; then From 7e9b69c7b36d076a5b65e52e6800b96d183338e1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 28 Aug 2018 08:17:15 +0200 Subject: [PATCH 65/66] updated CHANGELOG for 4.1.4 --- CHANGELOG-4.1.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGELOG-4.1.md b/CHANGELOG-4.1.md index fbde322ed215c..98aa4aca6a284 100644 --- a/CHANGELOG-4.1.md +++ b/CHANGELOG-4.1.md @@ -7,6 +7,30 @@ in 4.1 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.1.0...v4.1.1 +* 4.1.4 (2018-08-28) + + * bug #28278 [HttpFoundation] Fix unprepared BinaryFileResponse sends empty file (wackymole) + * bug #28284 [PhpUnitBridge] keep compat with composer 1.0 (nicolas-grekas) + * bug #28251 [HttpFoundation] Allow RedisCluster class for RedisSessionHandler (michaelperrin) + * bug #28241 [HttpKernel] fix forwarding trusted headers as server parameters (nicolas-grekas) + * bug #28220 [PropertyAccess] fix type error handling when writing values (xabbuh) + * bug #28249 [Cache] enable Memcached::OPT_TCP_NODELAY to fix perf of misses (nicolas-grekas) + * bug #28252 [DoctrineBridge] support __toString as documented for UniqueEntityValidator (dmaicher) + * bug #28216 [FrameworkBundle] `message_bus` alias public (sroze) + * bug #28113 [Form] Add help texts for checkboxes in horizontal bootstrap 4 forms (apfelbox) + * bug #28100 [Security] Call AccessListener after LogoutListener (chalasr) + * bug #28174 Remove the HTML5 validation from the profiler URL search form (Soullivaneuh) + * bug #28159 [DI] Fix autowire inner service (hason) + * bug #28060 [DI] Fix false-positive circular ref leading to wrong exceptions or infinite loops at runtime (nicolas-grekas) + * bug #28144 [HttpFoundation] fix false-positive ConflictingHeadersException (nicolas-grekas) + * bug #28152 [Translation] fix perf of lint:xliff command (nicolas-grekas) + * bug #28115 [Form] Remove extra .form-group wrapper around file widget in bootstrap 4 (MrMitch) + * bug #28120 [Routing] Fixed scheme redirecting for root path (twoleds) + * bug #28112 Fix CSS property typo (AhmedAbdulrahman) + * bug #28012 [PropertyInfo] Allow nested collections (jderusse) + * bug #28055 [PropertyInfo] Allow nested collections (jderusse) + * bug #28083 Remove the Expires header when calling Response::expire() (javiereguiluz) + * 4.1.3 (2018-08-01) * security #cve-2018-14774 [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer (nicolas-grekas) From f1f6062a6474f05446c2c17170e4f488d1d4c87d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 28 Aug 2018 08:17:42 +0200 Subject: [PATCH 66/66] updated VERSION for 4.1.4 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 00ac083e50024..9404cc0fba7d9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -63,12 +63,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.1.4-DEV'; + const VERSION = '4.1.4'; const VERSION_ID = 40104; const MAJOR_VERSION = 4; const MINOR_VERSION = 1; const RELEASE_VERSION = 4; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2019'; const END_OF_LIFE = '07/2019';