From 7b920c1ec52a9777fcde927acd1def17b07a5a64 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 3 Oct 2018 13:47:42 +0200 Subject: [PATCH 01/21] fix multi-digit seconds fraction handling --- .../Core/DataTransformer/DateTimeToRfc3339Transformer.php | 2 +- .../Core/DataTransformer/DateTimeToRfc3339TransformerTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php index 8d1a92af8b..59e3a765d5 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php @@ -69,7 +69,7 @@ class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer return; } - if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) { + if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) { throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $rfc3339)); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php index 5f4043523e..dc1633b844 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php @@ -67,6 +67,7 @@ class DateTimeToRfc3339TransformerTest extends TestCase array('UTC', 'UTC', '2010-02-03 04:05:00 UTC', '2010-02-03T04:05Z'), array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:00 America/New_York', '2010-02-03T17:05+08:00'), array('Europe/Amsterdam', 'Europe/Amsterdam', '2013-08-21 10:30:00 Europe/Amsterdam', '2013-08-21T08:30:00Z'), + array('UTC', 'UTC', '2018-10-03T10:00:00.000Z', '2018-10-03T10:00:00.000Z'), )); } From a7f0cffd33584372c89851375f64607448dfd910 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 3 Oct 2018 14:03:24 +0200 Subject: [PATCH 02/21] updated CHANGELOG for 3.4.17 --- CHANGELOG-3.4.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index 64cf429f3f..803e9bf627 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,15 @@ in 3.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.4.0...v3.4.1 +* 3.4.17 (2018-10-03) + + * bug #28604 [Finder] fixed root directory access for ftp/sftp wrapper (DerDu) + * bug #28688 [FWBundle] Throw if PropertyInfo is enabled, but the component isn't installed (dunglas) + * bug #28648 [PHPUnitBridge] Fix ClockMock microtime() format (acasademont) + * bug #28678 [DI] fix dumping setters before their inlined instances (nicolas-grekas) + * bug #28672 [DI] fix error in dumped container (nicolas-grekas) + * bug #28664 [Console] Don't return early as this bypasses the auto exit feature (duncan3dc) + * 3.4.16 (2018-09-30) * bug #28376 [TwigBundle] Fixed caching of templates in src/Resources//views on cache warmup (yceruto) From bf23505b927db28b68872ec731e85c9ae340f2f6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 3 Oct 2018 14:03:34 +0200 Subject: [PATCH 03/21] updated VERSION for 3.4.17 --- 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 f001134324..a285911dd5 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.17-DEV'; + const VERSION = '3.4.17'; const VERSION_ID = 30417; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; const RELEASE_VERSION = 17; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 155fab6e6fb31391682d138cc7ffedf016478d90 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 3 Oct 2018 14:49:59 +0200 Subject: [PATCH 04/21] bumped Symfony version to 3.4.18 --- 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 a285911dd5..2e9d751091 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.17'; - const VERSION_ID = 30417; + const VERSION = '3.4.18-DEV'; + const VERSION_ID = 30418; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 17; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 18; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From b662e7eaf2410c809c03032efc259ab578902cf5 Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Thu, 4 Oct 2018 10:48:17 +0200 Subject: [PATCH 05/21] Correct PHPDoc type for float ttl It can be null as the Lock instance accepts it. --- src/Symfony/Component/Lock/Factory.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Lock/Factory.php b/src/Symfony/Component/Lock/Factory.php index e9fdde97e8..f35ad6d8ef 100644 --- a/src/Symfony/Component/Lock/Factory.php +++ b/src/Symfony/Component/Lock/Factory.php @@ -36,9 +36,9 @@ class Factory implements LoggerAwareInterface /** * Creates a lock for the given resource. * - * @param string $resource The resource to lock - * @param float $ttl Maximum expected lock duration in seconds - * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + * @param string $resource The resource to lock + * @param float|null $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed * * @return Lock */ From d64bd3b181f83752fae66c1da96a4eead8017872 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 2 Oct 2018 18:52:16 +0200 Subject: [PATCH 06/21] [Process] fix locking of pipe files on Windows --- .../Component/Process/Pipes/WindowsPipes.php | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index f81f65faca..0b2a76387f 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -28,6 +28,7 @@ class WindowsPipes extends AbstractPipes { private $files = array(); private $fileHandles = array(); + private $lockHandles = array(); private $readBytes = array( Process::STDOUT => 0, Process::STDERR => 0, @@ -47,31 +48,33 @@ class WindowsPipes extends AbstractPipes Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR, ); - $tmpCheck = false; $tmpDir = sys_get_temp_dir(); $lastError = 'unknown reason'; set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); - if (file_exists($file) && !unlink($file)) { - continue 2; - } - $h = fopen($file, 'xb'); - if (!$h) { - $error = $lastError; - if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) { - continue; - } + + if (!$h = fopen($file.'.lock', 'w')) { restore_error_handler(); - throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error)); + throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $lastError)); } - if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) { + if (!flock($h, LOCK_EX | LOCK_NB)) { continue 2; } - if (isset($this->files[$pipe])) { - unlink($this->files[$pipe]); + if (isset($this->lockHandles[$pipe])) { + flock($this->lockHandles[$pipe], LOCK_UN); + fclose($this->lockHandles[$pipe]); } + $this->lockHandles[$pipe] = $h; + + if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) { + flock($this->lockHandles[$pipe], LOCK_UN); + fclose($this->lockHandles[$pipe]); + unset($this->lockHandles[$pipe]); + continue 2; + } + $this->fileHandles[$pipe] = $h; $this->files[$pipe] = $file; } break; @@ -85,7 +88,6 @@ class WindowsPipes extends AbstractPipes public function __destruct() { $this->close(); - $this->removeFiles(); } /** @@ -145,8 +147,11 @@ class WindowsPipes extends AbstractPipes $read[$type] = $data; } if ($close) { + ftruncate($fileHandle, 0); fclose($fileHandle); - unset($this->fileHandles[$type]); + flock($this->lockHandles[$type], LOCK_UN); + fclose($this->lockHandles[$type]); + unset($this->fileHandles[$type], $this->lockHandles[$type]); } } @@ -167,10 +172,13 @@ class WindowsPipes extends AbstractPipes public function close() { parent::close(); - foreach ($this->fileHandles as $handle) { + foreach ($this->fileHandles as $type => $handle) { + ftruncate($handle, 0); fclose($handle); + flock($this->lockHandles[$type], LOCK_UN); + fclose($this->lockHandles[$type]); } - $this->fileHandles = array(); + $this->fileHandles = $this->lockHandles = array(); } /** @@ -185,17 +193,4 @@ class WindowsPipes extends AbstractPipes { return new static($process->isOutputDisabled(), $input); } - - /** - * Removes temporary files. - */ - private function removeFiles() - { - foreach ($this->files as $filename) { - if (file_exists($filename)) { - @unlink($filename); - } - } - $this->files = array(); - } } From 0683f0ac82f46a72c24fafb69713a4b6cf6bd7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 5 Oct 2018 13:29:17 +0200 Subject: [PATCH 07/21] [FWBundle] Automatically enable PropertyInfo when using Flex --- .../FrameworkBundle/DependencyInjection/Configuration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 7f47411d0b..92ae0b8147 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -21,6 +21,7 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Form\Form; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; +use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Translation\Translator; @@ -823,7 +824,7 @@ class Configuration implements ConfigurationInterface ->children() ->arrayNode('property_info') ->info('Property info configuration') - ->canBeEnabled() + ->{!class_exists(FullStack::class) && class_exists(PropertyInfoExtractor::class) ? 'canBeDisabled' : 'canBeEnabled'}() ->end() ->end() ; From b0253e58ea136aeab6fabb13de63aef4ea1af8e1 Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov Date: Fri, 5 Oct 2018 17:13:57 +0300 Subject: [PATCH 08/21] Replace deprecated validateValue with validate --- .../Component/Validator/Context/ExecutionContextInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index d38d33747a..548a4db1c1 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -88,7 +88,7 @@ interface ExecutionContextInterface extends LegacyExecutionContextInterface * { * $validator = $this->context->getValidator(); * - * $violations = $validator->validateValue($value, new Length(array('min' => 3))); + * $violations = $validator->validate($value, new Length(array('min' => 3))); * * if (count($violations) > 0) { * // ... From d3a43e0297876ea0debc2599365be87e1000d885 Mon Sep 17 00:00:00 2001 From: mweimerskirch <362092+mweimerskirch@users.noreply.github.com> Date: Fri, 5 Oct 2018 17:41:17 +0200 Subject: [PATCH 09/21] Added LB translation for #27993 (UUID validator message translation) --- .../Validator/Resources/translations/validators.lb.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index 4a06dbd45b..bdbc9da09c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -318,6 +318,10 @@ Error Feeler + + This is not a valid UUID. + Dëst ass keng gëlteg UUID. + From 545a8eef05e2d406bccc0c362bc0cf30a3af00b9 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Thu, 4 Oct 2018 20:06:57 +0200 Subject: [PATCH 10/21] [EventDispatcher] Remove template method in test case --- .../Component/EventDispatcher/Tests/GenericEventTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php index 9cf68c987f..b63f69df14 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php @@ -31,8 +31,6 @@ class GenericEventTest extends TestCase */ protected function setUp() { - parent::setUp(); - $this->subject = new \stdClass(); $this->event = new GenericEvent($this->subject, array('name' => 'Event')); } @@ -44,8 +42,6 @@ class GenericEventTest extends TestCase { $this->subject = null; $this->event = null; - - parent::tearDown(); } public function testConstruct() From 7196e49f7e20fae51fa4700a0de00283956e9640 Mon Sep 17 00:00:00 2001 From: mschop Date: Wed, 3 Oct 2018 20:15:00 +0200 Subject: [PATCH 11/21] Fix phpdocs See https://github.com/phan/phan/issues/2025 for explaination --- .../Component/Console/Command/Command.php | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index dc6fa509ad..796224b6a6 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -363,10 +363,12 @@ class Command /** * Adds an argument. * - * @param string $name The argument name - * @param int $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL - * @param string $description A description text - * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) + * @param string $name The argument name + * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param string $description A description text + * @param string|string[]|null $default The default value (for self::OPTIONAL mode only) + * + * @throws InvalidArgumentException When argument mode is not valid * * @return $this */ @@ -380,11 +382,13 @@ class Command /** * Adds an option. * - * @param string $name The option name - * @param string $shortcut The shortcut (can be null) - * @param int $mode The option mode: One of the InputOption::VALUE_* constants - * @param string $description A description text - * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) + * @param string $name The option name + * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int|null $mode The option mode: One of the VALUE_* constants + * @param string $description A description text + * @param string|string[]|bool|null $default The default value (must be null for self::VALUE_NONE) + * + * @throws InvalidArgumentException If option mode is invalid or incompatible * * @return $this */ From a854b0a01cedb5299c32e962ece55cf326de03e7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 5 Oct 2018 22:38:23 +0200 Subject: [PATCH 12/21] [DI] fix dumping inline services again --- .../DependencyInjection/Dumper/PhpDumper.php | 52 +++-- .../Tests/Dumper/PhpDumperTest.php | 34 ++++ .../Tests/Fixtures/containers/container19.php | 7 +- .../Tests/Fixtures/php/services19.php | 104 +++++++++- .../Tests/Fixtures/php/services_adawson.php | 184 ++++++++++++++++++ .../Fixtures/php/services_inline_self_ref.php | 78 ++++++++ .../Tests/Fixtures/yaml/services_adawson.yml | 28 +++ 7 files changed, 453 insertions(+), 34 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 541a540583..ce55ecf073 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -503,10 +503,6 @@ EOF; } } - if (false !== strpos($this->dumpLiteralClass($this->dumpValue($definition->getClass())), '$')) { - return false; - } - return true; } @@ -598,18 +594,16 @@ EOF; $return = array(); if ($class = $definition->getClass()) { - $class = $this->container->resolveEnvPlaceholders($class); + $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class); $return[] = sprintf(0 === strpos($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\')); } elseif ($definition->getFactory()) { $factory = $definition->getFactory(); if (\is_string($factory)) { $return[] = sprintf('@return object An instance returned by %s()', $factory); } elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) { - if (\is_string($factory[0]) || $factory[0] instanceof Reference) { - $return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]); - } elseif ($factory[0] instanceof Definition) { - $return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]); - } + $class = $factory[0] instanceof Definition ? $factory[0]->getClass() : (string) $factory[0]; + $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class); + $return[] = sprintf('@return object An instance returned by %s::%s()', $class, $factory[1]); } } @@ -704,7 +698,7 @@ EOF; if (\is_array($argument)) { $hasSelfRef = $this->addInlineVariables($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef; } elseif ($argument instanceof Reference) { - $hasSelfRef = $this->addInlineReference($head, $tail, $id, $this->container->normalizeId($argument), $forConstructor) || $hasSelfRef; + $hasSelfRef = $this->addInlineReference($head, $id, $this->container->normalizeId($argument), $forConstructor) || $hasSelfRef; } elseif ($argument instanceof Definition) { $hasSelfRef = $this->addInlineService($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef; } @@ -713,37 +707,31 @@ EOF; return $hasSelfRef; } - private function addInlineReference(&$head, &$tail, $id, $targetId, $forConstructor) + private function addInlineReference(&$code, $id, $targetId, $forConstructor) { + $hasSelfRef = isset($this->circularReferences[$id][$targetId]); + if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) { - return isset($this->circularReferences[$id][$targetId]); + return $hasSelfRef; } list($callCount, $behavior) = $this->serviceCalls[$targetId]; - if (2 > $callCount && (!$forConstructor || !isset($this->circularReferences[$id][$targetId]))) { - return isset($this->circularReferences[$id][$targetId]); + if (2 > $callCount && (!$hasSelfRef || !$forConstructor)) { + return $hasSelfRef; } $name = $this->getNextVariableName(); $this->referenceVariables[$targetId] = new Variable($name); $reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId, $behavior) : null; - $code = sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference)); + $code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference)); - if (!isset($this->circularReferences[$id][$targetId])) { - $head .= $code; - - return false; + if (!$hasSelfRef || !$forConstructor) { + return $hasSelfRef; } - if (!$forConstructor) { - $tail .= $code; - - return true; - } - - $head .= $code.sprintf(<<<'EOTXT' + $code .= sprintf(<<<'EOTXT' if (isset($this->%s['%s'])) { return $this->%1$s['%2$s']; @@ -766,7 +754,7 @@ EOTXT $arguments = array($definition->getArguments(), $definition->getFactory()); - if (2 > $this->inlinedDefinitions[$definition] && !$definition->getMethodCalls() && !$definition->getProperties() && !$definition->getConfigurator() && false === strpos($this->dumpValue($definition->getClass()), '$')) { + if (2 > $this->inlinedDefinitions[$definition] && !$definition->getMethodCalls() && !$definition->getProperties() && !$definition->getConfigurator()) { return $this->addInlineVariables($head, $tail, $id, $arguments, $forConstructor); } @@ -774,9 +762,13 @@ EOTXT $this->definitionVariables[$definition] = new Variable($name); $code = ''; - $hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, $forConstructor); + if ($forConstructor) { + $hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, $forConstructor); + } else { + $hasSelfRef = $this->addInlineVariables($code, $code, $id, $arguments, $forConstructor); + } $code .= $this->addNewInstance($definition, '$'.$name, ' = ', $id); - $hasSelfRef ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= ('' !== $head ? "\n" : '').$code; + $hasSelfRef && !$forConstructor ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= ('' !== $head ? "\n" : '').$code; $code = ''; $arguments = array($definition->getProperties(), $definition->getMethodCalls(), $definition->getConfigurator()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 25761d28b0..3ffcf0dc0a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -863,6 +863,28 @@ class PhpDumperTest extends TestCase $this->assertEquals((object) array('p2' => (object) array('p3' => (object) array())), $container->get('foo')->bClone); } + public function testInlineSelfRef() + { + $container = new ContainerBuilder(); + + $bar = (new Definition('App\Bar')) + ->setProperty('foo', new Reference('App\Foo')); + + $baz = (new Definition('App\Baz')) + ->setProperty('bar', $bar) + ->addArgument($bar); + + $container->register('App\Foo') + ->setPublic(true) + ->addArgument($baz); + + $passConfig = $container->getCompiler()->getPassConfig(); + $container->compile(); + + $dumper = new PhpDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_self_ref.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Inline_Self_Ref'))); + } + public function testHotPathOptimizations() { $container = include self::$fixturesPath.'/containers/container_inline_requires.php'; @@ -940,6 +962,18 @@ class PhpDumperTest extends TestCase $this->assertEquals((object) array('foo' => (object) array(123)), $container->get('bar')); } + public function testAdawsonContainer() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('services_adawson.yml'); + $container->compile(); + + $dumper = new PhpDumper($container); + $dump = $dumper->dump(); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump()); + } + /** * @group legacy * @expectedDeprecation The "private" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php index 823a77f534..300a5cc769 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php @@ -7,9 +7,12 @@ require_once __DIR__.'/../includes/classes.php'; $container = new ContainerBuilder(); +$container->setParameter('env(FOO)', 'Bar\FaooClass'); +$container->setParameter('foo', '%env(FOO)%'); + $container - ->register('service_from_anonymous_factory', 'Bar\FooClass') - ->setFactory(array(new Definition('Bar\FooClass'), 'getInstance')) + ->register('service_from_anonymous_factory', '%foo%') + ->setFactory(array(new Definition('%foo%'), 'getInstance')) ->setPublic(true) ; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php index 667dd852a0..1092363fd3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php @@ -21,6 +21,8 @@ class ProjectServiceContainer extends Container public function __construct() { + $this->parameters = $this->getDefaultParameters(); + $this->services = array(); $this->methodMap = array( 'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService', @@ -58,11 +60,11 @@ class ProjectServiceContainer extends Container /** * Gets the public 'service_from_anonymous_factory' shared service. * - * @return \Bar\FooClass + * @return object A %env(FOO)% instance */ protected function getServiceFromAnonymousFactoryService() { - return $this->services['service_from_anonymous_factory'] = (new \Bar\FooClass())->getInstance(); + return $this->services['service_from_anonymous_factory'] = (new ${($_ = $this->getEnv('FOO')) && false ?: "_"}())->getInstance(); } /** @@ -78,4 +80,102 @@ class ProjectServiceContainer extends Container return $instance; } + + public function getParameter($name) + { + $name = (string) $name; + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + $name = $this->normalizeParameterName($name); + + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + 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]; + } + + public function hasParameter($name) + { + $name = (string) $name; + $name = $this->normalizeParameterName($name); + + return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); + } + + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + 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( + 'foo' => false, + ); + 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) + { + switch ($name) { + case 'foo': $value = $this->getEnv('FOO'); break; + default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); + } + $this->loadedDynamicParameters[$name] = true; + + return $this->dynamicParameters[$name] = $value; + } + + private $normalizedParameterNames = array( + 'env(foo)' => 'env(FOO)', + ); + + private function normalizeParameterName($name) + { + if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { + $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; + if ((string) $name !== $normalizedName) { + @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); + } + } else { + $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; + } + + return $normalizedName; + } + + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'env(FOO)' => 'Bar\\FaooClass', + ); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php new file mode 100644 index 0000000000..8e9e65ad98 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php @@ -0,0 +1,184 @@ +services = array(); + $this->normalizedIds = array( + 'app\\bus' => 'App\\Bus', + 'app\\db' => 'App\\Db', + 'app\\handler1' => 'App\\Handler1', + 'app\\handler2' => 'App\\Handler2', + 'app\\processor' => 'App\\Processor', + 'app\\registry' => 'App\\Registry', + 'app\\schema' => 'App\\Schema', + ); + $this->methodMap = array( + 'App\\Bus' => 'getBusService', + 'App\\Db' => 'getDbService', + 'App\\Handler1' => 'getHandler1Service', + 'App\\Handler2' => 'getHandler2Service', + 'App\\Processor' => 'getProcessorService', + 'App\\Registry' => 'getRegistryService', + 'App\\Schema' => 'getSchemaService', + ); + $this->privates = array( + 'App\\Handler1' => true, + 'App\\Handler2' => true, + 'App\\Processor' => true, + 'App\\Registry' => true, + 'App\\Schema' => true, + ); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'App\\Handler1' => true, + 'App\\Handler2' => true, + 'App\\Processor' => true, + 'App\\Registry' => true, + 'App\\Schema' => true, + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } + + /** + * Gets the public 'App\Bus' shared service. + * + * @return \App\Bus + */ + protected function getBusService() + { + $this->services['App\Bus'] = $instance = new \App\Bus(${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}); + + $instance->handler1 = ${($_ = isset($this->services['App\Handler1']) ? $this->services['App\Handler1'] : $this->getHandler1Service()) && false ?: '_'}; + $instance->handler2 = ${($_ = isset($this->services['App\Handler2']) ? $this->services['App\Handler2'] : $this->getHandler2Service()) && false ?: '_'}; + + return $instance; + } + + /** + * Gets the public 'App\Db' shared service. + * + * @return \App\Db + */ + protected function getDbService() + { + $this->services['App\Db'] = $instance = new \App\Db(); + + $instance->schema = ${($_ = isset($this->services['App\Schema']) ? $this->services['App\Schema'] : $this->getSchemaService()) && false ?: '_'}; + + return $instance; + } + + /** + * Gets the private 'App\Handler1' shared service. + * + * @return \App\Handler1 + */ + protected function getHandler1Service() + { + $a = ${($_ = isset($this->services['App\Processor']) ? $this->services['App\Processor'] : $this->getProcessorService()) && false ?: '_'}; + + if (isset($this->services['App\Handler1'])) { + return $this->services['App\Handler1']; + } + + return $this->services['App\Handler1'] = new \App\Handler1(${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\Schema']) ? $this->services['App\Schema'] : $this->getSchemaService()) && false ?: '_'}, $a); + } + + /** + * Gets the private 'App\Handler2' shared service. + * + * @return \App\Handler2 + */ + protected function getHandler2Service() + { + return $this->services['App\Handler2'] = new \App\Handler2(${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\Schema']) ? $this->services['App\Schema'] : $this->getSchemaService()) && false ?: '_'}, ${($_ = isset($this->services['App\Processor']) ? $this->services['App\Processor'] : $this->getProcessorService()) && false ?: '_'}); + } + + /** + * Gets the private 'App\Processor' shared service. + * + * @return \App\Processor + */ + protected function getProcessorService() + { + $a = ${($_ = isset($this->services['App\Registry']) ? $this->services['App\Registry'] : $this->getRegistryService()) && false ?: '_'}; + + if (isset($this->services['App\Processor'])) { + return $this->services['App\Processor']; + } + + return $this->services['App\Processor'] = new \App\Processor($a, ${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}); + } + + /** + * Gets the private 'App\Registry' shared service. + * + * @return \App\Registry + */ + protected function getRegistryService() + { + $this->services['App\Registry'] = $instance = new \App\Registry(); + + $instance->processor = array(0 => ${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}, 1 => ${($_ = isset($this->services['App\Bus']) ? $this->services['App\Bus'] : $this->getBusService()) && false ?: '_'}); + + return $instance; + } + + /** + * Gets the private 'App\Schema' shared service. + * + * @return \App\Schema + */ + protected function getSchemaService() + { + $a = ${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}; + + if (isset($this->services['App\Schema'])) { + return $this->services['App\Schema']; + } + + return $this->services['App\Schema'] = new \App\Schema($a); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php new file mode 100644 index 0000000000..5cb1002fea --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php @@ -0,0 +1,78 @@ +services = array(); + $this->normalizedIds = array( + 'app\\foo' => 'App\\Foo', + ); + $this->methodMap = array( + 'App\\Foo' => 'getFooService', + ); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } + + /** + * Gets the public 'App\Foo' shared service. + * + * @return \App\Foo + */ + protected function getFooService() + { + $b = new \App\Bar(); + $a = new \App\Baz($b); + + $this->services['App\Foo'] = $instance = new \App\Foo($a); + + $b->foo = $instance; + + $a->bar = $b; + + return $instance; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml new file mode 100644 index 0000000000..2a26f38a83 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml @@ -0,0 +1,28 @@ +services: + App\Db: + public: true + properties: + schema: '@App\Schema' + + App\Bus: + public: true + arguments: ['@App\Db'] + properties: + handler1: '@App\Handler1' + handler2: '@App\Handler2' + + App\Handler1: + ['@App\Db', '@App\Schema', '@App\Processor'] + + App\Handler2: + ['@App\Db', '@App\Schema', '@App\Processor'] + + App\Processor: + ['@App\Registry', '@App\Db'] + + App\Registry: + properties: + processor: ['@App\Db', '@App\Bus'] + + App\Schema: + arguments: ['@App\Db'] From 3b99a0d8237b382147390ff2c92e1fcff0f77fc3 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 8 Oct 2018 10:07:11 +0200 Subject: [PATCH 13/21] [FrameworkBundle] Fix 3.4 tests --- .../FrameworkBundle/DependencyInjection/Configuration.php | 4 ++-- .../Tests/DependencyInjection/ConfigurationTest.php | 2 +- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 6 ------ 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 92ae0b8147..4ad140e6c6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -21,7 +21,7 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Form\Form; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; -use Symfony\Component\PropertyInfo\PropertyInfoExtractor; +use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Translation\Translator; @@ -824,7 +824,7 @@ class Configuration implements ConfigurationInterface ->children() ->arrayNode('property_info') ->info('Property info configuration') - ->{!class_exists(FullStack::class) && class_exists(PropertyInfoExtractor::class) ? 'canBeDisabled' : 'canBeEnabled'}() + ->{!class_exists(FullStack::class) && interface_exists(PropertyInfoExtractorInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}() ->end() ->end() ; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 0c0167630d..d3317809aa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -335,7 +335,7 @@ class ConfigurationTest extends TestCase 'throw_exception_on_invalid_index' => false, ), 'property_info' => array( - 'enabled' => false, + 'enabled' => !class_exists(FullStack::class), ), 'router' => array( 'enabled' => false, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 06e709c5ca..38420ac1e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -979,12 +979,6 @@ abstract class FrameworkExtensionTest extends TestCase $this->assertFalse($container->hasDefinition('serializer')); } - public function testPropertyInfoDisabled() - { - $container = $this->createContainerFromFile('default_config'); - $this->assertFalse($container->has('property_info')); - } - public function testPropertyInfoEnabled() { $container = $this->createContainerFromFile('property_info'); From 9d70e22794027908c2afb2029a4c62dad25526a5 Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Mon, 8 Oct 2018 13:49:05 +0100 Subject: [PATCH 14/21] [Validator] Add a missing translation --- .../Validator/Resources/translations/validators.pl.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index f33274e6e6..51a76eefc1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -318,6 +318,10 @@ Error Błąd + + This is not a valid UUID. + To nie jest poprawne UUID. + From 5a51bb24dce5e30a18553d190237694de4cf0045 Mon Sep 17 00:00:00 2001 From: Florent Viel Date: Mon, 8 Oct 2018 15:32:18 +0200 Subject: [PATCH 15/21] Fix class documentation The phpdoc references the PHP flush function, neither a method of this class nor its parent. --- src/Symfony/Component/HttpFoundation/StreamedResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index ed1c5ff3ec..44f654aef6 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -17,7 +17,7 @@ namespace Symfony\Component\HttpFoundation; * A StreamedResponse uses a callback for its content. * * The callback should use the standard PHP functions like echo - * to stream the response back to the client. The flush() method + * to stream the response back to the client. The flush() function * can also be used if needed. * * @see flush() From 5094d3e288f47d4e1929954c347ed713c70bae6d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 8 Oct 2018 23:49:21 +0200 Subject: [PATCH 16/21] fix command description --- .../Bundle/WebServerBundle/Command/ServerStatusCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php index 9759228f5b..907f69f1c4 100644 --- a/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php +++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php @@ -39,7 +39,7 @@ class ServerStatusCommand extends ServerCommand new InputOption('pidfile', null, InputOption::VALUE_REQUIRED, 'PID file'), new InputOption('filter', null, InputOption::VALUE_REQUIRED, 'The value to display (one of port, host, or address)'), )) - ->setDescription('Outputs the status of the local web server for the given address') + ->setDescription('Outputs the status of the local web server') ->setHelp(<<<'EOF' %command.name% shows the details of the given local web server, such as the address and port where it is listening to: From 03dbd84f7d0987dbd0eef6cfdddd4febe5171c0e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 9 Oct 2018 10:07:08 +0200 Subject: [PATCH 17/21] add missing cache prefix seed attribute to XSD --- .../FrameworkBundle/Resources/config/schema/symfony-1.0.xsd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 7c270685fb..1feb77bba8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -249,6 +249,8 @@ + + From aee63f5e4b058af7beb28f9642e1f52f9322d3dc Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 9 Oct 2018 13:19:40 +0200 Subject: [PATCH 18/21] invalidate stale commits for PRs too --- .github/rm-invalid-lowest-lock-files.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php index 3105942a09..c036fd356f 100644 --- a/.github/rm-invalid-lowest-lock-files.php +++ b/.github/rm-invalid-lowest-lock-files.php @@ -104,8 +104,7 @@ foreach ($composerJsons as list($dir, $lockedPackages)) { } } -if (!$referencedCommits || (isset($_SERVER['TRAVIS_PULL_REQUEST']) && 'false' !== $_SERVER['TRAVIS_PULL_REQUEST'])) { - // cached commits cannot be stale for PRs +if (!$referencedCommits) { return; } From 95dce676290340231464108cbeee32e51779fd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20P=C3=A9cro?= Date: Sun, 29 Jul 2018 20:56:37 +0200 Subject: [PATCH 19/21] [Security] Do not deauthenticate user when the first refreshed user has changed --- .../Http/Firewall/ContextListener.php | 22 +++++++++++++++---- .../Tests/Firewall/ContextListenerTest.php | 9 ++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 4c250a7773..cdaebbca75 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -161,6 +161,7 @@ class ContextListener implements ListenerInterface } $userNotFoundByProvider = false; + $userDeauthenticated = false; foreach ($this->userProviders as $provider) { if (!$provider instanceof UserProviderInterface) { @@ -169,21 +170,26 @@ class ContextListener implements ListenerInterface try { $refreshedUser = $provider->refreshUser($user); - $token->setUser($refreshedUser); + $newToken = unserialize(serialize($token)); + $newToken->setUser($refreshedUser); // tokens can be deauthenticated if the user has been changed. - if (!$token->isAuthenticated()) { + if (!$newToken->isAuthenticated()) { if ($this->logoutOnUserChange) { + $userDeauthenticated = true; + if (null !== $this->logger) { - $this->logger->debug('Token was deauthenticated after trying to refresh it.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider))); + $this->logger->debug('Cannot refresh token because user has changed.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider))); } - return null; + continue; } @trigger_error('Refreshing a deauthenticated user is deprecated as of 3.4 and will trigger a logout in 4.0.', E_USER_DEPRECATED); } + $token->setUser($refreshedUser); + if (null !== $this->logger) { $context = array('provider' => \get_class($provider), 'username' => $refreshedUser->getUsername()); @@ -209,6 +215,14 @@ class ContextListener implements ListenerInterface } } + if ($userDeauthenticated) { + if (null !== $this->logger) { + $this->logger->debug('Token was deauthenticated after trying to refresh it.'); + } + + return null; + } + if ($userNotFoundByProvider) { return null; } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index f4e2ae7f72..bb49d03961 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -273,6 +273,15 @@ class ContextListenerTest extends TestCase $this->assertNull($tokenStorage->getToken()); } + public function testIfTokenIsNotDeauthenticated() + { + $tokenStorage = new TokenStorage(); + $badRefreshedUser = new User('foobar', 'baz'); + $goodRefreshedUser = new User('foobar', 'bar'); + $this->handleEventWithPreviousSession($tokenStorage, array(new SupportingUserProvider($badRefreshedUser), new SupportingUserProvider($goodRefreshedUser)), $goodRefreshedUser, true); + $this->assertSame($goodRefreshedUser, $tokenStorage->getToken()->getUser()); + } + public function testTryAllUserProvidersUntilASupportingUserProviderIsFound() { $tokenStorage = new TokenStorage(); From 7743146e55a7c157390b1bc838052fc076be1e3f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 9 Oct 2018 18:27:41 +0200 Subject: [PATCH 20/21] do not override custom access decision configs --- .../DependencyInjection/MainConfiguration.php | 4 +--- .../CompleteConfigurationTest.php | 15 ++++++++++++-- ...ess_decision_manager_customized_config.php | 20 +++++++++++++++++++ ...ess_decision_manager_customized_config.xml | 18 +++++++++++++++++ ...ess_decision_manager_customized_config.yml | 11 ++++++++++ 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index daeeb6fbd9..6cdb9deb8f 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -66,9 +66,7 @@ class MainConfiguration implements ConfigurationInterface return false; }) ->then(function ($v) { - $v['access_decision_manager'] = array( - 'strategy' => AccessDecisionManager::STRATEGY_AFFIRMATIVE, - ); + $v['access_decision_manager']['strategy'] = AccessDecisionManager::STRATEGY_AFFIRMATIVE; return $v; }) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index d2f7e2c60e..15b43bede9 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -555,11 +555,22 @@ abstract class CompleteConfigurationTest extends TestCase /** * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException - * @expectedExceptionMessage "strategy" and "service" cannot be used together. + * @expectedExceptionMessage Invalid configuration for path "security.access_decision_manager": "strategy" and "service" cannot be used together. */ public function testAccessDecisionManagerServiceAndStrategyCannotBeUsedAtTheSameTime() { - $container = $this->getContainer('access_decision_manager_service_and_strategy'); + $this->getContainer('access_decision_manager_service_and_strategy'); + } + + public function testAccessDecisionManagerOptionsAreNotOverriddenByImplicitStrategy() + { + $container = $this->getContainer('access_decision_manager_customized_config'); + + $accessDecisionManagerDefinition = $container->getDefinition('security.access.decision_manager'); + + $this->assertSame(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $accessDecisionManagerDefinition->getArgument(1)); + $this->assertTrue($accessDecisionManagerDefinition->getArgument(2)); + $this->assertFalse($accessDecisionManagerDefinition->getArgument(3)); } /** diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php new file mode 100644 index 0000000000..cd3cc12000 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php @@ -0,0 +1,20 @@ +loadFromExtension('security', array( + 'access_decision_manager' => array( + 'allow_if_all_abstain' => true, + 'allow_if_equal_granted_denied' => false, + ), + 'providers' => array( + 'default' => array( + 'memory' => array( + 'users' => array( + 'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER'), + ), + ), + ), + ), + 'firewalls' => array( + 'simple' => array('pattern' => '/login', 'security' => false), + ), +)); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml new file mode 100644 index 0000000000..22123dfa21 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml new file mode 100644 index 0000000000..a8d044f1de --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml @@ -0,0 +1,11 @@ +security: + access_decision_manager: + allow_if_all_abstain: true + allow_if_equal_granted_denied: false + providers: + default: + memory: + users: + foo: { password: foo, roles: ROLE_USER } + firewalls: + simple: { pattern: /login, security: false } From 06295442d1485d06f9013d16c9fdfccbcda2af47 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 Sep 2018 17:51:10 +0200 Subject: [PATCH 21/21] Added the Code of Conduct file --- CODE_OF_CONDUCT.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..d211dd419d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,83 @@ +Code of Conduct +=============== + +Our Pledge +---------- + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnic origin, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal appearance, +religion, or sexual identity and orientation. + +Our Standards +------------- + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +Our Responsibilities +-------------------- + +[CoC Active Response Ensurers, or CARE][1], are responsible for clarifying the +standards of acceptable behavior and are expected to take appropriate and fair +corrective action in response to any instances of unacceptable behavior. + +CARE team members have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. + +Scope +----- + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by CARE team members. + +Enforcement +----------- + +Instances of abusive, harassing, or otherwise unacceptable behavior +[may be reported][2] by contacting the [CARE team members][1]. +All complaints will be reviewed and investigated and will result in a response +that is deemed necessary and appropriate to the circumstances. The CARE team is +obligated to maintain confidentiality with regard to the reporter of an +incident. Further details of specific enforcement policies may be posted +separately. + +CARE team members who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by the +[core team][3]. + +Attribution +----------- + +This Code of Conduct is adapted from the [Contributor Covenant version 1.4][4]. + +[1]: https://symfony.com/doc/current/contributing/code_of_conduct/care_team.html +[2]: https://symfony.com/doc/current/contributing/code_of_conduct/reporting_guidelines.html +[3]: https://symfony.com/doc/current/contributing/code/core_team.html +[4]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html