Skip to content

Commit 1897ea0

Browse files
committed
Merge branch '3.4' into 4.0
* 3.4: [HttpKernel] Fix race condition when clearing old containers [DI] Fix infinite loop in InlineServiceDefinitionsPass [HttpKernel] Keep legacy container files for concurrent requests Do not cache cache attributes if `attributes` is in the context Test that it do not remove the new flashes when displaying the existing ones [HttpFoundation] AutExpireFlashBag should not clear new flashes [FrameworkBundle][Serializer] Remove YamlEncoder definition if Yaml component isn't installed [DI] Fix tracking of env vars in exceptions [Form] Don't rely on if http-foundation isn't in FileType Fix merge substitute aliases in inline mappings added ability for substitute aliases when mapping in YAML is on single line [Console] Fix global console flag when used in chain
2 parents d2496ab + 5cb6c93 commit 1897ea0

File tree

17 files changed

+208
-32
lines changed

17 files changed

+208
-32
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
use Symfony\Component\WebLink\HttpHeaderSerializer;
7575
use Symfony\Component\Workflow;
7676
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
77+
use Symfony\Component\Yaml\Yaml;
7778

7879
/**
7980
* FrameworkExtension.
@@ -1159,6 +1160,10 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
11591160
$container->removeDefinition('serializer.normalizer.object');
11601161
}
11611162

1163+
if (!class_exists(Yaml::class)) {
1164+
$container->removeDefinition('serializer.encoder.yaml');
1165+
}
1166+
11621167
$serializerLoaders = array();
11631168
if (isset($config['enable_annotations']) && $config['enable_annotations']) {
11641169
if (!$this->annotationsConfigEnabled) {

src/Symfony/Component/Console/Input/ArgvInput.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ public function hasParameterOption($values, $onlyParams = false)
280280
if ($token === $value || 0 === strpos($token, $value.'=')) {
281281
return true;
282282
}
283+
284+
if (0 === strpos($token, '-') && 0 !== strpos($token, '--')) {
285+
$searchableToken = str_replace('-', '', $token);
286+
$searchableValue = str_replace('-', '', $value);
287+
if ('' !== $searchableToken && '' !== $searchableValue && false !== strpos($searchableToken, $searchableValue)) {
288+
return true;
289+
}
290+
}
283291
}
284292
}
285293

src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ public function testHasParameterOption()
314314
$input = new ArgvInput(array('cli.php', '-f', 'foo'));
315315
$this->assertTrue($input->hasParameterOption('-f'), '->hasParameterOption() returns true if the given short option is in the raw input');
316316

317+
$input = new ArgvInput(array('cli.php', '-fh'));
318+
$this->assertTrue($input->hasParameterOption('-fh'), '->hasParameterOption() returns true if the given short option is in the raw input');
319+
317320
$input = new ArgvInput(array('cli.php', '--foo', 'foo'));
318321
$this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input');
319322

src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ protected function processValue($value, $isRoot = false)
4747
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
4848
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
4949

50-
if ($definition->isShared()) {
51-
return $definition;
52-
}
53-
$value = clone $definition;
50+
return $definition->isShared() ? $definition : clone $definition;
5451
}
5552
}
5653

src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,26 @@ public function process(ContainerBuilder $container)
5656
}
5757
$config = $resolvingBag->resolveValue($config);
5858

59-
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
60-
$tmpContainer->setResourceTracking($container->isTrackingResources());
61-
$tmpContainer->addObjectResource($extension);
62-
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
63-
$tmpContainer->addObjectResource($configuration);
64-
}
59+
try {
60+
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
61+
$tmpContainer->setResourceTracking($container->isTrackingResources());
62+
$tmpContainer->addObjectResource($extension);
63+
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
64+
$tmpContainer->addObjectResource($configuration);
65+
}
6566

66-
foreach ($exprLangProviders as $provider) {
67-
$tmpContainer->addExpressionLanguageProvider($provider);
68-
}
67+
foreach ($exprLangProviders as $provider) {
68+
$tmpContainer->addExpressionLanguageProvider($provider);
69+
}
6970

70-
$extension->load($config, $tmpContainer);
71+
$extension->load($config, $tmpContainer);
72+
} catch (\Exception $e) {
73+
if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
74+
$container->getParameterBag()->mergeEnvPlaceholders($resolvingBag);
75+
}
76+
77+
throw $e;
78+
}
7179

7280
if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
7381
// don't keep track of env vars that are *overridden* when configs are merged

src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,25 @@ public function testProcessDoesInlineNonSharedService()
9292
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
9393
}
9494

95+
public function testProcessInlinesMixedServicesLoop()
96+
{
97+
$container = new ContainerBuilder();
98+
$container
99+
->register('foo')
100+
->addArgument(new Reference('bar'))
101+
->setShared(false)
102+
;
103+
$container
104+
->register('bar')
105+
->setPublic(false)
106+
->addMethodCall('setFoo', array(new Reference('foo')))
107+
;
108+
109+
$this->process($container);
110+
111+
$this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
112+
}
113+
95114
public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition()
96115
{
97116
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,26 @@ public function testProcessedEnvsAreIncompatibleWithResolve()
110110
{
111111
$container = new ContainerBuilder();
112112
$container->registerExtension(new BarExtension());
113-
$container->prependExtensionConfig('bar', array());
113+
$container->prependExtensionConfig('bar', []);
114114

115115
(new MergeExtensionConfigurationPass())->process($container);
116116
}
117+
118+
public function testThrowingExtensionsGetMergedBag()
119+
{
120+
$container = new ContainerBuilder();
121+
$container->registerExtension(new ThrowingExtension());
122+
$container->prependExtensionConfig('throwing', array('bar' => '%env(FOO)%'));
123+
124+
try {
125+
$pass = new MergeExtensionConfigurationPass();
126+
$pass->process($container);
127+
$this->fail('An exception should have been thrown.');
128+
} catch (\Exception $e) {
129+
}
130+
131+
$this->assertSame(array('FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders()));
132+
}
117133
}
118134

119135
class FooConfiguration implements ConfigurationInterface
@@ -163,3 +179,21 @@ public function load(array $configs, ContainerBuilder $container)
163179
$container->resolveEnvPlaceholders('%env(int:FOO)%', true);
164180
}
165181
}
182+
183+
class ThrowingExtension extends Extension
184+
{
185+
public function getAlias()
186+
{
187+
return 'throwing';
188+
}
189+
190+
public function getConfiguration(array $config, ContainerBuilder $container)
191+
{
192+
return new FooConfiguration();
193+
}
194+
195+
public function load(array $configs, ContainerBuilder $container)
196+
{
197+
throw new \Exception();
198+
}
199+
}

src/Symfony/Component/Form/Extension/Core/Type/FileType.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,12 @@ public function finishView(FormView $view, FormInterface $form, array $options)
9292
*/
9393
public function configureOptions(OptionsResolver $resolver)
9494
{
95-
$dataClass = function (Options $options) {
96-
return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File';
97-
};
95+
$dataClass = null;
96+
if (class_exists('Symfony\Component\HttpFoundation\File\File')) {
97+
$dataClass = function (Options $options) {
98+
return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File';
99+
};
100+
}
98101

99102
$emptyData = function (Options $options) {
100103
return $options['multiple'] ? array() : null;

src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function get($type, array $default = array())
106106
public function all()
107107
{
108108
$return = $this->flashes['display'];
109-
$this->flashes = array('new' => array(), 'display' => array());
109+
$this->flashes['display'] = array();
110110

111111
return $return;
112112
}

src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,12 @@ public function testClear()
150150
{
151151
$this->assertEquals(array('notice' => array('A previous flash message')), $this->bag->clear());
152152
}
153+
154+
public function testDoNotRemoveTheNewFlashesWhenDisplayingTheExistingOnes()
155+
{
156+
$this->bag->add('success', 'Something');
157+
$this->bag->all();
158+
159+
$this->assertEquals(array('new' => array('success' => array('Something')), 'display' => array()), $this->array);
160+
}
153161
}

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,17 @@ protected function initializeContainer()
515515
}
516516

517517
if ($oldContainer && get_class($this->container) !== $oldContainer->name) {
518-
(new Filesystem())->remove(dirname($oldContainer->getFileName()));
518+
// Because concurrent requests might still be using them,
519+
// old container files are not removed immediately,
520+
// but on a next dump of the container.
521+
$oldContainerDir = dirname($oldContainer->getFileName());
522+
foreach (glob(dirname($oldContainerDir).'/*.legacyContainer') as $legacyContainer) {
523+
if ($oldContainerDir.'.legacyContainer' !== $legacyContainer && @unlink($legacyContainer)) {
524+
(new Filesystem())->remove(substr($legacyContainer, 0, -16));
525+
}
526+
}
527+
528+
touch($oldContainerDir.'.legacyContainer');
519529
}
520530

521531
if ($this->container->has('cache_warmer')) {

src/Symfony/Component/HttpKernel/Tests/KernelTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ public function testKernelReset()
520520
$kernel->boot();
521521

522522
$this->assertTrue(get_class($kernel->getContainer()) !== $containerClass);
523-
$this->assertFileNotExists($containerFile);
523+
$this->assertFileExists($containerFile);
524+
$this->assertFileExists(dirname($containerFile).'.legacyContainer');
524525
}
525526

526527
public function testKernelPass()

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ protected function getAttributes($object, $format = null, array $context)
129129
return $allowedAttributes;
130130
}
131131

132+
if (isset($context['attributes'])) {
133+
return $this->extractAttributes($object, $format, $context);
134+
}
135+
132136
if (isset($this->attributesCache[$class])) {
133137
return $this->attributesCache[$class];
134138
}

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,37 @@ public function testAttributesContextDenormalizeConstructor()
723723
'inner' => array('foo' => 'foo', 'bar' => 'bar'),
724724
), DummyWithConstructorObjectAndDefaultValue::class, null, $context));
725725
}
726+
727+
public function testNormalizeSameObjectWithDifferentAttributes()
728+
{
729+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
730+
$this->normalizer = new ObjectNormalizer($classMetadataFactory);
731+
$serializer = new Serializer(array($this->normalizer));
732+
$this->normalizer->setSerializer($serializer);
733+
734+
$dummy = new ObjectOuter();
735+
$dummy->foo = new ObjectInner();
736+
$dummy->foo->foo = 'foo.foo';
737+
$dummy->foo->bar = 'foo.bar';
738+
739+
$dummy->bar = new ObjectInner();
740+
$dummy->bar->foo = 'bar.foo';
741+
$dummy->bar->bar = 'bar.bar';
742+
743+
$this->assertEquals(array(
744+
'foo' => array(
745+
'bar' => 'foo.bar',
746+
),
747+
'bar' => array(
748+
'foo' => 'bar.foo',
749+
),
750+
), $this->normalizer->normalize($dummy, 'json', array(
751+
'attributes' => array(
752+
'foo' => array('bar'),
753+
'bar' => array('foo'),
754+
),
755+
)));
756+
}
726757
}
727758

728759
class ObjectDummy

src/Symfony/Component/Yaml/Inline.php

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
402402
$output = array();
403403
$len = strlen($mapping);
404404
++$i;
405+
$allowOverwrite = false;
405406

406407
// {foo: bar, bar:foo, ...}
407408
while ($i < $len) {
@@ -443,6 +444,10 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
443444
throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
444445
}
445446

447+
if ('<<' === $key) {
448+
$allowOverwrite = true;
449+
}
450+
446451
while ($i < $len) {
447452
if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
448453
++$i;
@@ -458,7 +463,18 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
458463
// Spec: Keys MUST be unique; first one wins.
459464
// Parser cannot abort this mapping earlier, since lines
460465
// are processed sequentially.
461-
if (isset($output[$key])) {
466+
// But overwriting is allowed when a merge node is used in current block.
467+
if ('<<' === $key) {
468+
foreach ($value as $parsedValue) {
469+
$output += $parsedValue;
470+
}
471+
} elseif ($allowOverwrite || !isset($output[$key])) {
472+
if (null !== $tag) {
473+
$output[$key] = new TaggedValue($tag, $value);
474+
} else {
475+
$output[$key] = $value;
476+
}
477+
} elseif (isset($output[$key])) {
462478
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
463479
}
464480
break;
@@ -468,7 +484,16 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
468484
// Spec: Keys MUST be unique; first one wins.
469485
// Parser cannot abort this mapping earlier, since lines
470486
// are processed sequentially.
471-
if (isset($output[$key])) {
487+
// But overwriting is allowed when a merge node is used in current block.
488+
if ('<<' === $key) {
489+
$output += $value;
490+
} elseif ($allowOverwrite || !isset($output[$key])) {
491+
if (null !== $tag) {
492+
$output[$key] = new TaggedValue($tag, $value);
493+
} else {
494+
$output[$key] = $value;
495+
}
496+
} elseif (isset($output[$key])) {
472497
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
473498
}
474499
break;
@@ -477,18 +502,20 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
477502
// Spec: Keys MUST be unique; first one wins.
478503
// Parser cannot abort this mapping earlier, since lines
479504
// are processed sequentially.
480-
if (isset($output[$key])) {
505+
// But overwriting is allowed when a merge node is used in current block.
506+
if ('<<' === $key) {
507+
$output += $value;
508+
} elseif ($allowOverwrite || !isset($output[$key])) {
509+
if (null !== $tag) {
510+
$output[$key] = new TaggedValue($tag, $value);
511+
} else {
512+
$output[$key] = $value;
513+
}
514+
} elseif (isset($output[$key])) {
481515
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
482516
}
483517
--$i;
484518
}
485-
486-
if (null !== $tag && '' !== $tag) {
487-
$output[$key] = new TaggedValue($tag, $value);
488-
} else {
489-
$output[$key] = $value;
490-
}
491-
492519
++$i;
493520

494521
continue 2;

src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ yaml: |
2121
c:
2222
foo: bar
2323
bar: foo
24+
bar_inline: {a: before, d: other, <<: *foo, b: new, x: Oren, c: { foo: bar, bar: foo}}
2425
foo2: &foo2
2526
a: Ballmer
2627
ding: &dong [ fi, fei, fo, fam]
@@ -42,14 +43,19 @@ yaml: |
4243
p: 12345
4344
z:
4445
<<: *nestedref
46+
head_inline: &head_inline { <<: [ *foo , *dong , *foo2 ] }
47+
recursive_inline: { <<: *head_inline, c: { <<: *foo2 } }
4548
php: |
4649
array(
4750
'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'),
4851
'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'),
52+
'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'e' => 'notnull', 'x' => 'Oren'),
4953
'foo2' => array('a' => 'Ballmer'),
5054
'ding' => array('fi', 'fei', 'fo', 'fam'),
5155
'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'),
5256
'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
5357
'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)),
54-
'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345))
58+
'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)),
59+
'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
60+
'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
5561
)

0 commit comments

Comments
 (0)