From 059f59a106634ba9e408c70c8dea557a9bd6c658 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 13 Nov 2017 20:26:33 +0100 Subject: [PATCH 01/74] Fix ambiguous pattern --- src/Symfony/Component/Validator/Constraints/UrlValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 56857de63c49a..4498bd167ca79 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -25,7 +25,7 @@ class UrlValidator extends ConstraintValidator (%s):// # protocol (([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth ( - ([\pL\pN\pS-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name + ([\pL\pN\pS\-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or From 278088931b4a7171bb616a1eec08cfb98c632afa Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Tue, 14 Nov 2017 19:49:30 +0100 Subject: [PATCH 02/74] Replace array|\Traversable by iterable --- src/Symfony/Component/Console/Application.php | 4 +-- .../Component/Console/Question/Question.php | 4 +-- .../Component/Filesystem/Filesystem.php | 34 +++++++++---------- .../Form/ChoiceList/ArrayChoiceList.php | 10 +++--- .../Factory/ChoiceListFactoryInterface.php | 6 ++-- .../Factory/PropertyAccessDecorator.php | 2 +- .../Data/Bundle/Writer/TextBundleWriter.php | 10 +++--- .../PropertyAccess/PropertyAccessor.php | 10 +++--- .../RecursiveContextualValidator.php | 2 +- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 8964f10789bec..a6e7c35d148fe 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -1015,8 +1015,8 @@ public function extractNamespace($name, $limit = null) * Finds alternative of $name among $collection, * if nothing is found in $collection, try in $abbrevs. * - * @param string $name The string - * @param array|\Traversable $collection The collection + * @param string $name The string + * @param iterable $collection The collection * * @return string[] A sorted array of similar string */ diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index bece3e59752ad..d94836b85b785 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -114,7 +114,7 @@ public function setHiddenFallback($fallback) /** * Gets values for the autocompleter. * - * @return null|array|\Traversable + * @return null|iterable */ public function getAutocompleterValues() { @@ -124,7 +124,7 @@ public function getAutocompleterValues() /** * Sets values for the autocompleter. * - * @param null|array|\Traversable $values + * @param null|iterable $values * * @return $this * diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 1c10366cee414..40371d9307cd2 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -83,8 +83,8 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false) /** * Creates a directory recursively. * - * @param string|array|\Traversable $dirs The directory path - * @param int $mode The directory mode + * @param string|iterable $dirs The directory path + * @param int $mode The directory mode * * @throws IOException On any directory creation failure */ @@ -111,7 +111,7 @@ public function mkdir($dirs, $mode = 0777) /** * Checks the existence of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to check * * @return bool true if the file exists, false otherwise */ @@ -135,9 +135,9 @@ public function exists($files) /** * Sets access and modification time of file. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create - * @param int $time The touch time as a Unix timestamp - * @param int $atime The access time as a Unix timestamp + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to create + * @param int $time The touch time as a Unix timestamp + * @param int $atime The access time as a Unix timestamp * * @throws IOException When touch fails */ @@ -154,7 +154,7 @@ public function touch($files, $time = null, $atime = null) /** * Removes files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove * * @throws IOException When removal fails */ @@ -190,10 +190,10 @@ public function remove($files) /** * Change mode for an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode - * @param int $mode The new mode (octal) - * @param int $umask The mode mask (octal) - * @param bool $recursive Whether change the mod recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change mode + * @param int $mode The new mode (octal) + * @param int $umask The mode mask (octal) + * @param bool $recursive Whether change the mod recursively or not * * @throws IOException When the change fail */ @@ -212,9 +212,9 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) /** * Change the owner of an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner - * @param string $user The new owner user name - * @param bool $recursive Whether change the owner recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner + * @param string $user The new owner user name + * @param bool $recursive Whether change the owner recursively or not * * @throws IOException When the change fail */ @@ -239,9 +239,9 @@ public function chown($files, $user, $recursive = false) /** * Change the group of an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group - * @param string $group The group name - * @param bool $recursive Whether change the group recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group + * @param string $group The group name + * @param bool $recursive Whether change the group recursively or not * * @throws IOException When the change fail */ diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index 676987e641216..418aa3200cc17 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -58,11 +58,11 @@ class ArrayChoiceList implements ChoiceListInterface * * The given choice array must have the same array keys as the value array. * - * @param array|\Traversable $choices The selectable choices - * @param callable|null $value The callable for creating the value - * for a choice. If `null` is passed, - * incrementing integers are used as - * values + * @param iterable $choices The selectable choices + * @param callable|null $value The callable for creating the value + * for a choice. If `null` is passed, + * incrementing integers are used as + * values */ public function __construct($choices, $value = null) { diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php index 7933dd91d48d7..c66ce0f028d37 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php @@ -31,9 +31,9 @@ interface ChoiceListFactoryInterface * The callable receives the choice as first and the array key as the second * argument. * - * @param array|\Traversable $choices The choices - * @param null|callable $value The callable generating the choice - * values + * @param iterable $choices The choices + * @param null|callable $value The callable generating the choice + * values * * @return ChoiceListInterface The choice list */ diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php index 82b2082f33e1f..42f7b916f6ed6 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php @@ -63,7 +63,7 @@ public function getDecoratedFactory() /** * {@inheritdoc} * - * @param array|\Traversable $choices The choices + * @param iterable $choices The choices * @param null|callable|string|PropertyPath $value The callable or path for * generating the choice values * diff --git a/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php b/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php index 3a444fd350edb..20fad5347aed2 100644 --- a/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php +++ b/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php @@ -195,11 +195,11 @@ private function writeArray($file, array $value, $indentation) /** * Writes a "table" node. * - * @param resource $file The file handle to write to - * @param array|\Traversable $value The value of the node - * @param int $indentation The number of levels to indent - * @param bool $fallback Whether the table should be merged - * with the fallback locale + * @param resource $file The file handle to write to + * @param iterable $value The value of the node + * @param int $indentation The number of levels to indent + * @param bool $fallback Whether the table should be merged + * with the fallback locale * * @throws UnexpectedTypeException when $value is not an array and not a * \Traversable instance diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 4ce814a538479..233a6fe2f3fe7 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -611,11 +611,11 @@ private function writeProperty($zval, $property, $value) /** * Adjusts a collection-valued property by calling add*() and remove*() methods. * - * @param array $zval The array containing the object to write to - * @param string $property The property to write - * @param array|\Traversable $collection The collection to write - * @param string $addMethod The add*() method - * @param string $removeMethod The remove*() method + * @param array $zval The array containing the object to write to + * @param string $property The property to write + * @param iterable $collection The collection to write + * @param string $addMethod The add*() method + * @param string $removeMethod The remove*() method */ private function writeCollection($zval, $property, $collection, $addMethod, $removeMethod) { diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index acb43283967ca..00c1c4d6e480a 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -378,7 +378,7 @@ private function validateObject($object, $propertyPath, array $groups, $traversa * objects are iterated as well. Nested arrays are always iterated, * regardless of the value of $recursive. * - * @param array|\Traversable $collection The collection + * @param iterable $collection The collection * @param string $propertyPath The current property path * @param string[] $groups The validated groups * @param bool $stopRecursion Whether to disable From ddffd6163f76b840b95deb155302617900888354 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 16 Nov 2017 17:24:08 +0100 Subject: [PATCH 03/74] updated CHANGELOG for 2.7.38 --- CHANGELOG-2.7.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 371e8c464e7a1..7ac65a77371f6 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,13 @@ in 2.7 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.7.0...v2.7.1 +* 2.7.38 (2017-11-16) + + * security #24995 Validate redirect targets using the session cookie domain (nicolas-grekas) + * security #24994 Prevent bundle readers from breaking out of paths (xabbuh) + * security #24993 Ensure that submitted data are uploaded files (xabbuh) + * security #24992 Namespace generated CSRF tokens depending of the current scheme (dunglas) + * 2.7.37 (2017-11-13) * bug #24952 [HttpFoundation] Fix session-related BC break (nicolas-grekas, sroze) From 330c5e5577c1b727d0c3175377184c17dc791510 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 16 Nov 2017 17:24:22 +0100 Subject: [PATCH 04/74] updated VERSION for 2.7.38 --- 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 f78633744e12f..b1ba60fd65ed1 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.38-DEV'; + const VERSION = '2.7.38'; const VERSION_ID = 20738; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; const RELEASE_VERSION = 38; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From b2febb46880ad3de0e2b5ceda7330a4099fc71e9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 16 Nov 2017 18:43:51 +0100 Subject: [PATCH 05/74] updated CHANGELOG for 2.8.31 --- CHANGELOG-2.8.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index fe42e8d13a52a..626c310af437f 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,13 @@ 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.31 (2017-11-16) + + * security #24995 Validate redirect targets using the session cookie domain (nicolas-grekas) + * security #24994 Prevent bundle readers from breaking out of paths (xabbuh) + * security #24993 Ensure that submitted data are uploaded files (xabbuh) + * security #24992 Namespace generated CSRF tokens depending of the current scheme (dunglas) + * 2.8.30 (2017-11-13) * bug #24952 [HttpFoundation] Fix session-related BC break (nicolas-grekas, sroze) From 762b8d85f31b3daad24e808a5c93ccea4c53f497 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 16 Nov 2017 18:43:55 +0100 Subject: [PATCH 06/74] updated VERSION for 2.8.31 --- 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 1aab5ee0da4a3..3e0993a126f05 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.31-DEV'; + const VERSION = '2.8.31'; const VERSION_ID = 20831; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 31; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From c963178206515c40968c01dcccdbd9ddbc250fe1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 17 Nov 2017 07:26:23 +0100 Subject: [PATCH 07/74] bumped Symfony version to 2.7.39 --- 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 b1ba60fd65ed1..466e01b172ecb 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.38'; - const VERSION_ID = 20738; + const VERSION = '2.7.39-DEV'; + const VERSION_ID = 20739; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 38; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 39; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 58352f2f0291df9c2f63a4bfd82a0056dbe85f0b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 17 Nov 2017 07:34:32 +0100 Subject: [PATCH 08/74] bumped Symfony version to 2.8.32 --- 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 3e0993a126f05..0bfec287a98b3 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.31'; - const VERSION_ID = 20831; + const VERSION = '2.8.32-DEV'; + const VERSION_ID = 20832; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 31; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 32; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 3b6c22e86a2a5f9bef247f6697eb99e9fb2b07c3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 17 Nov 2017 07:39:26 +0100 Subject: [PATCH 09/74] bumped Symfony version to 3.3.14 --- 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 c5aa20930fc3f..711f410e0d654 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -61,12 +61,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface private $projectDir; - const VERSION = '3.3.13'; - const VERSION_ID = 30313; + const VERSION = '3.3.14-DEV'; + const VERSION_ID = 30314; const MAJOR_VERSION = 3; const MINOR_VERSION = 3; - const RELEASE_VERSION = 13; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 14; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2018'; const END_OF_LIFE = '07/2018'; From 3822c07f65c33295d40cac129d4b0d213463bb37 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 17 Nov 2017 13:59:02 +0100 Subject: [PATCH 10/74] [Console] Remove remaining dead code --- src/Symfony/Component/Console/Application.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 8964f10789bec..84f2cca7c34fc 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -113,11 +113,10 @@ public function run(InputInterface $input = null, OutputInterface $output = null $e = null; $exitCode = $this->doRun($input, $output); } catch (\Exception $e) { - } catch (\Throwable $e) { } if (null !== $e) { - if (!$this->catchExceptions || !$e instanceof \Exception) { + if (!$this->catchExceptions) { throw $e; } From 20f9b758574718d52106014a519a1832ebcb6304 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 17 Nov 2017 15:26:00 +0100 Subject: [PATCH 11/74] [SecurityBundle] Fix syntax error in test --- .../Compiler/AddSessionDomainConstraintPassTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php index f476b5ef7313e..7d49ad3dd4ec6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php @@ -124,7 +124,8 @@ private function createContainer($sessionStorageOptions) $ext = new SecurityExtension(); $ext->load($config, $container); - (new AddSessionDomainConstraintPass())->process($container); + $pass = new AddSessionDomainConstraintPass(); + $pass->process($container); return $container; } From 1f8db731a0dd6ba464f04c0cde2752a8f4be4102 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Wed, 15 Nov 2017 16:25:33 +0100 Subject: [PATCH 12/74] [Console] Fix global console flag when used in chain --- src/Symfony/Component/Console/Input/ArgvInput.php | 8 ++++++++ .../Component/Console/Tests/Input/ArgvInputTest.php | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index c2f533eb36798..4493a5bafc3b9 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -282,6 +282,14 @@ public function hasParameterOption($values) if ($token === $value || 0 === strpos($token, $value.'=')) { return true; } + + if (0 === strpos($token, '-') && 0 !== strpos($token, '--')) { + $searchableToken = str_replace('-', '', $token); + $searchableValue = str_replace('-', '', $value); + if ('' !== $searchableToken && '' !== $searchableValue && false !== strpos($searchableToken, $searchableValue)) { + return true; + } + } } } diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index 1fe21d0f6c1a8..85fb533715b62 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -296,6 +296,9 @@ public function testHasParameterOption() $input = new ArgvInput(array('cli.php', '-f', 'foo')); $this->assertTrue($input->hasParameterOption('-f'), '->hasParameterOption() returns true if the given short option is in the raw input'); + $input = new ArgvInput(array('cli.php', '-fh')); + $this->assertTrue($input->hasParameterOption('-fh'), '->hasParameterOption() returns true if the given short option is in the raw input'); + $input = new ArgvInput(array('cli.php', '--foo', 'foo')); $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input'); From 0577d20ade7d6191c68174c8a3fe68d84072e442 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Nov 2017 14:29:22 +0200 Subject: [PATCH 13/74] [Bridge\PhpUnit] Disable broken auto-require mechanism of phpunit --- src/Symfony/Bridge/PhpUnit/Blacklist.php | 41 +++++++++++++++++++ .../Legacy/SymfonyTestsListenerTrait.php | 18 ++------ src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 14 ------- src/Symfony/Bridge/PhpUnit/bootstrap.php | 3 ++ 4 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 src/Symfony/Bridge/PhpUnit/Blacklist.php diff --git a/src/Symfony/Bridge/PhpUnit/Blacklist.php b/src/Symfony/Bridge/PhpUnit/Blacklist.php new file mode 100644 index 0000000000000..09ff256decc1a --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Blacklist.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit; + +/** + * Utility class replacing PHPUnit's implementation of the same class. + * + * All files are blacklisted so that process-isolated tests don't start with broken + * "require_once" statements. Composer is the only supported way to load code there. + */ +class Blacklist +{ + public static $blacklistedClassNames = array(); + + public function getBlacklistedDirectories() + { + $root = dirname(__DIR__); + while ($root !== $parent = dirname($root)) { + $root = $parent; + } + + return array($root); + } + + public function isBlacklisted($file) + { + return true; + } +} + +class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit\Util\Blacklist'); +class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit_Util_Blacklist'); diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index b114c69c5176c..498919c09991b 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -15,7 +15,6 @@ use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; -use PHPUnit\Util\Blacklist; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Bridge\PhpUnit\DnsMock; @@ -46,17 +45,6 @@ class SymfonyTestsListenerTrait */ public function __construct(array $mockedNamespaces = array()) { - if (class_exists('PHPUnit_Util_Blacklist')) { - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\DeprecationErrorHandler'] = 1; - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener'] = 1; - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 1; - } else { - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\DeprecationErrorHandler'] = 1; - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 1; - } - $warn = false; foreach ($mockedNamespaces as $type => $namespaces) { if (!is_array($namespaces)) { @@ -103,7 +91,7 @@ public function globalListenerDisabled() public function startTestSuite($suite) { - if (class_exists('PHPUnit_Util_Blacklist', false)) { + if (class_exists('PHPUnit_Util_Test', false)) { $Test = 'PHPUnit_Util_Test'; } else { $Test = 'PHPUnit\Util\Test'; @@ -190,7 +178,7 @@ public function startTest($test) putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); } - if (class_exists('PHPUnit_Util_Blacklist', false)) { + if (class_exists('PHPUnit_Util_Test', false)) { $Test = 'PHPUnit_Util_Test'; $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; } else { @@ -236,7 +224,7 @@ public function addWarning($test, $e, $time) public function endTest($test, $time) { - if (class_exists('PHPUnit_Util_Blacklist', false)) { + if (class_exists('PHPUnit_Util_Test', false)) { $Test = 'PHPUnit_Util_Test'; $BaseTestRunner = 'PHPUnit_Runner_BaseTestRunner'; $Warning = 'PHPUnit_Framework_Warning'; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index ac358dd4bed8e..728ab1913dfe8 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -82,17 +82,6 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ define('PHPUNIT_COMPOSER_INSTALL', __DIR__.'/vendor/autoload.php'); require PHPUNIT_COMPOSER_INSTALL; -if (!class_exists('SymfonyBlacklistPhpunit', false)) { - class SymfonyBlacklistPhpunit {} -} -if (class_exists('PHPUnit_Util_Blacklist')) { - PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; - PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; -} else { - PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; - PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; -} - Symfony\Bridge\PhpUnit\TextUI\Command::main(); EOPHP @@ -211,9 +200,6 @@ if ($components) { } } } elseif (!isset($argv[1]) || 'install' !== $argv[1] || file_exists('install')) { - if (!class_exists('SymfonyBlacklistSimplePhpunit', false)) { - class SymfonyBlacklistSimplePhpunit {} - } array_splice($argv, 1, 0, array('--colors=always')); $_SERVER['argv'] = $argv; $_SERVER['argc'] = ++$argc; diff --git a/src/Symfony/Bridge/PhpUnit/bootstrap.php b/src/Symfony/Bridge/PhpUnit/bootstrap.php index a265a129e6fdc..1197ab050b0ba 100644 --- a/src/Symfony/Bridge/PhpUnit/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/bootstrap.php @@ -12,6 +12,9 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler; +// Replace the native phpunit Blacklist, it's a broken artifact from the past +require_once __DIR__.'/Blacklist.php'; + // Detect if we need to serialize deprecations to a file. if ($file = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) { DeprecationErrorHandler::collectDeprecations($file); From a5122174312fb9e3ea6c5fc6c20667d55e5a0516 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Nov 2017 20:49:57 +0200 Subject: [PATCH 14/74] Remove function_exists(__phpunit_run_isolated_test) checks --- src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php | 4 +--- .../Component/Routing/Tests/Fixtures/validresource.php | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php index d338ca9d5752b..21e0aba17d358 100644 --- a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php +++ b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php @@ -1,5 +1,3 @@ import('validpattern.php'); From 0187e9b3400e55b978901483ad71f40dc48c70ed Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Nov 2017 21:42:16 +0200 Subject: [PATCH 15/74] [Bridge/PhpUnit] Fix compat with phpunit 4.8 & bridge <=3.3.13 --- composer.json | 2 +- src/Symfony/Bridge/PhpUnit/Blacklist.php | 23 ++++++++++++++----- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 2 +- src/Symfony/Bridge/PhpUnit/bootstrap.php | 4 +++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 1c8a7027bcaba..202e141f36c28 100644 --- a/composer.json +++ b/composer.json @@ -97,7 +97,7 @@ "ocramius/proxy-manager": "~0.4|~1.0|~2.0", "predis/predis": "~1.0", "egulias/email-validator": "~1.2,>=1.2.8|~2.0", - "symfony/phpunit-bridge": "~3.2", + "symfony/phpunit-bridge": "~3.4|~4.0", "symfony/security-acl": "~2.8|~3.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0", "sensio/framework-extra-bundle": "^3.0.2" diff --git a/src/Symfony/Bridge/PhpUnit/Blacklist.php b/src/Symfony/Bridge/PhpUnit/Blacklist.php index 09ff256decc1a..abfd3172580ba 100644 --- a/src/Symfony/Bridge/PhpUnit/Blacklist.php +++ b/src/Symfony/Bridge/PhpUnit/Blacklist.php @@ -23,12 +23,19 @@ class Blacklist public function getBlacklistedDirectories() { - $root = dirname(__DIR__); - while ($root !== $parent = dirname($root)) { - $root = $parent; + $blacklist = array(); + + foreach (get_declared_classes() as $class) { + if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $v = dirname(dirname($r->getFileName())); + if (file_exists($v.'/composer/installed.json')) { + $blacklist[] = $v; + } + } } - return array($root); + return $blacklist; } public function isBlacklisted($file) @@ -37,5 +44,9 @@ public function isBlacklisted($file) } } -class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit\Util\Blacklist'); -class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit_Util_Blacklist'); +if (class_exists('PHPUnit\Util\Test')) { + class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit\Util\Blacklist'); +} +if (class_exists('PHPUnit_Util_Test')) { + class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit_Util_Blacklist'); +} diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 728ab1913dfe8..f7e34e048b954 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -68,7 +68,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); } - passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"~3.3.11@dev|~3.4.0-beta2@dev|^4.0.0-beta2@dev\""); + passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"~3.4-beta5@dev|^4.0-beta5@dev\""); $prevRoot = getenv('COMPOSER_ROOT_VERSION'); putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); $exit = proc_close(proc_open("$COMPOSER install --no-dev --prefer-dist --no-progress --ansi", array(), $p, getcwd(), null, array('bypass_shell' => true))); diff --git a/src/Symfony/Bridge/PhpUnit/bootstrap.php b/src/Symfony/Bridge/PhpUnit/bootstrap.php index 1197ab050b0ba..8e85feaa34269 100644 --- a/src/Symfony/Bridge/PhpUnit/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/bootstrap.php @@ -13,7 +13,9 @@ use Symfony\Bridge\PhpUnit\DeprecationErrorHandler; // Replace the native phpunit Blacklist, it's a broken artifact from the past -require_once __DIR__.'/Blacklist.php'; +if (!class_exists('Symfony\Bridge\PhpUnit\Blacklist', false)) { + require_once __DIR__.'/Blacklist.php'; +} // Detect if we need to serialize deprecations to a file. if ($file = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) { From 675a3fe7f616ceda079f90c96c8da692bf698fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Strzelecki?= Date: Thu, 24 Jul 2014 10:48:45 +0200 Subject: [PATCH 16/74] added ability for substitute aliases when mapping in YAML is on single line --- src/Symfony/Component/Yaml/Parser.php | 55 ++++++++++++++++++- .../Yaml/Tests/Fixtures/sfMergeKey.yml | 8 ++- .../Component/Yaml/Tests/ParserTest.php | 12 ++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 8ffa8ccf64940..93b2fca4d71b9 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -491,6 +491,59 @@ private function moveToPreviousLine() return true; } + /** + * Substitute from alias where is used a << + * + * @param mixed $values Parsed YAML in which aliases are not substituted + * + * @return mixed YAML with substituted aliases + * + * @throws Exception\ParseException When indentation problem are detected + */ + private function substituteAliases($values) + { + if (is_array($values)) { + $keys = array(); + foreach ($values as $key => $value) { + if ($key ==='<<' && preg_grep('/^\*.+/', (array) $value) === array_values((array) $value)) { + $values[$key] = array(); + foreach ((array) $value as $ref) { + $refName = substr($ref, 1); + if (!array_key_exists($refName, $this->refs)) { + throw new ParseException( + sprintf('Reference "%s" does not exist.', $refName), + $this->getRealCurrentLineNb() + 1, + $this->currentLine + ); + } + + $keys = array_merge( + $keys, + array_diff(array_keys($this->refs[$refName]), $keys) + ); + $values[$key] = array_replace($this->refs[$refName], $values[$key]); + } + } elseif (!isset($result[$key]) || is_array($result[$key])) { + $keys[] = $key; + $values[$key] = $this->substituteAliases($value); + } + } + + if (isset($values['<<'])) { + $values = array_replace($values['<<'], $values); + unset($values['<<']); + uksort( + $values, + function ($a, $b) use ($keys) { + return array_search($a, $keys, true) - array_search($b, $keys, true); + } + ); + } + } + + return $values; + } + /** * Parses a YAML value. * @@ -526,7 +579,7 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob } try { - return Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs); + return $this->substituteAliases(Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs)); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml index 59f612514170a..a37eca2e3cd73 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml @@ -22,6 +22,7 @@ yaml: | foo: bar foo: ignore bar: foo + bar_inline: {a: before, d: other, <<: *foo, b: new, x: Oren, c: { foo: bar, foo: ignore, bar: foo}} duplicate: foo: bar foo: ignore @@ -46,15 +47,20 @@ yaml: | p: 12345 z: <<: *nestedref + head_inline: &head_inline { <<: [ *foo , *dong , *foo2 ] } + recursive_inline: { <<: *head_inline, c: { <<: *foo2 } } php: | array( 'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'), 'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), + 'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), 'duplicate' => array('foo' => 'bar'), 'foo2' => array('a' => 'Ballmer'), 'ding' => array('fi', 'fei', 'fo', 'fam'), 'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'), 'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), 'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)), - 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)) + 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)), + 'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam'), + 'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'fi', 'fei', 'fo', 'fam') ) diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 9be278f67ec92..97ce0cac0f770 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1207,6 +1207,18 @@ public function testParseReferencesOnMergeKeys() $this->assertSame($expected, $this->parser->parse($yaml)); } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessage Reference "foo" does not exist + */ + public function testEvalRefException() + { + $yaml = <<parser->parse($yaml); + } } class B From dd26c80aa95c32af0ddbf195b2bab1cd29c74b7b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 20 Nov 2017 08:47:12 +0100 Subject: [PATCH 17/74] substitute aliases in inline mappings --- src/Symfony/Component/Yaml/Inline.php | 22 +++++++- src/Symfony/Component/Yaml/Parser.php | 55 +------------------ .../Yaml/Tests/Fixtures/sfMergeKey.yml | 6 +- 3 files changed, 23 insertions(+), 60 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 9ff9b89c1c123..31a0514fd4972 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -365,6 +365,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) $output = array(); $len = strlen($mapping); ++$i; + $allowOverwrite = false; // {foo: bar, bar:foo, ...} while ($i < $len) { @@ -384,6 +385,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // key $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + if ('<<' === $key) { + $allowOverwrite = true; + } + // value $done = false; @@ -395,7 +400,12 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + foreach ($value as $parsedValue) { + $output += $parsedValue; + } + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; @@ -406,7 +416,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + $output += $value; + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; @@ -419,7 +432,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + $output += $value; + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 93b2fca4d71b9..8ffa8ccf64940 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -491,59 +491,6 @@ private function moveToPreviousLine() return true; } - /** - * Substitute from alias where is used a << - * - * @param mixed $values Parsed YAML in which aliases are not substituted - * - * @return mixed YAML with substituted aliases - * - * @throws Exception\ParseException When indentation problem are detected - */ - private function substituteAliases($values) - { - if (is_array($values)) { - $keys = array(); - foreach ($values as $key => $value) { - if ($key ==='<<' && preg_grep('/^\*.+/', (array) $value) === array_values((array) $value)) { - $values[$key] = array(); - foreach ((array) $value as $ref) { - $refName = substr($ref, 1); - if (!array_key_exists($refName, $this->refs)) { - throw new ParseException( - sprintf('Reference "%s" does not exist.', $refName), - $this->getRealCurrentLineNb() + 1, - $this->currentLine - ); - } - - $keys = array_merge( - $keys, - array_diff(array_keys($this->refs[$refName]), $keys) - ); - $values[$key] = array_replace($this->refs[$refName], $values[$key]); - } - } elseif (!isset($result[$key]) || is_array($result[$key])) { - $keys[] = $key; - $values[$key] = $this->substituteAliases($value); - } - } - - if (isset($values['<<'])) { - $values = array_replace($values['<<'], $values); - unset($values['<<']); - uksort( - $values, - function ($a, $b) use ($keys) { - return array_search($a, $keys, true) - array_search($b, $keys, true); - } - ); - } - } - - return $values; - } - /** * Parses a YAML value. * @@ -579,7 +526,7 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob } try { - return $this->substituteAliases(Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs)); + return Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml index a37eca2e3cd73..499446c10cb76 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml @@ -53,7 +53,7 @@ php: | array( 'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'), 'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), - 'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), + 'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'e' => 'notnull', 'x' => 'Oren'), 'duplicate' => array('foo' => 'bar'), 'foo2' => array('a' => 'Ballmer'), 'ding' => array('fi', 'fei', 'fo', 'fam'), @@ -61,6 +61,6 @@ php: | 'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), 'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)), 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)), - 'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam'), - 'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'fi', 'fei', 'fo', 'fam') + 'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), + 'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), ) From b746e8a0172857486db33b8f0d5b91de35b6c797 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Sun, 19 Nov 2017 13:41:04 +0200 Subject: [PATCH 18/74] [HttpKernel] add a test for FilterControllerEvents --- .../FilterControllerArgumentsEventTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Symfony/Component/HttpKernel/Tests/Event/FilterControllerArgumentsEventTest.php diff --git a/src/Symfony/Component/HttpKernel/Tests/Event/FilterControllerArgumentsEventTest.php b/src/Symfony/Component/HttpKernel/Tests/Event/FilterControllerArgumentsEventTest.php new file mode 100644 index 0000000000000..9165d31f24a15 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Event/FilterControllerArgumentsEventTest.php @@ -0,0 +1,17 @@ +assertEquals($filterController->getArguments(), array('test')); + } +} From faf5470fd5498b9ae4d1faf83bd0266ba7ccfcdb Mon Sep 17 00:00:00 2001 From: "Issei.M" Date: Mon, 20 Nov 2017 13:43:41 +0900 Subject: [PATCH 19/74] [Form] Add phpdoc to `RequestHandlerInterface::isFileUpload()` method --- .../Extension/HttpFoundation/HttpFoundationRequestHandler.php | 3 +++ src/Symfony/Component/Form/NativeRequestHandler.php | 3 +++ src/Symfony/Component/Form/RequestHandlerInterface.php | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 368a5a80a1481..571db0eb41dfc 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -108,6 +108,9 @@ public function handleRequest(FormInterface $form, $request = null) $form->submit($data, 'PATCH' !== $method); } + /** + * {@inheritdoc} + */ public function isFileUpload($data) { return $data instanceof File; diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index f68efe25cfe54..37e1c99a74505 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -118,6 +118,9 @@ public function handleRequest(FormInterface $form, $request = null) $form->submit($data, 'PATCH' !== $method); } + /** + * {@inheritdoc} + */ public function isFileUpload($data) { // POST data will always be strings or arrays of strings. Thus, we can be sure diff --git a/src/Symfony/Component/Form/RequestHandlerInterface.php b/src/Symfony/Component/Form/RequestHandlerInterface.php index e6360e449889f..3d7b45d5064af 100644 --- a/src/Symfony/Component/Form/RequestHandlerInterface.php +++ b/src/Symfony/Component/Form/RequestHandlerInterface.php @@ -27,7 +27,9 @@ interface RequestHandlerInterface public function handleRequest(FormInterface $form, $request = null); /** - * @param mixed $data + * Returns true if the given data is a file upload. + * + * @param mixed $data The form field data * * @return bool */ From 381f5d1bc57c0c51110082e63f255b1bf9607d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 27 Oct 2017 17:09:21 +0200 Subject: [PATCH 20/74] Add a "link" script to ease debugging Flex apps --- link | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 link diff --git a/link b/link new file mode 100755 index 0000000000000..f4070998e72b5 --- /dev/null +++ b/link @@ -0,0 +1,59 @@ +#!/usr/bin/env php + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/IOException.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Filesystem.php'; + +use Symfony\Component\Filesystem\Filesystem; + +/** + * Links dependencies to components to a local clone of the main symfony/symfony GitHub repository. + * + * @author Kévin Dunglas + */ + +if (2 !== $argc) { + echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; + echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; + exit(1); +} + +if (!is_dir("$argv[1]/vendor/symfony")) { + echo "The directory \"$argv[1]\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; + exit(1); +} + +$sfPackages = array('symfony/symfony' => __DIR__); +foreach (glob(__DIR__.'/src/Symfony/{Bundle,Bridge,Component,Component/Security}/*', GLOB_BRACE | GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { + $sfPackages[json_decode(file_get_contents("$dir/composer.json"))->name] = $dir; +} + +$filesystem = new Filesystem(); +foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { + $package = 'symfony/'.basename($dir); + if (is_link($dir)) { + echo "\"$package\" is already a symlink, skipping.".PHP_EOL; + continue; + } + + if (!isset($sfPackages[$package])) { + continue; + } + + $sfDir = '\\' === DIRECTORY_SEPARATOR ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir))); + + $filesystem->remove($dir); + $filesystem->symlink($sfDir, $dir); + echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; +} From a35d4f88b34fca0883fc904838f85447c0ff788a Mon Sep 17 00:00:00 2001 From: "Issei.M" Date: Mon, 20 Nov 2017 15:44:43 +0900 Subject: [PATCH 21/74] [Form] Rename `FormConfigBuilder::$nativeRequestProcessor` private variable to `::$nativeRequestHandler` --- src/Symfony/Component/Form/FormConfigBuilder.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index f51881a092c97..243ef89f312cf 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -32,7 +32,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface * * @var NativeRequestHandler */ - private static $nativeRequestProcessor; + private static $nativeRequestHandler; /** * The accepted request methods. @@ -511,10 +511,10 @@ public function getMethod() public function getRequestHandler() { if (null === $this->requestHandler) { - if (null === self::$nativeRequestProcessor) { - self::$nativeRequestProcessor = new NativeRequestHandler(); + if (null === self::$nativeRequestHandler) { + self::$nativeRequestHandler = new NativeRequestHandler(); } - $this->requestHandler = self::$nativeRequestProcessor; + $this->requestHandler = self::$nativeRequestHandler; } return $this->requestHandler; From 5ddb121723daa61766da38598d1b407753355f8a Mon Sep 17 00:00:00 2001 From: Guillaume Aveline <917449+joky@users.noreply.github.com> Date: Tue, 21 Nov 2017 09:21:36 +0100 Subject: [PATCH 22/74] [Bridge/PhpUnit] Remove trailing "\n" from ClockMock::microtime(false) --- src/Symfony/Bridge/PhpUnit/ClockMock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/ClockMock.php b/src/Symfony/Bridge/PhpUnit/ClockMock.php index fe5cd851258d2..8bfb9a6211186 100644 --- a/src/Symfony/Bridge/PhpUnit/ClockMock.php +++ b/src/Symfony/Bridge/PhpUnit/ClockMock.php @@ -66,7 +66,7 @@ public static function microtime($asFloat = false) return self::$now; } - return sprintf("%0.6f %d\n", self::$now - (int) self::$now, (int) self::$now); + return sprintf('%0.6f %d', self::$now - (int) self::$now, (int) self::$now); } public static function register($class) From 1c1a540d2f18ed173789df4f659ddbf419163774 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Nov 2017 20:31:57 +0100 Subject: [PATCH 23/74] Bump phpunit-bridge requirement to 3.4|4.0 --- composer.json | 2 +- phpunit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f067b4bbe20b2..f263c15d45324 100644 --- a/composer.json +++ b/composer.json @@ -80,7 +80,7 @@ "monolog/monolog": "~1.11", "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "symfony/phpunit-bridge": "~3.2", + "symfony/phpunit-bridge": "~3.4|~4.0", "egulias/email-validator": "~1.2,>=1.2.1", "sensio/framework-extra-bundle": "^3.0.2" }, diff --git a/phpunit b/phpunit index 53e1a8dc31dbf..86f4cdd5ae0a2 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php Date: Tue, 21 Nov 2017 10:41:52 +0100 Subject: [PATCH 24/74] [HttpFoundation] Fix bad merge in NativeSessionStorage --- .../HttpFoundation/Session/Storage/NativeSessionStorage.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index 6f60a5c762f7d..f03cdf343024d 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -108,7 +108,11 @@ public function __construct(array $options = array(), $handler = null, MetadataB 'use_cookies' => 1, ); - session_register_shutdown(); + if (\PHP_VERSION_ID >= 50400) { + session_register_shutdown(); + } else { + register_shutdown_function('session_write_close'); + } $this->setMetadataBag($metaBag); $this->setOptions($options); From e233ba3a3f531cb9498882e0de0020f81e8d9ae3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Nov 2017 08:42:46 +0100 Subject: [PATCH 25/74] [Bridge\PhpUnit] Turn "preserveGlobalState" to false by default, revert "Blacklist" removal This reverts commit 0577d20ade7d6191c68174c8a3fe68d84072e442. --- src/Symfony/Bridge/PhpUnit/Blacklist.php | 52 ------------------- .../Legacy/SymfonyTestsListenerTrait.php | 21 ++++++-- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 14 +++++ src/Symfony/Bridge/PhpUnit/bootstrap.php | 5 -- 4 files changed, 32 insertions(+), 60 deletions(-) delete mode 100644 src/Symfony/Bridge/PhpUnit/Blacklist.php diff --git a/src/Symfony/Bridge/PhpUnit/Blacklist.php b/src/Symfony/Bridge/PhpUnit/Blacklist.php deleted file mode 100644 index abfd3172580ba..0000000000000 --- a/src/Symfony/Bridge/PhpUnit/Blacklist.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit; - -/** - * Utility class replacing PHPUnit's implementation of the same class. - * - * All files are blacklisted so that process-isolated tests don't start with broken - * "require_once" statements. Composer is the only supported way to load code there. - */ -class Blacklist -{ - public static $blacklistedClassNames = array(); - - public function getBlacklistedDirectories() - { - $blacklist = array(); - - foreach (get_declared_classes() as $class) { - if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { - $r = new \ReflectionClass($class); - $v = dirname(dirname($r->getFileName())); - if (file_exists($v.'/composer/installed.json')) { - $blacklist[] = $v; - } - } - } - - return $blacklist; - } - - public function isBlacklisted($file) - { - return true; - } -} - -if (class_exists('PHPUnit\Util\Test')) { - class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit\Util\Blacklist'); -} -if (class_exists('PHPUnit_Util_Test')) { - class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit_Util_Blacklist'); -} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 498919c09991b..5bc4a29a7e25e 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; +use PHPUnit\Util\Blacklist; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Bridge\PhpUnit\DnsMock; @@ -45,6 +46,14 @@ class SymfonyTestsListenerTrait */ public function __construct(array $mockedNamespaces = array()) { + if (class_exists('PHPUnit_Util_Blacklist')) { + \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; + \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener'] = 1; + } else { + Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; + Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener'] = 1; + } + $warn = false; foreach ($mockedNamespaces as $type => $namespaces) { if (!is_array($namespaces)) { @@ -91,7 +100,7 @@ public function globalListenerDisabled() public function startTestSuite($suite) { - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; } else { $Test = 'PHPUnit\Util\Test'; @@ -134,6 +143,10 @@ public function startTestSuite($suite) if (in_array('dns-sensitive', $groups, true)) { DnsMock::register($test->getName()); } + } elseif (!($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { + // no-op + } elseif (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { + $test->setPreserveGlobalState(false); } } } @@ -144,6 +157,8 @@ public function startTestSuite($suite) || isset($this->wasSkipped[$suiteName]['*']) || isset($this->wasSkipped[$suiteName][$test->getName()])) { $skipped[] = $test; + } elseif (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { + $test->setPreserveGlobalState(false); } } $suite->setTests($skipped); @@ -178,7 +193,7 @@ public function startTest($test) putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); } - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; } else { @@ -224,7 +239,7 @@ public function addWarning($test, $e, $time) public function endTest($test, $time) { - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $BaseTestRunner = 'PHPUnit_Runner_BaseTestRunner'; $Warning = 'PHPUnit_Framework_Warning'; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index f7e34e048b954..889642636cdca 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -82,6 +82,17 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ define('PHPUNIT_COMPOSER_INSTALL', __DIR__.'/vendor/autoload.php'); require PHPUNIT_COMPOSER_INSTALL; +if (!class_exists('SymfonyBlacklistPhpunit', false)) { + class SymfonyBlacklistPhpunit {} +} +if (class_exists('PHPUnit_Util_Blacklist')) { + PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; + PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; +} else { + PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; + PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; +} + Symfony\Bridge\PhpUnit\TextUI\Command::main(); EOPHP @@ -200,6 +211,9 @@ if ($components) { } } } elseif (!isset($argv[1]) || 'install' !== $argv[1] || file_exists('install')) { + if (!class_exists('SymfonyBlacklistSimplePhpunit', false)) { + class SymfonyBlacklistSimplePhpunit {} + } array_splice($argv, 1, 0, array('--colors=always')); $_SERVER['argv'] = $argv; $_SERVER['argc'] = ++$argc; diff --git a/src/Symfony/Bridge/PhpUnit/bootstrap.php b/src/Symfony/Bridge/PhpUnit/bootstrap.php index 8e85feaa34269..a265a129e6fdc 100644 --- a/src/Symfony/Bridge/PhpUnit/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/bootstrap.php @@ -12,11 +12,6 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler; -// Replace the native phpunit Blacklist, it's a broken artifact from the past -if (!class_exists('Symfony\Bridge\PhpUnit\Blacklist', false)) { - require_once __DIR__.'/Blacklist.php'; -} - // Detect if we need to serialize deprecations to a file. if ($file = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) { DeprecationErrorHandler::collectDeprecations($file); From 4f63b3ac28d9d4f20c9eba9d042ac872ff241ebf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 Nov 2017 18:42:30 +0100 Subject: [PATCH 26/74] Update github PR template --- .github/PULL_REQUEST_TEMPLATE.md | 3 +-- phpunit | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3af6c2a83bc18..e51cf88761451 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | master / 2.7, 2.8, 3.3, or 3.4 +| Branch? | master for features / 2.7 up to 4.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no @@ -14,6 +14,5 @@ - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. -- Please fill in this template according to the PR you're about to submit. - Replace this comment by a description of what your PR is solving. --> diff --git a/phpunit b/phpunit index 86f4cdd5ae0a2..b6783d0ba5d41 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php Date: Wed, 22 Nov 2017 09:54:48 +0100 Subject: [PATCH 27/74] Force phpunit-bridge update --- phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit b/phpunit index b6783d0ba5d41..cb572db266937 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php Date: Wed, 22 Nov 2017 09:52:58 +0100 Subject: [PATCH 28/74] [Bridge/PhpUnit] Fix blacklist --- .../Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php | 6 ++---- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 5bc4a29a7e25e..9d662d0d8ab37 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -47,11 +47,9 @@ class SymfonyTestsListenerTrait public function __construct(array $mockedNamespaces = array()) { if (class_exists('PHPUnit_Util_Blacklist')) { - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener'] = 1; + \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; } else { - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener'] = 1; + Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; } $warn = false; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 889642636cdca..5843192b3c13d 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -11,7 +11,7 @@ */ // Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2016-10-20 14:00 UTC +// Cache-Id-Version: 2017-11-22 09:00 UTC error_reporting(-1); From fe328345d794532bd0cd173bc2fe8d3cdc39dd89 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Nov 2017 10:23:05 +0100 Subject: [PATCH 29/74] [Bridge/PhpUnit] Fix disabling global state preservation --- .../PhpUnit/Legacy/SymfonyTestsListenerTrait.php | 15 +++++++++------ src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 9d662d0d8ab37..655687575d241 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -106,6 +106,15 @@ public function startTestSuite($suite) $suiteName = $suite->getName(); $this->testsWithWarnings = array(); + foreach ($suite->tests() as $test) { + if (!($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { + continue; + } + if (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { + $test->setPreserveGlobalState(false); + } + } + if (-1 === $this->state) { echo "Testing $suiteName\n"; $this->state = 0; @@ -141,10 +150,6 @@ public function startTestSuite($suite) if (in_array('dns-sensitive', $groups, true)) { DnsMock::register($test->getName()); } - } elseif (!($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { - // no-op - } elseif (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { - $test->setPreserveGlobalState(false); } } } @@ -155,8 +160,6 @@ public function startTestSuite($suite) || isset($this->wasSkipped[$suiteName]['*']) || isset($this->wasSkipped[$suiteName][$test->getName()])) { $skipped[] = $test; - } elseif (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { - $test->setPreserveGlobalState(false); } } $suite->setTests($skipped); diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 5843192b3c13d..b30eaa14538dc 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -11,7 +11,7 @@ */ // Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2017-11-22 09:00 UTC +// Cache-Id-Version: 2017-11-22 09:30 UTC error_reporting(-1); From 9d68751431ad72b064f9c16a8a48d397698adcd4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Nov 2017 10:25:38 +0100 Subject: [PATCH 30/74] Force phpunit-bridge update (bis) --- phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit b/phpunit index cb572db266937..c0ffe8ddef9e9 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php Date: Wed, 22 Nov 2017 00:40:17 +0100 Subject: [PATCH 31/74] Display a nice error message if the form/serializer component is missing. --- .../DependencyInjection/FrameworkExtension.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 2617163523a4c..cb0a53d5d6072 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -171,6 +171,10 @@ public function load(array $configs, ContainerBuilder $container) } if ($this->isConfigEnabled($container, $config['form'])) { + if (!class_exists('Symfony\Component\Form\Form')) { + throw new LogicException('Form support cannot be enabled as the Form component is not installed.'); + } + $this->formConfigEnabled = true; $this->registerFormConfiguration($config, $container, $loader); $config['validation']['enabled'] = true; @@ -216,6 +220,10 @@ public function load(array $configs, ContainerBuilder $container) $this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader); if ($this->isConfigEnabled($container, $config['serializer'])) { + if (!class_exists('Symfony\Component\Serializer\Serializer')) { + throw new LogicException('Serializer support cannot be enabled as the Serializer component is not installed.'); + } + $this->registerSerializerConfiguration($config['serializer'], $container, $loader); } From c9c18ac7f317e269e82b2289169287142321c436 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 23 Nov 2017 09:59:26 +0100 Subject: [PATCH 32/74] [DI] Fix handling of inlined definitions by ContainerBuilder --- .../DependencyInjection/ContainerBuilder.php | 50 ++++++++++++------- .../Tests/ContainerBuilderTest.php | 22 ++++++++ .../Tests/Fixtures/includes/classes.php | 2 +- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 65ea1c842c04f..59f8cc7d0dcb9 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -441,7 +441,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV $this->loading[$id] = true; try { - $service = $this->createService($definition, $id); + $service = $this->createService($definition, new \SplObjectStorage(), $id); } catch (\Exception $e) { unset($this->loading[$id]); @@ -827,8 +827,12 @@ public function findDefinition($id) * * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code */ - public function createService(Definition $definition, $id, $tryProxy = true) + public function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true) { + if (null === $id && isset($inlinedDefinitions[$definition])) { + return $inlinedDefinitions[$definition]; + } + if ($definition instanceof DefinitionDecorator) { throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id)); } @@ -845,11 +849,11 @@ public function createService(Definition $definition, $id, $tryProxy = true) ->instantiateProxy( $container, $definition, - $id, function () use ($definition, $id, $container) { - return $container->createService($definition, $id, false); + $id, function () use ($definition, $inlinedDefinitions, $id, $container) { + return $container->createService($definition, $inlinedDefinitions, $id, false); } ); - $this->shareService($definition, $proxy, $id); + $this->shareService($definition, $proxy, $id, $inlinedDefinitions); return $proxy; } @@ -860,11 +864,11 @@ public function createService(Definition $definition, $id, $tryProxy = true) require_once $parameterBag->resolveValue($definition->getFile()); } - $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))); + $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions); if (null !== $factory = $definition->getFactory()) { if (is_array($factory)) { - $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]); + $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]); } elseif (!is_string($factory)) { throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); } @@ -888,16 +892,16 @@ public function createService(Definition $definition, $id, $tryProxy = true) if ($tryProxy || !$definition->isLazy()) { // share only if proxying failed, or if not a proxy - $this->shareService($definition, $service, $id); + $this->shareService($definition, $service, $id, $inlinedDefinitions); } - $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); + $properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions); foreach ($properties as $name => $value) { $service->$name = $value; } foreach ($definition->getMethodCalls() as $call) { - $this->callMethod($service, $call); + $this->callMethod($service, $call, $inlinedDefinitions); } if ($callable = $definition->getConfigurator()) { @@ -907,7 +911,7 @@ public function createService(Definition $definition, $id, $tryProxy = true) if ($callable[0] instanceof Reference) { $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior()); } elseif ($callable[0] instanceof Definition) { - $callable[0] = $this->createService($callable[0], null); + $callable[0] = $this->createService($callable[0], $inlinedDefinitions); } } @@ -930,15 +934,20 @@ public function createService(Definition $definition, $id, $tryProxy = true) * the real service instances and all expressions evaluated */ public function resolveServices($value) + { + return $this->doResolveServices($value, new \SplObjectStorage()); + } + + private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions) { if (is_array($value)) { foreach ($value as $k => $v) { - $value[$k] = $this->resolveServices($v); + $value[$k] = $this->doResolveServices($v, $inlinedDefinitions); } } elseif ($value instanceof Reference) { $value = $this->get((string) $value, $value->getInvalidBehavior()); } elseif ($value instanceof Definition) { - $value = $this->createService($value, null); + $value = $this->createService($value, $inlinedDefinitions); } elseif ($value instanceof Expression) { $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this)); } @@ -1065,14 +1074,14 @@ private function synchronize($id) foreach ($definition->getMethodCalls() as $call) { foreach ($call[1] as $argument) { if ($argument instanceof Reference && $id == (string) $argument) { - $this->callMethod($this->get($definitionId), $call); + $this->callMethod($this->get($definitionId), $call, new \SplObjectStorage()); } } } } } - private function callMethod($service, $call) + private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions) { $services = self::getServiceConditionals($call[1]); @@ -1082,7 +1091,7 @@ private function callMethod($service, $call) } } - call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])))); + call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions)); } /** @@ -1094,9 +1103,14 @@ private function callMethod($service, $call) * * @throws InactiveScopeException */ - private function shareService(Definition $definition, $service, $id) + private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions) { - if (null !== $id && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) { + if (self::SCOPE_PROTOTYPE === $scope = $definition->getScope()) { + return; + } + if (null === $id) { + $inlinedDefinitions[$definition] = $service; + } else { if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) { throw new InactiveScopeException($id, $scope); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f4274b80a4443..32e1b99adb255 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -827,6 +827,28 @@ public function testLazyLoadedService() $this->assertTrue($classInList); } + public function testInlinedDefinitions() + { + $container = new ContainerBuilder(); + + $definition = new Definition('BarClass'); + + $container->register('bar_user', 'BarUserClass') + ->addArgument($definition) + ->setProperty('foo', $definition); + + $container->register('bar', 'BarClass') + ->setProperty('foo', $definition) + ->addMethodCall('setBaz', array($definition)); + + $barUser = $container->get('bar_user'); + $bar = $container->get('bar'); + + $this->assertSame($barUser->foo, $barUser->bar); + $this->assertSame($bar->foo, $bar->getBaz()); + $this->assertNotSame($bar->foo, $barUser->foo); + } + public function testInitializePropertiesBeforeMethodCalls() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php index 0ecdea3fbfb89..92db8f3c5ebfb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php @@ -8,7 +8,7 @@ function sc_configure($instance) $instance->configure(); } -class BarClass +class BarClass extends BazClass { protected $baz; public $foo = 'foo'; From 1b408e692ddc6d353c89e9684afd96f51ce6d417 Mon Sep 17 00:00:00 2001 From: chihiro-adachi Date: Wed, 22 Nov 2017 19:00:37 +0900 Subject: [PATCH 33/74] [Form] Fixed ContextErrorException in FileType --- .../Form/Extension/Core/Type/FileType.php | 7 ++++++- .../Tests/Extension/Core/Type/FileTypeTest.php | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php index fc5b1aae68329..cff7adf1bb2c8 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php @@ -34,8 +34,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) if ($options['multiple']) { $data = array(); + $files = $event->getData(); - foreach ($event->getData() as $file) { + if (!is_array($files)) { + $files = array(null); + } + + foreach ($files as $file) { if ($requestHandler->isFileUpload($file)) { $data[] = $file; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php index 5d6fe1e20d668..646470ff5abf9 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php @@ -158,6 +158,24 @@ public function testMultipleSubmittedFilePathsAreDropped(RequestHandlerInterface $this->assertCount(1, $form->getData()); } + /** + * @dataProvider requestHandlerProvider + */ + public function testSubmitNonArrayValueWhenMultiple(RequestHandlerInterface $requestHandler) + { + $form = $this->factory + ->createBuilder(static::TESTED_TYPE, null, array( + 'multiple' => true, + )) + ->setRequestHandler($requestHandler) + ->getForm(); + $form->submit(null); + + $this->assertSame(array(), $form->getData()); + $this->assertSame(array(), $form->getNormData()); + $this->assertSame(array(), $form->getViewData()); + } + public function requestHandlerProvider() { return array( From 37baa1de512da4390a953bfcc0d59f36e73ddc0e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 23 Nov 2017 12:13:33 +0100 Subject: [PATCH 34/74] Fix merge --- src/Symfony/Component/DependencyInjection/ContainerBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 84863a2fb8245..15da037be7869 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1151,7 +1151,7 @@ private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitio */ private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions) { - if (!$definition->isShared() || self::SCOPE_PROTOTYPE === $scope = $definition->getScope()) { + if (!$definition->isShared() || self::SCOPE_PROTOTYPE === $scope = $definition->getScope(false)) { return; } if (null === $id) { From b34d5b77a4a44db4db704987fbda6caebed5858a Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Thu, 23 Nov 2017 12:03:37 +0000 Subject: [PATCH 35/74] `resolveEnvPlaceholders` will return a mixed value --- src/Symfony/Component/DependencyInjection/ContainerBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index de3e84823dea1..c3aee4e6fd35a 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1286,7 +1286,7 @@ public function getAutoconfiguredInstanceof() * true to resolve to the actual values of the referenced env vars * @param array &$usedEnvs Env vars found while resolving are added to this array * - * @return string The string with env parameters resolved + * @return mixed The value with env parameters resolved if a string or an array is passed */ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null) { From c429c3346a7c7dea1f00ca8fdcb5698d5c523a93 Mon Sep 17 00:00:00 2001 From: Jerzy Zawadzki Date: Wed, 22 Nov 2017 14:58:23 +0100 Subject: [PATCH 36/74] Make search in debug:container command case-insensitive --- .../Bundle/FrameworkBundle/Command/ContainerDebugCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 21d1e6d3c9976..a9c5663eecca4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -217,9 +217,8 @@ private function findServiceIdsContaining(ContainerBuilder $builder, $name) { $serviceIds = $builder->getServiceIds(); $foundServiceIds = array(); - $name = strtolower($name); foreach ($serviceIds as $serviceId) { - if (false === strpos($serviceId, $name)) { + if (false === stripos($serviceId, $name)) { continue; } $foundServiceIds[] = $serviceId; From 5998e9d7b5b71b93f9f87e69fea336480c263ed0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Nov 2017 15:32:31 +0100 Subject: [PATCH 37/74] [Routing] Fix "config-file-relative" annotation loader resources --- .../Routing/Loader/AnnotationDirectoryLoader.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php index 616d01ef4cda4..4574a0201c0c3 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php @@ -34,7 +34,9 @@ class AnnotationDirectoryLoader extends AnnotationFileLoader */ public function load($path, $type = null) { - $dir = $this->locator->locate($path); + if (!is_dir($dir = $this->locator->locate($path))) { + return parent::supports($path, $type) ? parent::load($path, $type) : new RouteCollection(); + } $collection = new RouteCollection(); $collection->addResource(new DirectoryResource($dir, '/\.php$/')); @@ -74,16 +76,18 @@ function (\SplFileInfo $current) { */ public function supports($resource, $type = null) { - if (!is_string($resource)) { + if ('annotation' === $type) { + return true; + } + + if ($type || !is_string($resource)) { return false; } try { - $path = $this->locator->locate($resource); + return is_dir($this->locator->locate($resource)); } catch (\Exception $e) { return false; } - - return is_dir($path) && (!$type || 'annotation' === $type); } } From c7333b1c68bb735828eda0128d09da9353495af3 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Fri, 24 Nov 2017 00:05:16 +0100 Subject: [PATCH 38/74] Prefer overflow-wrap to word-break --- .../Bundle/TwigBundle/Resources/views/exception.css.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig index 87a60d4197072..f0ca2f5b048ee 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig @@ -22,7 +22,7 @@ table th { background-color: #E0E0E0; font-weight: bold; text-align: left; } .hidden { display: none; } .nowrap { white-space: nowrap; } .newline { display: block; } -.break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } +.break-long-words { word-wrap: break-word; overflow-wrap: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; min-width: 0; } .text-small { font-size: 12px !important; } .text-muted { color: #999; } .text-bold { font-weight: bold; } From bef26187795fead355967c066acc41acd619d197 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Fri, 24 Nov 2017 09:32:53 +0100 Subject: [PATCH 39/74] [WebProfilerBundle] Reset letter-spacing in toolbar --- .../WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 3a65e1d0537d6..5bfb109adbed7 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -40,6 +40,7 @@ -moz-box-sizing: content-box; box-sizing: content-box; vertical-align: baseline; + letter-spacing: normal; } .sf-toolbarreset { From f4999d8af0fe97ecc2992ba28afab0e404929478 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Fri, 24 Nov 2017 10:32:00 +0000 Subject: [PATCH 40/74] Add tests proving it can load annotated files --- .../Loader/AnnotationDirectoryLoaderTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php index 78cec4be2a159..1e8ee394015e1 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php @@ -69,6 +69,24 @@ public function testSupports() $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified'); } + public function testItSupportsAnyAnnotation() + { + $this->assertTrue($this->loader->supports(__DIR__.'/../Fixtures/even-with-not-existing-folder', 'annotation')); + } + + public function testLoadFileIfLocatedResourceIsFile() + { + $this->reader->expects($this->exactly(1))->method('getClassAnnotation'); + + $this->reader + ->expects($this->any()) + ->method('getMethodAnnotations') + ->will($this->returnValue(array())) + ; + + $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); + } + private function expectAnnotationsToBeReadFrom(array $classes) { $this->reader->expects($this->exactly(count($classes))) From 7921255faf04be83b2b1e08500027e9514a0d286 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 24 Nov 2017 12:48:20 +0100 Subject: [PATCH 41/74] [DI] Dont resolve envs in service ids --- .../Compiler/CheckDefinitionValidityPass.php | 16 +- .../Compiler/ResolveEnvPlaceholdersPass.php | 2 +- .../DependencyInjection/Dumper/PhpDumper.php | 33 ++-- .../CheckDefinitionValidityPassTest.php | 21 ++- .../Tests/ContainerBuilderTest.php | 16 ++ .../Tests/Dumper/PhpDumperTest.php | 9 + .../containers/container_env_in_id.php | 22 +++ .../Tests/Fixtures/php/services_env_in_id.php | 177 ++++++++++++++++++ 8 files changed, 269 insertions(+), 27 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php index a8a652c7a2319..435d97e3daf3f 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php @@ -77,16 +77,20 @@ public function process(ContainerBuilder $container) } } - $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); - if (null !== $usedEnvs) { - throw new EnvParameterException(array($resolvedId), null, 'A service name ("%s") cannot contain dynamic values.'); + if ($definition->isPublic()) { + $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); + if (null !== $usedEnvs) { + throw new EnvParameterException(array($resolvedId), null, 'A service name ("%s") cannot contain dynamic values.'); + } } } foreach ($container->getAliases() as $id => $alias) { - $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); - if (null !== $usedEnvs) { - throw new EnvParameterException(array($resolvedId), null, 'An alias name ("%s") cannot contain dynamic values.'); + if ($alias->isPublic()) { + $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); + if (null !== $usedEnvs) { + throw new EnvParameterException(array($resolvedId), null, 'An alias name ("%s") cannot contain dynamic values.'); + } } } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php index 8e44008317c27..f42107c6f7fd2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php @@ -35,7 +35,7 @@ protected function processValue($value, $isRoot = false) $value = parent::processValue($value, $isRoot); - if ($value && is_array($value)) { + if ($value && is_array($value) && !$isRoot) { $value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), true), $value); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index d60072b7551e9..6c0cf4f1b6a69 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -680,6 +680,7 @@ private function addServices() private function addNewInstance(Definition $definition, $return, $instantiation, $id) { $class = $this->dumpValue($definition->getClass()); + $return = ' '.$return.$instantiation; $arguments = array(); foreach ($definition->getArguments() as $value) { @@ -695,7 +696,7 @@ private function addNewInstance(Definition $definition, $return, $instantiation, if ($callable[0] instanceof Reference || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) { - return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); } $class = $this->dumpValue($callable[0]); @@ -705,24 +706,24 @@ private function addNewInstance(Definition $definition, $return, $instantiation, throw new RuntimeException(sprintf('Cannot dump definition: The "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id)); } - return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); } if (0 === strpos($class, 'new ')) { - return sprintf(" $return{$instantiation}(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); } - return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : ''); + return $return.sprintf("call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : ''); } - return sprintf(" $return{$instantiation}%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : ''); } if (false !== strpos($class, '$')) { - return sprintf(" \$class = %s;\n\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments)); + return sprintf(" \$class = %s;\n\n%snew \$class(%s);\n", $class, $return, implode(', ', $arguments)); } - return sprintf(" $return{$instantiation}new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments)); + return $return.sprintf("new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments)); } /** @@ -890,7 +891,7 @@ private function addNormalizedIds() ksort($normalizedIds); foreach ($normalizedIds as $id => $normalizedId) { if ($this->container->has($normalizedId)) { - $code .= ' '.$this->export($id).' => '.$this->export($normalizedId).",\n"; + $code .= ' '.$this->doExport($id).' => '.$this->doExport($normalizedId).",\n"; } } @@ -912,7 +913,7 @@ private function addMethodMap() $code = " \$this->methodMap = array(\n"; ksort($definitions); foreach ($definitions as $id => $definition) { - $code .= ' '.$this->export($id).' => '.$this->export($this->generateMethodName($id)).",\n"; + $code .= ' '.$this->doExport($id).' => '.$this->doExport($this->generateMethodName($id)).",\n"; } return $code." );\n"; @@ -933,7 +934,7 @@ private function addPrivateServices() ksort($definitions); foreach ($definitions as $id => $definition) { if (!$definition->isPublic()) { - $code .= ' '.$this->export($id)." => true,\n"; + $code .= ' '.$this->doExport($id)." => true,\n"; } } @@ -966,7 +967,7 @@ private function addAliases() while (isset($aliases[$id])) { $id = (string) $aliases[$id]; } - $code .= ' '.$this->export($alias).' => '.$this->export($id).",\n"; + $code .= ' '.$this->doExport($alias).' => '.$this->doExport($id).",\n"; } return $code." );\n"; @@ -1688,9 +1689,9 @@ private function exportTargetDirs() private function export($value) { if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) { - $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1])).'.' : ''; + $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = $matches[0][1] + strlen($matches[0][0]); - $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix)) : ''; + $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; $dirname = '__DIR__'; if (0 < $offset = 1 + $this->targetDirMaxMatches - count($matches)) { @@ -1704,10 +1705,10 @@ private function export($value) return $dirname; } - return $this->doExport($value); + return $this->doExport($value, true); } - private function doExport($value) + private function doExport($value, $resolveEnv = false) { if (is_string($value) && false !== strpos($value, "\n")) { $cleanParts = explode("\n", $value); @@ -1717,7 +1718,7 @@ private function doExport($value) $export = var_export($value, true); } - if ("'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('%s').'")) { + if ($resolveEnv && "'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('%s').'")) { $export = $resolvedExport; if ("'" === $export[1]) { $export = substr($export, 3); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php index 473d5667d448e..d47303e85138c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Compiler\CheckDefinitionValidityPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -79,11 +80,11 @@ public function testInvalidTags() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException */ - public function testDynamicServiceName() + public function testDynamicPublicServiceName() { $container = new ContainerBuilder(); $env = $container->getParameterBag()->get('env(BAR)'); - $container->register("foo.$env", 'class'); + $container->register("foo.$env", 'class')->setPublic(true); $this->process($container); } @@ -91,15 +92,27 @@ public function testDynamicServiceName() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException */ - public function testDynamicAliasName() + public function testDynamicPublicAliasName() { $container = new ContainerBuilder(); $env = $container->getParameterBag()->get('env(BAR)'); - $container->setAlias("foo.$env", 'class'); + $container->setAlias("foo.$env", new Alias('class', true)); $this->process($container); } + public function testDynamicPrivateName() + { + $container = new ContainerBuilder(); + $env = $container->getParameterBag()->get('env(BAR)'); + $container->register("foo.$env", 'class')->setPublic(false); + $container->setAlias("bar.$env", new Alias('class', false)); + + $this->process($container); + + $this->addToAssertionCount(1); + } + protected function process(ContainerBuilder $container) { $pass = new CheckDefinitionValidityPass(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 665a0b25d77d2..8b905746b2e43 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -665,6 +665,22 @@ public function testCompileWithResolveMissingEnv() $container->compile(true); } + public function testEnvInId() + { + $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php'; + $container->compile(true); + + $expected = array( + 'service_container', + 'foo', + 'bar', + 'bar_%env(BAR)%', + ); + $this->assertSame($expected, array_keys($container->getDefinitions())); + + $this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1))); + } + /** * @expectedException \LogicException */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 0d734cb4c222a..44e172fed2c79 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -327,6 +327,15 @@ public function testDumpAutowireData() $this->assertStringEqualsFile(self::$fixturesPath.'/php/services24.php', $dumper->dump()); } + public function testEnvInId() + { + $container = include self::$fixturesPath.'/containers/container_env_in_id.php'; + $container->compile(); + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_env_in_id.php', $dumper->dump()); + } + public function testEnvParameter() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php new file mode 100644 index 0000000000000..4699f41011a41 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php @@ -0,0 +1,22 @@ +setParameter('env(BAR)', 'bar'); + +$container->register('foo', 'stdClass')->setPublic(true) + ->addArgument(new Reference('bar_%env(BAR)%')) + ->addArgument(array('baz_%env(BAR)%' => new Reference('baz_%env(BAR)%'))); + +$container->register('bar', 'stdClass')->setPublic(true) + ->addArgument(new Reference('bar_%env(BAR)%')); + +$container->register('bar_%env(BAR)%', 'stdClass')->setPublic(false); +$container->register('baz_%env(BAR)%', 'stdClass')->setPublic(false); + +return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php new file mode 100644 index 0000000000000..d7f2ea626aa87 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php @@ -0,0 +1,177 @@ +parameters = $this->getDefaultParameters(); + + $this->services = array(); + $this->normalizedIds = array( + 'bar_%env(bar)%' => 'bar_%env(BAR)%', + ); + $this->methodMap = array( + 'bar' => 'getBarService', + 'bar_%env(BAR)%' => 'getBarenvBARService', + 'foo' => 'getFooService', + ); + $this->privates = array( + 'bar_%env(BAR)%' => true, + ); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + /** + * {@inheritdoc} + */ + public function isCompiled() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } + + /** + * Gets the public 'bar' shared service. + * + * @return \stdClass + */ + protected function getBarService() + { + return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : $this->getBarenvBARService()) && false ?: '_'}); + } + + /** + * Gets the public 'foo' shared service. + * + * @return \stdClass + */ + protected function getFooService() + { + return $this->services['foo'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : $this->getBarenvBARService()) && false ?: '_'}, array('baz_'.$this->getEnv('BAR') => new \stdClass())); + } + + /** + * Gets the private 'bar_%env(BAR)%' shared service. + * + * @return \stdClass + */ + protected function getBarenvBARService() + { + return $this->services['bar_%env(BAR)%'] = new \stdClass(); + } + + /** + * {@inheritdoc} + */ + public function getParameter($name) + { + $name = strtolower($name); + + if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + if (isset($this->loadedDynamicParameters[$name])) { + return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + + return $this->parameters[$name]; + } + + /** + * {@inheritdoc} + */ + public function hasParameter($name) + { + $name = strtolower($name); + + return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]); + } + + /** + * {@inheritdoc} + */ + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + /** + * {@inheritdoc} + */ + public function getParameterBag() + { + if (null === $this->parameterBag) { + $parameters = $this->parameters; + foreach ($this->loadedDynamicParameters as $name => $loaded) { + $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + $this->parameterBag = new FrozenParameterBag($parameters); + } + + return $this->parameterBag; + } + + private $loadedDynamicParameters = array(); + private $dynamicParameters = array(); + + /** + * Computes a dynamic parameter. + * + * @param string The name of the dynamic parameter to load + * + * @return mixed The value of the dynamic parameter + * + * @throws InvalidArgumentException When the dynamic parameter does not exist + */ + private function getDynamicParameter($name) + { + throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); + } + + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'env(bar)' => 'bar', + ); + } +} From a264238e8a398029266350ef14d9b1c088cd4161 Mon Sep 17 00:00:00 2001 From: "Issei.M" Date: Sat, 25 Nov 2017 00:42:53 +0900 Subject: [PATCH 42/74] [Form] Don't rely on if http-foundation isn't in FileType --- .../Component/Form/Extension/Core/Type/FileType.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php index ddd5cae0bc3c3..7d84512d9b3c7 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php @@ -92,9 +92,12 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - $dataClass = function (Options $options) { - return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; - }; + $dataClass = null; + if (class_exists('Symfony\Component\HttpFoundation\File\File')) { + $dataClass = function (Options $options) { + return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; + }; + } $emptyData = function (Options $options) { return $options['multiple'] ? array() : null; From 73f1ac5ea2bc153f6a8ba9b9ad03a02996691117 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 26 Nov 2017 18:52:52 +0100 Subject: [PATCH 43/74] [DI] Fix tracking of env vars in exceptions --- .../MergeExtensionConfigurationPass.php | 28 +++++++++------ .../MergeExtensionConfigurationPassTest.php | 34 +++++++++++++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php index c3b4d78dd622d..491e2c48589d2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php @@ -52,18 +52,26 @@ public function process(ContainerBuilder $container) } $config = $resolvingBag->resolveValue($config); - $tmpContainer = new ContainerBuilder($resolvingBag); - $tmpContainer->setResourceTracking($container->isTrackingResources()); - $tmpContainer->addObjectResource($extension); - if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) { - $tmpContainer->addObjectResource($configuration); - } + try { + $tmpContainer = new ContainerBuilder($resolvingBag); + $tmpContainer->setResourceTracking($container->isTrackingResources()); + $tmpContainer->addObjectResource($extension); + if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) { + $tmpContainer->addObjectResource($configuration); + } - foreach ($exprLangProviders as $provider) { - $tmpContainer->addExpressionLanguageProvider($provider); - } + foreach ($exprLangProviders as $provider) { + $tmpContainer->addExpressionLanguageProvider($provider); + } - $extension->load($config, $tmpContainer); + $extension->load($config, $tmpContainer); + } catch (\Exception $e) { + if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) { + $container->getParameterBag()->mergeEnvPlaceholders($resolvingBag); + } + + throw $e; + } if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) { // don't keep track of env vars that are *overridden* when configs are merged diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php index 44d1933a80fa8..7f4583a16c95d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php @@ -84,6 +84,22 @@ public function testOverriddenEnvsAreMerged() $this->assertSame(array('BAZ', 'FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders())); $this->assertSame(array('BAZ' => 1, 'FOO' => 0), $container->getEnvCounters()); } + + public function testThrowingExtensionsGetMergedBag() + { + $container = new ContainerBuilder(); + $container->registerExtension(new ThrowingExtension()); + $container->prependExtensionConfig('throwing', array('bar' => '%env(FOO)%')); + + try { + $pass = new MergeExtensionConfigurationPass(); + $pass->process($container); + $this->fail('An exception should have been thrown.'); + } catch (\Exception $e) { + } + + $this->assertSame(array('FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders())); + } } class FooConfiguration implements ConfigurationInterface @@ -125,3 +141,21 @@ public function load(array $configs, ContainerBuilder $container) } } } + +class ThrowingExtension extends Extension +{ + public function getAlias() + { + return 'throwing'; + } + + public function getConfiguration(array $config, ContainerBuilder $container) + { + return new FooConfiguration(); + } + + public function load(array $configs, ContainerBuilder $container) + { + throw new \Exception(); + } +} From a44f8a5b1ae18a8899fa2ea0369f87404d439ab8 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 27 Nov 2017 18:35:30 +0100 Subject: [PATCH 44/74] [FrameworkBundle][Serializer] Remove YamlEncoder definition if Yaml component isn't installed --- .../DependencyInjection/FrameworkExtension.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cb0a53d5d6072..8b21f6c644a5a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -56,6 +56,7 @@ use Symfony\Component\Validator\ObjectInitializerInterface; use Symfony\Component\WebLink\HttpHeaderSerializer; use Symfony\Component\Workflow; +use Symfony\Component\Yaml\Yaml; /** * FrameworkExtension. @@ -1172,6 +1173,10 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $container->removeDefinition('serializer.normalizer.object'); } + if (!class_exists(Yaml::class)) { + $container->removeDefinition('serializer.encoder.yaml'); + } + $serializerLoaders = array(); if (isset($config['enable_annotations']) && $config['enable_annotations']) { if (!$this->annotationsConfigEnabled) { From 7fe3fe824547101a9c0d66a558ff1d4873dfe5f0 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Tue, 28 Nov 2017 06:31:17 +0100 Subject: [PATCH 45/74] [HttpFoundation] AutExpireFlashBag should not clear new flashes --- .../HttpFoundation/Session/Flash/AutoExpireFlashBag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php index 59ba309005b38..0ed6600974371 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php @@ -106,7 +106,7 @@ public function get($type, array $default = array()) public function all() { $return = $this->flashes['display']; - $this->flashes = array('new' => array(), 'display' => array()); + $this->flashes['display'] = array(); return $return; } From 706201efe46580e89d3f24d6fa097e065c43a2c8 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Tue, 28 Nov 2017 08:49:55 +0000 Subject: [PATCH 46/74] Test that it do not remove the new flashes when displaying the existing ones --- .../Tests/Session/Flash/AutoExpireFlashBagTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php index 18b71a5021fbb..0e0724a3249a4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php @@ -150,4 +150,12 @@ public function testClear() { $this->assertEquals(array('notice' => array('A previous flash message')), $this->bag->clear()); } + + public function testDoNotRemoveTheNewFlashesWhenDisplayingTheExistingOnes() + { + $this->bag->add('success', 'Something'); + $this->bag->all(); + + $this->assertEquals(array('new' => array('success' => array('Something')), 'display' => array()), $this->array); + } } From 6e87382bfaf2ca5fa75f307abf328495961f6a3a Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Tue, 28 Nov 2017 09:21:56 +0000 Subject: [PATCH 47/74] Do not cache cache attributes if `attributes` is in the context --- .../Normalizer/AbstractObjectNormalizer.php | 4 +++ .../Tests/Normalizer/ObjectNormalizerTest.php | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 68e86da1f21e2..29eab6f1ca8b4 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -126,6 +126,10 @@ protected function getAttributes($object, $format = null, array $context) return $allowedAttributes; } + if (isset($context['attributes'])) { + return $this->extractAttributes($object, $format, $context); + } + if (isset($this->attributesCache[$class])) { return $this->attributesCache[$class]; } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index b2d7b872f4d94..9407fdf52d7b0 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -713,6 +713,37 @@ public function testAttributesContextDenormalizeConstructor() 'inner' => array('foo' => 'foo', 'bar' => 'bar'), ), DummyWithConstructorObjectAndDefaultValue::class, null, $context)); } + + public function testNormalizeSameObjectWithDifferentAttributes() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory); + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + + $dummy = new ObjectOuter(); + $dummy->foo = new ObjectInner(); + $dummy->foo->foo = 'foo.foo'; + $dummy->foo->bar = 'foo.bar'; + + $dummy->bar = new ObjectInner(); + $dummy->bar->foo = 'bar.foo'; + $dummy->bar->bar = 'bar.bar'; + + $this->assertEquals(array( + 'foo' => array( + 'bar' => 'foo.bar', + ), + 'bar' => array( + 'foo' => 'bar.foo', + ), + ), $this->normalizer->normalize($dummy, 'json', array( + 'attributes' => array( + 'foo' => array('bar'), + 'bar' => array('foo'), + ), + ))); + } } class ObjectDummy From b988aa7c59f457ab4d4f03d45ed53d04df4cea56 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Nov 2017 09:00:03 +0100 Subject: [PATCH 48/74] [DI] Fix infinite loop in InlineServiceDefinitionsPass --- .../Compiler/InlineServiceDefinitionsPass.php | 5 +---- .../InlineServiceDefinitionsPassTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index f2ef363c837cc..ff9ac315b0af8 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -61,10 +61,7 @@ protected function processValue($value, $isRoot = false) $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); $this->inlinedServiceIds[$id][] = $this->currentId; - if ($definition->isShared()) { - return $definition; - } - $value = clone $definition; + return $definition->isShared() ? $definition : clone $definition; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php index 26b24fa713242..09e4913664784 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php @@ -92,6 +92,25 @@ public function testProcessDoesInlineNonSharedService() $this->assertNotSame($container->getDefinition('bar'), $arguments[2]); } + public function testProcessInlinesMixedServicesLoop() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->addArgument(new Reference('bar')) + ->setShared(false) + ; + $container + ->register('bar') + ->setPublic(false) + ->addMethodCall('setFoo', array(new Reference('foo'))) + ; + + $this->process($container); + + $this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar')); + } + public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition() { $container = new ContainerBuilder(); From d84b47fe9de42e7f9f1f4722c4490d95719eb9c8 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Wed, 29 Nov 2017 07:49:34 +0100 Subject: [PATCH 49/74] [HttpKernel] Arrays with scalar values passed to ESI fragment renderer throw deprecation notice --- .../Fragment/AbstractSurrogateFragmentRenderer.php | 4 ++-- .../Tests/Fragment/EsiFragmentRendererTest.php | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Fragment/AbstractSurrogateFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/AbstractSurrogateFragmentRenderer.php index e955cd0d43c6f..9526908a37858 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/AbstractSurrogateFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/AbstractSurrogateFragmentRenderer.php @@ -98,8 +98,8 @@ private function generateSignedFragmentUri($uri, Request $request) private function containsNonScalars(array $values) { foreach ($values as $value) { - if (is_array($value) && $this->containsNonScalars($value)) { - return true; + if (is_array($value)) { + return $this->containsNonScalars($value); } elseif (!is_scalar($value) && null !== $value) { return true; } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php index bfe922e22c76b..7099b4d7e8bf6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php @@ -34,7 +34,15 @@ public function testRenderFallbackWithObjectAttributesIsDeprecated() { $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo')); $request = Request::create('/'); - $reference = new ControllerReference('main_controller', array('foo' => array('a' => array(), 'b' => new \stdClass())), array()); + $reference = new ControllerReference('main_controller', array('foo' => new \stdClass()), array()); + $strategy->render($reference, $request); + } + + public function testRenderFallbackWithScalarIsNotDeprecated() + { + $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo')); + $request = Request::create('/'); + $reference = new ControllerReference('main_controller', array('foo' => array(true)), array()); $strategy->render($reference, $request); } From 9897da4c020b9188965132330ffc5ff8ff20480e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 29 Nov 2017 14:05:31 +0100 Subject: [PATCH 50/74] remove upgrade instructions for kernel.root_dir --- UPGRADE-3.3.md | 6 ------ UPGRADE-4.0.md | 6 ------ 2 files changed, 12 deletions(-) diff --git a/UPGRADE-3.3.md b/UPGRADE-3.3.md index 1b61c352238fe..2efc4df740d83 100644 --- a/UPGRADE-3.3.md +++ b/UPGRADE-3.3.md @@ -254,12 +254,6 @@ HttpFoundation HttpKernel ----------- - * Deprecated the `kernel.root_dir` parameter. Use the new `kernel.project_dir` - parameter instead. - - * Deprecated the `Kernel::getRootDir()` method. Use the new `Kernel::getProjectDir()` - method instead. - * The `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` methods have been deprecated and will be removed in 4.0. * The `Psr6CacheClearer::addPool()` method has been deprecated. Pass an array diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index b1bfc214837a4..5adaa8b794292 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -361,12 +361,6 @@ HttpFoundation HttpKernel ---------- - * Removed the `kernel.root_dir` parameter. Use the `kernel.project_dir` parameter - instead. - - * Removed the `Kernel::getRootDir()` method. Use the `Kernel::getProjectDir()` - method instead. - * The `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` methods have been removed. * Possibility to pass non-scalar values as URI attributes to the ESI and SSI From b0d297b962a2b115d01051d14485f19f43dc9c87 Mon Sep 17 00:00:00 2001 From: Derek Bonner Date: Wed, 29 Nov 2017 20:11:54 -0800 Subject: [PATCH 51/74] [Dotenv] Changed preg_match flags from null to 0 --- src/Symfony/Component/Dotenv/Dotenv.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 910a1622f303b..dde92f46af5b6 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -173,7 +173,7 @@ private function lexVarname() private function lexValue() { - if (preg_match('/[ \t]*+(?:#.*)?$/Am', $this->data, $matches, null, $this->cursor)) { + if (preg_match('/[ \t]*+(?:#.*)?$/Am', $this->data, $matches, 0, $this->cursor)) { $this->moveCursor($matches[0]); $this->skipEmptyLines(); @@ -295,7 +295,7 @@ private function lexNestedExpression() private function skipEmptyLines() { - if (preg_match('/(?:\s*+(?:#[^\n]*+)?+)++/A', $this->data, $match, null, $this->cursor)) { + if (preg_match('/(?:\s*+(?:#[^\n]*+)?+)++/A', $this->data, $match, 0, $this->cursor)) { $this->moveCursor($match[0]); } } From 1b141732db0ac76a0a7330c1df8a6e29047b5e20 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Nov 2017 16:33:25 +0100 Subject: [PATCH 52/74] [VarDumper] Dont use empty(), it chokes on eg GMP objects --- src/Symfony/Component/VarDumper/Caster/Caster.php | 4 ++-- src/Symfony/Component/VarDumper/Cloner/VarCloner.php | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index 29f002b8cc1a6..5fdae442dcda8 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -118,8 +118,8 @@ public static function filter(array $a, $filter, array $listedProperties = array if (null === $v) { $type |= self::EXCLUDE_NULL & $filter; - } - if (empty($v)) { + $type |= self::EXCLUDE_EMPTY & $filter; + } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || array() === $v) { $type |= self::EXCLUDE_EMPTY & $filter; } if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !in_array($k, $listedProperties, true)) { diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 5399c66010a89..1f588db82cae5 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -94,13 +94,16 @@ protected function doClone($var) // Create $stub when the original value $v can not be used directly // If $v is a nested structure, put that structure in array $a switch (true) { - case empty($v): - case true === $v: + case null === $v: + case \is_bool($v): case \is_int($v): case \is_float($v): continue 2; case \is_string($v): + if ('' === $v) { + continue 2; + } if (!\preg_match('//u', $v)) { $stub = new Stub(); $stub->type = Stub::TYPE_STRING; @@ -124,6 +127,9 @@ protected function doClone($var) break; case \is_array($v): + if (!$v) { + continue 2; + } $stub = $arrayStub; $stub->class = Stub::ARRAY_INDEXED; From 85058949883eee0b0deafbf5b090704adad28750 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Thu, 30 Nov 2017 23:22:28 -0500 Subject: [PATCH 53/74] Fix collision between view properties and form fields --- .../Bridge/Twig/Extension/FormExtension.php | 7 +++++++ .../views/Form/bootstrap_3_layout.html.twig | 4 ++-- .../views/Form/form_div_layout.html.twig | 4 ++-- .../views/Form/form_table_layout.html.twig | 2 +- .../Extension/FormExtensionDivLayoutTest.php | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index 053b1d4a6b336..aaed8221c1fc8 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -14,6 +14,7 @@ use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser; use Symfony\Bridge\Twig\Form\TwigRendererInterface; use Symfony\Component\Form\Extension\Core\View\ChoiceView; +use Symfony\Component\Form\FormView; use Twig\Environment; use Twig\Extension\AbstractExtension; use Twig\Extension\InitRuntimeInterface; @@ -97,6 +98,7 @@ public function getTests() { return array( new TwigTest('selectedchoice', array($this, 'isSelectedChoice')), + new TwigTest('rootform', array($this, 'isRootForm')), ); } @@ -156,6 +158,11 @@ public function isSelectedChoice(ChoiceView $choice, $selectedValue) return $choice->value === $selectedValue; } + public function isRootForm(FormView $formView) + { + return null === $formView->parent; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index 2efc0c4d4a213..e3c76349648e5 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -238,12 +238,12 @@ {% block form_errors -%} {% if errors|length > 0 -%} - {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}{% else %}
{% endif %}
    {%- for error in errors -%}
  • {{ error.message }}
  • {%- endfor -%}
- {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}
{% else %}
{% endif %} {%- endif %} {%- endblock form_errors %} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index a27c81dd495ae..ad00a502a0f71 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -15,7 +15,7 @@ {%- block form_widget_compound -%}
- {%- if form.parent is empty -%} + {%- if form is rootform -%} {{ form_errors(form) }} {%- endif -%} {{- block('form_rows') -}} @@ -303,7 +303,7 @@ {% endif %} {%- endfor %} - {% if not form.methodRendered and form.parent is null %} + {% if not form.methodRendered and form is rootform %} {%- do form.setMethodRendered() -%} {% set method = method|upper %} {%- if method in ["GET", "POST"] -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig index c7b3a4365b51b..39274c6c8d058 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig @@ -31,7 +31,7 @@ {%- block form_widget_compound -%} - {%- if form.parent is empty and errors|length > 0 -%} + {%- if form is rootform and errors|length > 0 -%}
{{- form_errors(form) -}} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index e2fbb48ce0339..e11daf1831349 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -146,6 +146,22 @@ public function testIsChoiceSelected($expected, $choice, $value) $this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value)); } + public function isRootFormProvider() + { + return array( + array(true, new FormView()), + array(false, new FormView(new FormView())), + ); + } + + /** + * @dataProvider isRootFormProvider + */ + public function testIsRootForm($expected, FormView $formView) + { + $this->assertSame($expected, $this->extension->isRootForm($formView)); + } + protected function renderForm(FormView $view, array $vars = array()) { return (string) $this->extension->renderer->renderBlock($view, 'form', $vars); From b1ab7d0050be4f98bf1a5dc7cf386975b25dcb4a Mon Sep 17 00:00:00 2001 From: Tim Strehle Date: Thu, 30 Nov 2017 21:28:52 +0100 Subject: [PATCH 54/74] [WebProfilerBundle], [TwigBundle] Fix Profiler breaking XHTML pages (Content-Type: application/xhtml+xml) --- src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig | 2 +- .../Resources/views/Profiler/base_js.html.twig | 2 +- .../Resources/views/Profiler/toolbar_js.html.twig | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig index ccabdc968fb2e..0ac832ee0610d 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig @@ -1,6 +1,6 @@ {# This file is based on WebProfilerBundle/Resources/views/Profiler/base_js.html.twig. If you make any change in this file, verify the same change is needed in the other file. #} -/*/*/*/* {{ include('@WebProfiler/Profiler/toolbar.css.twig', { 'position': position, 'floatable': true }) }} -/*/* Date: Fri, 1 Dec 2017 11:47:04 +0100 Subject: [PATCH 55/74] do not eagerly filter comment lines Trying to be clever by filtering commented lines inside `getNextEmbedBlock()` does not work as expected. The `#` may as well be part of a multi-line quoted string where it must not be treated as the beginning of a comment. Thus, we only must ensure that a comment-like line does not skip the process of getting the next line of the embed block. --- src/Symfony/Component/Yaml/Parser.php | 15 ++------------- .../Component/Yaml/Tests/ParserTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 5093d7cd1297f..702df16f0aec0 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -601,21 +601,10 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) continue; } - // we ignore "comment" lines only when we are not inside a scalar block - if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) { - // remember ignored comment lines (they are used later in nested - // parser calls to determine real line numbers) - // - // CAUTION: beware to not populate the global property here as it - // will otherwise influence the getRealCurrentLineNb() call here - // for consecutive comment lines and subsequent embedded blocks - $this->locallySkippedLineNumbers[] = $this->getRealCurrentLineNb(); - - continue; - } - if ($indent >= $newIndent) { $data[] = substr($this->currentLine, $newIndent); + } elseif ($this->isCurrentLineComment()) { + $data[] = $this->currentLine; } elseif (0 == $indent) { $this->moveToPreviousLine(); diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index f98ac7f51c97b..7a3c405714328 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1554,6 +1554,24 @@ public function testMultiLineQuotedStringWithTrailingBackslash() $this->assertSame(array('foobar' => 'foobar'), $this->parser->parse($yaml)); } + public function testCommentCharactersInMultiLineQuotedStrings() + { + $yaml = << array( + 'foobar' => 'foo #bar', + 'bar' => 'baz', + ), + ); + + $this->assertSame($expected, $this->parser->parse($yaml)); + } + public function testParseMultiLineUnquotedString() { $yaml = << Date: Mon, 30 Oct 2017 06:23:08 +0100 Subject: [PATCH 56/74] [Validator] ExpressionValidator should use OBJECT_TO_STRING to allow value in message --- .../Constraints/ExpressionValidator.php | 4 +-- .../Constraints/ExpressionValidatorTest.php | 34 +++++++++++++++++++ .../Validator/Tests/Fixtures/ToString.php | 22 ++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/ToString.php diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index 360ec5a8d9e8d..96761f51f2c2a 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -78,11 +78,11 @@ public function validate($value, Constraint $constraint) if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING)) ->addViolation(); } else { $this->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING)) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php index 3b6de4d412582..be15967dcbd88 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraints\Expression; use Symfony\Component\Validator\Constraints\ExpressionValidator; use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\ToString; use Symfony\Component\Validator\Validation; class ExpressionValidatorTest extends AbstractConstraintValidatorTest @@ -90,6 +91,39 @@ public function testFailingExpressionAtObjectLevel() ->assertRaised(); } + public function testSucceedingExpressionAtObjectLevelWithToString() + { + $constraint = new Expression('this.data == 1'); + + $object = new ToString(); + $object->data = '1'; + + $this->setObject($object); + + $this->validator->validate($object, $constraint); + + $this->assertNoViolation(); + } + + public function testFailingExpressionAtObjectLevelWithToString() + { + $constraint = new Expression(array( + 'expression' => 'this.data == 1', + 'message' => 'myMessage', + )); + + $object = new ToString(); + $object->data = '2'; + + $this->setObject($object); + + $this->validator->validate($object, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', 'toString') + ->assertRaised(); + } + public function testSucceedingExpressionAtPropertyLevel() { $constraint = new Expression('value == this.data'); diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php b/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php new file mode 100644 index 0000000000000..714fdb9e98f5f --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Fixtures; + +class ToString +{ + public $data; + + public function __toString() + { + return 'toString'; + } +} From 3e7780cb908b34903f2ea82b5070c532a8e71c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 1 Dec 2017 20:16:54 +0100 Subject: [PATCH 57/74] [link] Prevent warnings when running link with 2.7 --- link | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/link b/link index f4070998e72b5..3bbc97f041a20 100755 --- a/link +++ b/link @@ -35,11 +35,14 @@ if (!is_dir("$argv[1]/vendor/symfony")) { } $sfPackages = array('symfony/symfony' => __DIR__); + +$filesystem = new Filesystem(); foreach (glob(__DIR__.'/src/Symfony/{Bundle,Bridge,Component,Component/Security}/*', GLOB_BRACE | GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { - $sfPackages[json_decode(file_get_contents("$dir/composer.json"))->name] = $dir; + if ($filesystem->exists($composer = "$dir/composer.json")) { + $sfPackages[json_decode(file_get_contents($composer))->name] = $dir; + } } -$filesystem = new Filesystem(); foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { $package = 'symfony/'.basename($dir); if (is_link($dir)) { From 05c3c81a200aabf7d16875d9019f3b89a929a247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 1 Dec 2017 20:12:52 +0100 Subject: [PATCH 58/74] [link] clear the cache after linking --- link | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/link b/link index f4070998e72b5..adba4a5a1ad7e 100755 --- a/link +++ b/link @@ -57,3 +57,7 @@ foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) $filesystem->symlink($sfDir, $dir); echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; } + +foreach (glob("$argv[1]/var/cache/*") as $cacheDir) { + $filesystem->remove($cacheDir); +} From 23b575819849f523d6c86c57dc08d8034b523583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 2 Dec 2017 16:57:48 +0100 Subject: [PATCH 59/74] [FrameworkBundle] Fix visibility of a test helper --- .../FrameworkBundle/Tests/Controller/RedirectControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 14b6e4428e550..c4d6d837c6a7a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -290,7 +290,7 @@ private function createRedirectController($httpPort = null, $httpsPort = null) return $controller; } - public function assertRedirectUrl(Response $returnResponse, $expectedUrl) + private function assertRedirectUrl(Response $returnResponse, $expectedUrl) { $this->assertTrue($returnResponse->isRedirect($expectedUrl), "Expected: $expectedUrl\nGot: ".$returnResponse->headers->get('Location')); } From 3bdeda048b7a9b56ca18551a1de14547d3e3f135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 2 Dec 2017 15:59:45 +0100 Subject: [PATCH 60/74] Fail as early and noisily as possible Today, I tried using SYMFONY_PHPUNIT_VERSION=6 because I don't really care about the minor version. I got lots of warnings, followed by hard-to-understand error messages. This will silence the first warning and will throw an exception instead. --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index b30eaa14538dc..110e57d321389 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -51,7 +51,12 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? '(del /S /F /Q %s & rmdir %1$s) >nul': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION")); } if (extension_loaded('openssl') && ini_get('allow_url_fopen') && !isset($_SERVER['http_proxy']) && !isset($_SERVER['https_proxy'])) { - stream_copy_to_stream(fopen("https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip", 'rb'), fopen("$PHPUNIT_VERSION.zip", 'wb')); + $remoteZip = "https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip"; + $remoteZipStream = @fopen($remoteZip, 'rb'); + if (!$remoteZipStream) { + throw new \RuntimeException("Could not find $remoteZip"); + } + stream_copy_to_stream($remoteZipStream, fopen("$PHPUNIT_VERSION.zip", 'wb')); } else { @unlink("$PHPUNIT_VERSION.zip"); passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip"); From 369075a282b0f29eeed511708651d2f9f6e67d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Mon, 4 Dec 2017 13:08:37 +0100 Subject: [PATCH 61/74] Fix for missing whitespace control modifier in form layout --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index a27c81dd495ae..eb0f6d057dcea 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -301,7 +301,7 @@ {% if not child.rendered %} {{- form_row(child) -}} {% endif %} - {%- endfor %} + {%- endfor -%} {% if not form.methodRendered and form.parent is null %} {%- do form.setMethodRendered() -%} @@ -315,7 +315,7 @@ {%- if form_method != method -%} {%- endif -%} - {% endif %} + {% endif -%} {% endblock form_rest %} {# Support #} From c9f72e2807762bd3a77d11fd4d413bc11c53a981 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 4 Dec 2017 13:50:51 +0100 Subject: [PATCH 62/74] [SecurityBundle] Fix compat with HttpFoundation >=3.4 --- .../Security/Factory/AbstractFactory.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php index d1b7980faa8a6..39c73dc0c3d95 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php @@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler; /** * AbstractFactory is the base class for all classes inheriting from @@ -29,7 +30,7 @@ abstract class AbstractFactory implements SecurityFactoryInterface protected $options = array( 'check_path' => '/login_check', 'use_forward' => false, - 'require_previous_session' => true, + 'require_previous_session' => null, ); protected $defaultSuccessHandlerOptions = array( @@ -80,6 +81,10 @@ public function addConfiguration(NodeDefinition $node) ->scalarNode('failure_handler')->end() ; + if (array_key_exists('require_previous_session', $this->options) && null === $this->options['require_previous_session']) { + $this->options['require_previous_session'] = !class_exists(AbstractSessionHandler::class); + } + foreach (array_merge($this->options, $this->defaultSuccessHandlerOptions, $this->defaultFailureHandlerOptions) as $name => $default) { if (is_bool($default)) { $builder->booleanNode($name)->defaultValue($default); From 6a2f518e74daab1f66653299f247293b390f2fc0 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Mon, 4 Dec 2017 12:36:56 +0100 Subject: [PATCH 63/74] Disallow viewing dot-files in Profiler The file viewer in the profiler should not open files that were meant to be hidden, like specifically .env files, but similarly files like .htaccess that might expose server configuration knowledge. --- .../Controller/ProfilerController.php | 2 +- .../Controller/ProfilerControllerTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 4aca4cc354e44..0920a1aa5e18a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -385,7 +385,7 @@ public function openAction(Request $request) $filename = $this->baseDir.DIRECTORY_SEPARATOR.$file; - if (preg_match("'(^|[/\\\\])\.\.?([/\\\\]|$)'", $file) || !is_readable($filename)) { + if (preg_match("'(^|[/\\\\])\.'", $file) || !is_readable($filename)) { throw new NotFoundHttpException(sprintf('The file "%s" cannot be opened.', $file)); } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index 839c9f21d9fe9..670f71dfc176d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController; use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Profiler\Profile; use Symfony\Component\HttpFoundation\Request; @@ -46,6 +47,42 @@ public function getEmptyTokenCases() ); } + /** + * @dataProvider getOpenFileCases + */ + public function testOpeningDisallowedPaths($path, $isAllowed) + { + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + $profiler = $this + ->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler') + ->disableOriginalConstructor() + ->getMock(); + + $controller = new ProfilerController($urlGenerator, $profiler, $twig, array(), 'bottom', null, __DIR__.'/../..'); + + try { + $response = $controller->openAction(Request::create('/_wdt/open', Request::METHOD_GET, array('file' => $path))); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($isAllowed); + } catch (NotFoundHttpException $e) { + $this->assertFalse($isAllowed); + } + } + + public function getOpenFileCases() + { + return array( + array('README.md', true), + array('composer.json', true), + array('Controller/ProfilerController.php', true), + array('.gitignore', false), + array('../TwigBundle/README.md', false), + array('Controller/../README.md', false), + array('Controller/./ProfilerController.php', false), + ); + } + /** * @dataProvider provideCspVariants */ From 888b48a89c7847d04a0a911ffc7e23f2e9b94131 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 4 Dec 2017 08:54:58 -0500 Subject: [PATCH 64/74] Fix collision between view properties and form fields --- .../Twig/Resources/views/Form/foundation_5_layout.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig index dc7bec9fb6ccd..af9e658923923 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig @@ -318,11 +318,11 @@ {% block form_errors -%} {% if errors|length > 0 -%} - {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}{% else %}
{% endif %} {%- for error in errors -%} {{ error.message }} {% if not loop.last %}, {% endif %} {%- endfor -%} - {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}
{% else %}
{% endif %} {%- endif %} {%- endblock form_errors %} From b23b957ae9cc77eda71357b3f07dbaaf13691e01 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 4 Dec 2017 14:06:32 +0100 Subject: [PATCH 65/74] parse newlines in quoted multiline strings --- src/Symfony/Component/Yaml/Parser.php | 17 ++++++++++++++++- src/Symfony/Component/Yaml/Tests/ParserTest.php | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 702df16f0aec0..a6e39007dfe0f 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -700,6 +700,8 @@ private function parseValue($value, $flags, $context) return Inline::parse($value, $flags, $this->refs); } + $lines = array(); + while ($this->moveToNextLine()) { // unquoted strings end before the first unindented line if (null === $quotation && 0 === $this->getCurrentLineIndentation()) { @@ -708,7 +710,7 @@ private function parseValue($value, $flags, $context) break; } - $value .= ' '.trim($this->currentLine); + $lines[] = trim($this->currentLine); // quoted string values end with a line that is terminated with the quotation character if ('' !== $this->currentLine && substr($this->currentLine, -1) === $quotation) { @@ -716,6 +718,19 @@ private function parseValue($value, $flags, $context) } } + for ($i = 0, $linesCount = count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) { + if ('' === $lines[$i]) { + $value .= "\n"; + $previousLineBlank = true; + } elseif ($previousLineBlank) { + $value .= $lines[$i]; + $previousLineBlank = false; + } else { + $value .= ' '.$lines[$i]; + $previousLineBlank = false; + } + } + Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); $parsedValue = Inline::parse($value, $flags, $this->refs); diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 7a3c405714328..1d35ecc1bd819 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1572,6 +1572,20 @@ public function testCommentCharactersInMultiLineQuotedStrings() $this->assertSame($expected, $this->parser->parse($yaml)); } + public function testBlankLinesInQuotedMultiLineString() + { + $yaml = << "foo\nbar", + ); + + $this->assertSame($expected, $this->parser->parse($yaml)); + } + public function testParseMultiLineUnquotedString() { $yaml = << Date: Mon, 4 Dec 2017 16:10:11 +0100 Subject: [PATCH 66/74] [DI] Fix deep-inlining of non-shared refs --- .../Compiler/InlineServiceDefinitionsPass.php | 44 ++++++++++++--- .../InlineServiceDefinitionsPassTest.php | 54 +++++++++++++++++++ 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index ff9ac315b0af8..8eb6e94d24696 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Reference; /** @@ -23,6 +24,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface { private $repeatedPass; + private $cloningIds = array(); private $inlinedServiceIds = array(); /** @@ -54,18 +56,44 @@ protected function processValue($value, $isRoot = false) // Reference found in ArgumentInterface::getValues() are not inlineable return $value; } - if ($value instanceof Reference && $this->container->hasDefinition($id = (string) $value)) { - $definition = $this->container->getDefinition($id); - if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) { - $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); - $this->inlinedServiceIds[$id][] = $this->currentId; - - return $definition->isShared() ? $definition : clone $definition; + if ($value instanceof Definition && $this->cloningIds) { + if ($value->isShared()) { + return $value; } + $value = clone $value; + } + + if (!$value instanceof Reference || !$this->container->hasDefinition($id = (string) $value)) { + return parent::processValue($value, $isRoot); + } + + $definition = $this->container->getDefinition($id); + + if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) { + return $value; } - return parent::processValue($value, $isRoot); + $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); + $this->inlinedServiceIds[$id][] = $this->currentId; + + if ($definition->isShared()) { + return $definition; + } + + if (isset($this->cloningIds[$id])) { + $ids = array_keys($this->cloningIds); + $ids[] = $id; + + throw new ServiceCircularReferenceException($id, array_slice($ids, array_search($id, $ids))); + } + + $this->cloningIds[$id] = true; + try { + return $this->processValue($definition); + } finally { + unset($this->cloningIds[$id]); + } } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php index 09e4913664784..365c16c2d2c95 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php @@ -111,6 +111,60 @@ public function testProcessInlinesMixedServicesLoop() $this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar')); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException + * @expectedExceptionMessage Circular reference detected for service "bar", path: "bar -> foo -> bar". + */ + public function testProcessThrowsOnNonSharedLoops() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->addArgument(new Reference('bar')) + ->setShared(false) + ; + $container + ->register('bar') + ->setShared(false) + ->addMethodCall('setFoo', array(new Reference('foo'))) + ; + + $this->process($container); + } + + public function testProcessNestedNonSharedServices() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->addArgument(new Reference('bar1')) + ->addArgument(new Reference('bar2')) + ; + $container + ->register('bar1') + ->setShared(false) + ->addArgument(new Reference('baz')) + ; + $container + ->register('bar2') + ->setShared(false) + ->addArgument(new Reference('baz')) + ; + $container + ->register('baz') + ->setShared(false) + ; + + $this->process($container); + + $baz1 = $container->getDefinition('foo')->getArgument(0)->getArgument(0); + $baz2 = $container->getDefinition('foo')->getArgument(1)->getArgument(0); + + $this->assertEquals($container->getDefinition('baz'), $baz1); + $this->assertEquals($container->getDefinition('baz'), $baz2); + $this->assertNotSame($baz1, $baz2); + } + public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition() { $container = new ContainerBuilder(); From 890edf7c38398b6981e0fdcdeb7786fee7f6bace Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Mon, 4 Dec 2017 15:32:05 +0100 Subject: [PATCH 67/74] [FrameworkBundle] Fix a bug where a color tag will be shown when passing an antislash --- .../FrameworkBundle/Console/Descriptor/TextDescriptor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 6977d4df9afa5..70012e3dc7c1b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; +use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Alias; @@ -226,7 +227,8 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o $rawOutput = isset($options['raw_text']) && $options['raw_text']; foreach ($this->sortServiceIds($serviceIds) as $serviceId) { $definition = $this->resolveServiceDefinition($builder, $serviceId); - $styledServiceId = $rawOutput ? $serviceId : sprintf('%s', $serviceId); + + $styledServiceId = $rawOutput ? $serviceId : sprintf('%s', OutputFormatter::escape($serviceId)); if ($definition instanceof Definition) { if ($showTag) { foreach ($definition->getTag($showTag) as $key => $tag) { From 0f8ff1583abffdf3b4eab026ea6e6052b30c1f11 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 10:21:12 -0800 Subject: [PATCH 68/74] marked method as being internal --- src/Symfony/Bridge/Twig/Extension/FormExtension.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index aaed8221c1fc8..e101704efaa9d 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -158,6 +158,9 @@ public function isSelectedChoice(ChoiceView $choice, $selectedValue) return $choice->value === $selectedValue; } + /** + * @internal + */ public function isRootForm(FormView $formView) { return null === $formView->parent; From 93e136b306f585b6f37fc869416b2f5c09b30fd6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 10:22:59 -0800 Subject: [PATCH 69/74] moved method to function --- .../Bridge/Twig/Extension/FormExtension.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index 6e6274dcc4935..beed1c95b3a12 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -106,7 +106,7 @@ public function getTests() { return array( new TwigTest('selectedchoice', 'Symfony\Bridge\Twig\Extension\twig_is_selected_choice'), - new TwigTest('rootform', array($this, 'isRootForm')), + new TwigTest('rootform', 'Symfony\Bridge\Twig\Extension\twig_is_root_form'), ); } @@ -166,14 +166,6 @@ public function __unset($name) unset($this->$name); } - /** - * @internal - */ - public function isRootForm(FormView $formView) - { - return null === $formView->parent; - } - /** * {@inheritdoc} */ @@ -202,3 +194,11 @@ function twig_is_selected_choice(ChoiceView $choice, $selectedValue) return $choice->value === $selectedValue; } + +/** + * @internal + */ +function twig_is_root_form(FormView $formView) +{ + return null === $formView->parent; +} From 11105f37177558826336bd12042c4eda0bf7ea37 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 10:36:52 -0800 Subject: [PATCH 70/74] fixed tests --- .../Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 9fa0a22ea31c6..6ac1846a5d414 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -159,7 +159,7 @@ public function isRootFormProvider() */ public function testIsRootForm($expected, FormView $formView) { - $this->assertSame($expected, $this->extension->isRootForm($formView)); + $this->assertSame($expected, twig_is_root_form($formView)); } protected function renderForm(FormView $view, array $vars = array()) From 0f0a5764ca7445ead215bbad3e69cf9623df4fe3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 11:01:57 -0800 Subject: [PATCH 71/74] fixed typo --- .../Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 6ac1846a5d414..2d1d03c5e6d26 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -159,7 +159,7 @@ public function isRootFormProvider() */ public function testIsRootForm($expected, FormView $formView) { - $this->assertSame($expected, twig_is_root_form($formView)); + $this->assertSame($expected, \Symfony\Bridge\Twig\Extension\twig_is_root_form($formView)); } protected function renderForm(FormView $view, array $vars = array()) From 1ff22e6accde46ad693ecbb8b234c65e4c53e717 Mon Sep 17 00:00:00 2001 From: Ricardo de Vries Date: Mon, 4 Dec 2017 12:06:27 +0100 Subject: [PATCH 72/74] [Bridge/PhpUnit] Prefer ['argv'] over --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 110e57d321389..b3f302cd340bf 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -108,6 +108,9 @@ EOPHP } +global $argv, $argc; +$argv = isset($_SERVER['argv']) ? $_SERVER['argv'] : array(); +$argc = isset($_SERVER['argc']) ? $_SERVER['argc'] : 0; $components = array(); $cmd = array_map('escapeshellarg', $argv); $exit = 0; From b1a1a8fb5c121087d5d1268021386641e97d7559 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 14:26:15 -0800 Subject: [PATCH 73/74] updated CHANGELOG for 3.3.14 --- CHANGELOG-3.3.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG-3.3.md b/CHANGELOG-3.3.md index 310284444011e..eeb42846f5f5e 100644 --- a/CHANGELOG-3.3.md +++ b/CHANGELOG-3.3.md @@ -7,6 +7,41 @@ in 3.3 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.3.0...v3.3.1 +* 3.3.14 (2017-12-04) + + * bug #25304 [Bridge/PhpUnit] Prefer $_SERVER['argv'] over $argv (ricknox) + * bug #25308 [FrameworkBundle] Fix a bug where a color tag will be shown when passing an antislash (Simperfit) + * bug #25278 Fix for missing whitespace control modifier in form layout (kubawerlos) + * bug #25305 [Form][TwigBridge] Fix collision between view properties and form fields (yceruto) + * bug #25236 [Form][TwigBridge] Fix collision between view properties and form fields (yceruto) + * bug #25312 [DI] Fix deep-inlining of non-shared refs (nicolas-grekas) + * bug #25309 [Yaml] parse newlines in quoted multiline strings (xabbuh) + * bug #25241 [Yaml] do not eagerly filter comment lines (xabbuh) + * bug #25258 [link] Prevent warnings when running link with 2.7 (dunglas) + * bug #24750 [Validator] ExpressionValidator should use OBJECT_TO_STRING (Simperfit) + * bug #25232 [WebProfilerBundle] [TwigBundle] Fix Profiler breaking XHTML pages (tistre) + * bug #25209 [VarDumper] Dont use empty(), it chokes on eg GMP objects (nicolas-grekas) + * bug #25200 [HttpKernel] Arrays with scalar values passed to ESI fragment renderer throw deprecation notice (Simperfit) + * bug #25217 [Dotenv] Changed preg_match flags from null to 0 (deekthesqueak) + * bug #25203 [DI] Fix infinite loop in InlineServiceDefinitionsPass (nicolas-grekas) + * bug #25185 [Serializer] Do not cache attributes if `attributes` in context (sroze) + * bug #25182 [HttpFoundation] AutExpireFlashBag should not clear new flashes (Simperfit, sroze) + * bug #25179 [FrameworkBundle][Serializer] Remove YamlEncoder definition if Yaml component isn't installed (ogizanagi) + * bug #25163 [DI] Fix tracking of env vars in exceptions (nicolas-grekas) + * bug #25152 [Form] Don't rely on `Symfony\Component\HttpFoundation\File\File` if http-foundation isn't in FileType (issei-m) + * bug #24987 [Console] Fix global console flag when used in chain (Simperfit) + * bug #25146 [DI] Dont resolve envs in service ids (nicolas-grekas) + * bug #25113 [Routing] Fix "config-file-relative" annotation loader resources (nicolas-grekas, sroze) + * bug #25109 Make debug:container search command case-insensitive (jzawadzki) + * bug #25043 [Yaml] added ability for substitute aliases when mapping is on single line (Michał Strzelecki, xabbuh) + * bug #25102 [Form] Fixed ContextErrorException in FileType (chihiro-adachi) + * bug #25130 [DI] Fix handling of inlined definitions by ContainerBuilder (nicolas-grekas) + * bug #25094 [FrameworkBundle][DX] Display a nice error message if an enabled component is missing (derrabus) + * bug #25097 [Bridge\PhpUnit] Turn "preserveGlobalState" to false by default, revert "Blacklist" removal (nicolas-grekas) + * bug #25072 [Bridge/PhpUnit] Remove trailing "\n" from ClockMock::microtime(false) (joky) + * bug #25032 [Bridge\PhpUnit] Disable broken auto-require mechanism of phpunit (nicolas-grekas) + * bug #24956 Fix ambiguous pattern (weltling) + * 3.3.13 (2017-11-16) * security #24995 Validate redirect targets using the session cookie domain (nicolas-grekas) From 4965ef5311c284aa4b5a23094239f976b836a99a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Dec 2017 14:26:28 -0800 Subject: [PATCH 74/74] updated VERSION for 3.3.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 711f410e0d654..d904460cf4f42 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -61,12 +61,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface private $projectDir; - const VERSION = '3.3.14-DEV'; + const VERSION = '3.3.14'; const VERSION_ID = 30314; const MAJOR_VERSION = 3; const MINOR_VERSION = 3; const RELEASE_VERSION = 14; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2018'; const END_OF_LIFE = '07/2018';