Merge branch '3.3' into 3.4

* 3.3:
  [DI] Fix infinite loop in InlineServiceDefinitionsPass
  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
This commit is contained in:
Christian Flothmann 2017-11-29 14:28:14 +01:00
commit f74ecedd0b
15 changed files with 195 additions and 35 deletions

View File

@ -76,6 +76,7 @@ use Symfony\Component\Validator\ObjectInitializerInterface;
use Symfony\Component\WebLink\HttpHeaderSerializer;
use Symfony\Component\Workflow;
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
use Symfony\Component\Yaml\Yaml;
/**
* FrameworkExtension.
@ -1442,6 +1443,10 @@ class FrameworkExtension extends Extension
$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) {

View File

@ -285,6 +285,14 @@ class ArgvInput extends Input
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;
}
}
}
}

View File

@ -314,6 +314,9 @@ class ArgvInputTest extends TestCase
$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');

View File

@ -65,10 +65,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
$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;
}
}

View File

@ -56,18 +56,26 @@ class MergeExtensionConfigurationPass implements CompilerPassInterface
}
$config = $resolvingBag->resolveValue($config);
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
$tmpContainer->setResourceTracking($container->isTrackingResources());
$tmpContainer->addObjectResource($extension);
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
$tmpContainer->addObjectResource($configuration);
}
try {
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $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

View File

@ -92,6 +92,25 @@ class InlineServiceDefinitionsPassTest extends TestCase
$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();

View File

@ -110,10 +110,26 @@ class MergeExtensionConfigurationPassTest extends TestCase
{
$container = new ContainerBuilder();
$container->registerExtension(new BarExtension());
$container->prependExtensionConfig('bar', array());
$container->prependExtensionConfig('bar', []);
(new MergeExtensionConfigurationPass())->process($container);
}
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
@ -163,3 +179,21 @@ class BarExtension extends Extension
$container->resolveEnvPlaceholders('%env(int:FOO)%', true);
}
}
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();
}
}

View File

@ -92,9 +92,12 @@ class FileType extends AbstractType
*/
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;

View File

@ -106,7 +106,7 @@ class AutoExpireFlashBag implements FlashBagInterface
public function all()
{
$return = $this->flashes['display'];
$this->flashes = array('new' => array(), 'display' => array());
$this->flashes['display'] = array();
return $return;
}

View File

@ -150,4 +150,12 @@ class AutoExpireFlashBagTest extends TestCase
{
$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);
}
}

View File

@ -129,6 +129,10 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
return $allowedAttributes;
}
if (isset($context['attributes'])) {
return $this->extractAttributes($object, $format, $context);
}
if (isset($this->attributesCache[$class])) {
return $this->attributesCache[$class];
}

View File

@ -723,6 +723,37 @@ class ObjectNormalizerTest extends TestCase
'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

View File

@ -478,6 +478,7 @@ class Inline
$output = array();
$len = strlen($mapping);
++$i;
$allowOverwrite = false;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
@ -518,6 +519,10 @@ class Inline
@trigger_error(self::getDeprecationMessage('Using a colon after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since version 3.2 and will throw a ParseException in 4.0.'), E_USER_DEPRECATED);
}
if ('<<' === $key) {
$allowOverwrite = true;
}
while ($i < $len) {
if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
++$i;
@ -526,7 +531,6 @@ class Inline
}
$tag = self::parseTag($mapping, $i, $flags);
$duplicate = false;
switch ($mapping[$i]) {
case '[':
// nested sequence
@ -534,9 +538,19 @@ class Inline
// 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])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
$duplicate = true;
}
break;
case '{':
@ -545,9 +559,17 @@ class Inline
// 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])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
$duplicate = true;
}
break;
default:
@ -555,20 +577,20 @@ class Inline
// 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])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
$duplicate = true;
}
--$i;
}
if (!$duplicate) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
}
++$i;
continue 2;

View File

@ -21,6 +21,7 @@ yaml: |
c:
foo: bar
bar: foo
bar_inline: {a: before, d: other, <<: *foo, b: new, x: Oren, c: { foo: bar, bar: foo}}
foo2: &foo2
a: Ballmer
ding: &dong [ fi, fei, fo, fam]
@ -42,14 +43,19 @@ 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'), 'e' => 'notnull', 'x' => 'Oren'),
'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', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
)

View File

@ -2046,6 +2046,18 @@ YAML;
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Reference "foo" does not exist
*/
public function testEvalRefException()
{
$yaml = <<<EOE
foo: { &foo { a: Steve, <<: *foo} }
EOE;
$this->parser->parse($yaml);
}
}
class B