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 56857de63c49..4498bd167ca7 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 8964f10789be..a6e7c35d148f 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 bece3e59752a..d94836b85b78 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 1c10366cee41..40371d9307cd 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 676987e64121..418aa3200cc1 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 7933dd91d48d..c66ce0f028d3 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 82b2082f33e1..42f7b916f6ed 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 3a444fd350ed..20fad5347aed 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 4ce814a53847..233a6fe2f3fe 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 acb43283967c..00c1c4d6e480 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 371e8c464e7a..7ac65a77371f 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 f78633744e12..b1ba60fd65ed 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 fe42e8d13a52..626c310af437 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 1aab5ee0da4a..3e0993a126f0 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 b1ba60fd65ed..466e01b172ec 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 3e0993a126f0..0bfec287a98b 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 c5aa20930fc3..711f410e0d65 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 8964f10789be..84f2cca7c34f 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 f476b5ef7313..7d49ad3dd4ec 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 c2f533eb3679..4493a5bafc3b 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 1fe21d0f6c1a..85fb533715b6 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 000000000000..09ff256decc1 --- /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 b114c69c5176..498919c09991 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 ac358dd4bed8..728ab1913dfe 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 a265a129e6fd..1197ab050b0b 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 d338ca9d5752..21e0aba17d35 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 1c8a7027bcab..202e141f36c2 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 09ff256decc1..abfd3172580b 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 728ab1913dfe..f7e34e048b95 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 1197ab050b0b..8e85feaa3426 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 8ffa8ccf6494..93b2fca4d71b 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 59f612514170..a37eca2e3cd7 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 9be278f67ec9..97ce0cac0f77 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 9ff9b89c1c12..31a0514fd497 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 93b2fca4d71b..8ffa8ccf6494 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 a37eca2e3cd7..499446c10cb7 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 000000000000..9165d31f24a1 --- /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 368a5a80a148..571db0eb41df 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 f68efe25cfe5..37e1c99a7450 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 e6360e449889..3d7b45d5064a 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 000000000000..f4070998e72b --- /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 f51881a092c9..243ef89f312c 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 fe5cd851258d..8bfb9a621118 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 f067b4bbe20b..f263c15d4532 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 53e1a8dc31db..86f4cdd5ae0a 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 6f60a5c762f7..f03cdf343024 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 abfd3172580b..000000000000 --- 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 498919c09991..5bc4a29a7e25 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 f7e34e048b95..889642636cdc 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 8e85feaa3426..a265a129e6fd 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 3af6c2a83bc1..e51cf8876145 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 86f4cdd5ae0a..b6783d0ba5d4 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 b6783d0ba5d4..cb572db26693 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 5bc4a29a7e25..9d662d0d8ab3 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 889642636cdc..5843192b3c13 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 9d662d0d8ab3..655687575d24 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 5843192b3c13..b30eaa14538d 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 cb572db26693..c0ffe8ddef9e 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 2617163523a4..cb0a53d5d607 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 65ea1c842c04..59f8cc7d0dcb 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 f4274b80a444..32e1b99adb25 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 0ecdea3fbfb8..92db8f3c5ebf 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 fc5b1aae6832..cff7adf1bb2c 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 5d6fe1e20d66..646470ff5abf 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 84863a2fb824..15da037be786 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 de3e84823dea..c3aee4e6fd35 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 21d1e6d3c997..a9c5663eecca 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 616d01ef4cda..4574a0201c0c 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 87a60d419707..f0ca2f5b048e 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 3a65e1d0537d..5bfb109adbed 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 78cec4be2a15..1e8ee394015e 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 a8a652c7a231..435d97e3daf3 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 8e44008317c2..f42107c6f7fd 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 d60072b7551e..6c0cf4f1b6a6 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 473d5667d448..d47303e85138 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 665a0b25d77d..8b905746b2e4 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 0d734cb4c222..44e172fed2c7 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 000000000000..4699f41011a4 --- /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 000000000000..d7f2ea626aa8 --- /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 ddd5cae0bc3c..7d84512d9b3c 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 c3b4d78dd622..491e2c48589d 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 44d1933a80fa..7f4583a16c95 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 cb0a53d5d607..8b21f6c644a5 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 59ba309005b3..0ed660097437 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 18b71a5021fb..0e0724a3249a 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 68e86da1f21e..29eab6f1ca8b 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 b2d7b872f4d9..9407fdf52d7b 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 f2ef363c837c..ff9ac315b0af 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 26b24fa71324..09e491366478 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 e955cd0d43c6..9526908a3785 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 bfe922e22c76..7099b4d7e8bf 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 1b61c352238f..2efc4df740d8 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 b1bfc214837a..5adaa8b79429 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 910a1622f303..dde92f46af5b 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 29f002b8cc1a..5fdae442dcda 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 5399c66010a8..1f588db82cae 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 053b1d4a6b33..aaed8221c1fc 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 2efc0c4d4a21..e3c76349648e 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 a27c81dd495a..ad00a502a0f7 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 c7b3a4365b51..39274c6c8d05 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 e2fbb48ce033..e11daf183134 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 ccabdc968fb2..0ac832ee0610 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 5093d7cd1297..702df16f0aec 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 f98ac7f51c97..7a3c40571432 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 360ec5a8d9e8..96761f51f2c2 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 3b6de4d41258..be15967dcbd8 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 000000000000..714fdb9e98f5 --- /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 f4070998e72b..3bbc97f041a2 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 f4070998e72b..adba4a5a1ad7 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 14b6e4428e55..c4d6d837c6a7 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 b30eaa14538d..110e57d32138 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 a27c81dd495a..eb0f6d057dce 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 d1b7980faa8a..39c73dc0c3d9 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 4aca4cc354e4..0920a1aa5e18 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 839c9f21d9fe..670f71dfc176 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 dc7bec9fb6cc..af9e65892392 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 702df16f0aec..a6e39007dfe0 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 7a3c40571432..1d35ecc1bd81 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 ff9ac315b0af..8eb6e94d2469 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 09e491366478..365c16c2d2c9 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 6977d4df9afa..70012e3dc7c1 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 aaed8221c1fc..e101704efaa9 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 6e6274dcc493..beed1c95b3a1 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 9fa0a22ea31c..6ac1846a5d41 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 6ac1846a5d41..2d1d03c5e6d2 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 110e57d32138..b3f302cd340b 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 310284444011..eeb42846f5f5 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 711f410e0d65..d904460cf4f4 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'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy