diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0070353a71..0bef5105c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -994,6 +994,8 @@ class Configuration implements ConfigurationInterface ->fixXmlConfig('resource') ->children() ->arrayNode('resources') + ->normalizeKeys(false) + ->useAttributeAsKey('name') ->requiresAtLeastOneElement() ->defaultValue(['default' => [class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphore' : 'flock']]) ->beforeNormalization() @@ -1016,6 +1018,7 @@ class Configuration implements ConfigurationInterface }) ->end() ->prototype('array') + ->performNoDeepMerging() ->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end() ->prototype('scalar')->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 3ba4c3ecfe..0e5ff1881d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -235,6 +235,34 @@ class ConfigurationTest extends TestCase yield [['enabled' => false, 'resource' => [['name' => 'foo', 'value' => 'flock'], ['name' => 'foo', 'value' => 'semaphore'], ['name' => 'bar', 'value' => 'semaphore']]], ['enabled' => false, 'resources' => ['foo' => ['flock', 'semaphore'], 'bar' => ['semaphore']]]]; } + public function testLockMergeConfigs() + { + $processor = new Processor(); + $configuration = new Configuration(true); + $config = $processor->processConfiguration($configuration, [ + [ + 'lock' => [ + 'payload' => 'flock', + ], + ], + [ + 'lock' => [ + 'payload' => 'semaphore', + ], + ], + ]); + + $this->assertEquals( + [ + 'enabled' => true, + 'resources' => [ + 'payload' => ['semaphore'], + ], + ], + $config['lock'] + ); + } + public function testItShowANiceMessageIfTwoMessengerBusesAreConfiguredButNoDefaultBus() { $expectedMessage = 'You must specify the "default_bus" if you define more than one bus.'; diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 6ef9159c23..1a9c6bbefb 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -166,7 +166,7 @@ class FormType extends BaseType // For any form that is not represented by a single HTML control, // errors should bubble up by default $errorBubbling = function (Options $options) { - return $options['compound']; + return $options['compound'] && !$options['inherit_data']; }; // If data is given, the form is locked to that data diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 4879850217..a10d407a66 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -518,6 +518,16 @@ class FormTypeTest extends BaseTypeTest $this->assertTrue($form->getConfig()->getErrorBubbling()); } + public function testErrorBubblingForCompoundFieldsIsDisabledByDefaultIfInheritDataIsEnabled() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'compound' => true, + 'inherit_data' => true, + ]); + + $this->assertFalse($form->getConfig()->getErrorBubbling()); + } + public function testPropertyPath() { $form = $this->factory->create(static::TESTED_TYPE, null, [ @@ -735,6 +745,28 @@ class FormTypeTest extends BaseTypeTest $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['help_translation_parameters']); } + + public function testErrorBubblingDoesNotSkipCompoundFieldsWithInheritDataConfigured() + { + $form = $this->factory->createNamedBuilder('form', self::TESTED_TYPE) + ->add( + $this->factory->createNamedBuilder('inherit_data_type', self::TESTED_TYPE, null, [ + 'inherit_data' => true, + ]) + ->add('child', self::TESTED_TYPE, [ + 'compound' => false, + 'error_bubbling' => true, + ]) + ) + ->getForm(); + $error = new FormError('error message'); + $form->get('inherit_data_type')->get('child')->addError($error); + + $this->assertCount(0, $form->getErrors()); + $this->assertCount(1, $form->get('inherit_data_type')->getErrors()); + $this->assertSame($error, $form->get('inherit_data_type')->getErrors()[0]); + $this->assertCount(0, $form->get('inherit_data_type')->get('child')->getErrors()); + } } class Money diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index cb4051d3a0..0f46b78350 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -410,7 +410,7 @@ class PropertyAccessor implements PropertyAccessorInterface if (__FILE__ === $trace['file'] && $name === $trace['function'] && $object instanceof $trace['class'] - && preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches) + && preg_match('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/', $e->getMessage(), $matches) ) { throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $name, $matches[1]), 0, $e); } diff --git a/src/Symfony/Component/Yaml/Dumper.php b/src/Symfony/Component/Yaml/Dumper.php index 5dec10945c..2de07d0231 100644 --- a/src/Symfony/Component/Yaml/Dumper.php +++ b/src/Symfony/Component/Yaml/Dumper.php @@ -72,10 +72,23 @@ class Dumper // If the first line starts with a space character, the spec requires a blockIndicationIndicator // http://www.yaml.org/spec/1.2/spec.html#id2793979 $blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : ''; - $output .= sprintf('%s%s%s |%s-', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator); + + if (isset($value[-2]) && "\n" === $value[-2] && "\n" === $value[-1]) { + $blockChompingIndicator = '+'; + } elseif ("\n" === $value[-1]) { + $blockChompingIndicator = ''; + } else { + $blockChompingIndicator = '-'; + } + + $output .= sprintf('%s%s%s |%s%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator, $blockChompingIndicator); foreach (explode("\n", $value) as $row) { - $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); + if ('' === $row) { + $output .= "\n"; + } else { + $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); + } } continue; diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index ef449a4dfd..5bf0530220 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -567,7 +567,7 @@ YAML; ], 4, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); } - public function testNoTrailingNewlineWhenDumpingAsMultiLineLiteralBlock() + public function testNoExtraTrailingNewlineWhenDumpingAsMultiLineLiteralBlock() { $data = [ "a\nb", @@ -579,6 +579,44 @@ YAML; $this->assertSame($data, Yaml::parse($yaml)); } + public function testDumpTrailingNewlineInMultiLineLiteralBlocks() + { + $data = [ + 'clip 1' => "one\ntwo\n", + 'clip 2' => "one\ntwo\n", + 'keep 1' => "one\ntwo\n", + 'keep 2' => "one\ntwo\n\n", + 'strip 1' => "one\ntwo", + 'strip 2' => "one\ntwo", + ]; + $yaml = $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); + + $expected = <<assertSame($expected, $yaml); + $this->assertSame($data, Yaml::parse($yaml)); + } + public function testZeroIndentationThrowsException() { $this->expectException('InvalidArgumentException'); diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block.yml index 8c43bd4754..1f61eb1216 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block.yml @@ -8,7 +8,7 @@ data: integer like line: 123456789 empty line: - + baz multi_line_with_carriage_return: "foo\nbar\r\nbaz" nested_inlined_multi_line_string: { inlined_multi_line: "foo\nbar\r\nempty line:\n\nbaz" }