Merge branch '2.6' into 2.7
* 2.6: Marked the ResolveParameterPlaceHoldersPassTest as legacy [ExpressionLanguage] fixed issues when parsing postfix expressions remove unused code do not inline service factories resolve class parameters in service factories [Serializer] Fix object normalization exceptions Conflicts: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php
This commit is contained in:
commit
59ca5b3af9
@ -65,9 +65,6 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
|
||||
|
||||
$configurator = $this->inlineArguments($container, array($definition->getConfigurator()));
|
||||
$definition->setConfigurator($configurator[0]);
|
||||
|
||||
$factory = $this->inlineArguments($container, array($definition->getFactory()));
|
||||
$definition->setFactory($factory[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,13 @@ class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
|
||||
$definition->setFactoryClass($parameterBag->resolveValue($definition->getFactoryClass()));
|
||||
}
|
||||
|
||||
$factory = $definition->getFactory();
|
||||
|
||||
if (is_array($factory) && isset($factory[0])) {
|
||||
$factory[0] = $parameterBag->resolveValue($factory[0]);
|
||||
$definition->setFactory($factory);
|
||||
}
|
||||
|
||||
$calls = array();
|
||||
foreach ($definition->getMethodCalls() as $name => $arguments) {
|
||||
$calls[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($arguments);
|
||||
|
@ -237,6 +237,23 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($ref, $calls[0][1][0]);
|
||||
}
|
||||
|
||||
public function testProcessDoesNotInlineFactories()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo.factory')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('foo')
|
||||
->setFactory(array(new Reference('foo.factory'), 'getFoo'))
|
||||
;
|
||||
$this->process($container);
|
||||
|
||||
$factory = $container->getDefinition('foo')->getFactory();
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $factory[0]);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass()));
|
||||
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
class LegacyResolveParameterPlaceHoldersPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testFactoryClassParametersShouldBeResolved()
|
||||
{
|
||||
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
|
||||
|
||||
$compilerPass = new ResolveParameterPlaceHoldersPass();
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('foo.factory.class', 'FooFactory');
|
||||
$fooDefinition = $container->register('foo', '%foo.factory.class%');
|
||||
$fooDefinition->setFactoryClass('%foo.factory.class%');
|
||||
$compilerPass->process($container);
|
||||
$fooDefinition = $container->getDefinition('foo');
|
||||
|
||||
$this->assertSame('FooFactory', $fooDefinition->getFactoryClass());
|
||||
}
|
||||
}
|
@ -33,9 +33,9 @@ class ResolveParameterPlaceHoldersPassTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('Foo', $this->fooDefinition->getClass());
|
||||
}
|
||||
|
||||
public function testFactoryClassParametersShouldBeResolved()
|
||||
public function testFactoryParametersShouldBeResolved()
|
||||
{
|
||||
$this->assertSame('FooFactory', $this->fooDefinition->getFactoryClass());
|
||||
$this->assertSame(array('FooFactory', 'getFoo'), $this->fooDefinition->getFactory());
|
||||
}
|
||||
|
||||
public function testArgumentParametersShouldBeResolved()
|
||||
@ -78,7 +78,7 @@ class ResolveParameterPlaceHoldersPassTest extends \PHPUnit_Framework_TestCase
|
||||
$containerBuilder->setParameter('alias.id', 'bar');
|
||||
|
||||
$fooDefinition = $containerBuilder->register('foo', '%foo.class%');
|
||||
$fooDefinition->setFactoryClass('%foo.factory.class%');
|
||||
$fooDefinition->setFactory(array('%foo.factory.class%', 'getFoo'));
|
||||
$fooDefinition->setArguments(array('%foo.arg1%', '%foo.arg2%'));
|
||||
$fooDefinition->addMethodCall('%foo.method%', array('%foo.arg1%', '%foo.arg2%'));
|
||||
$fooDefinition->setProperty('%foo.property.name%', '%foo.property.value%');
|
||||
|
@ -25,12 +25,9 @@ class XmlDumperTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$dumper = new XmlDumper($container = new ContainerBuilder());
|
||||
$dumper = new XmlDumper(new ContainerBuilder());
|
||||
|
||||
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services1.xml', $dumper->dump(), '->dump() dumps an empty container as an empty XML file');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$dumper = new XmlDumper($container);
|
||||
}
|
||||
|
||||
public function testExportParameters()
|
||||
@ -155,4 +152,26 @@ class XmlDumperTest extends \PHPUnit_Framework_TestCase
|
||||
", include $fixturesPath.'/containers/container16.php'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideCompiledContainerData
|
||||
*/
|
||||
public function testCompiledContainerCanBeDumped($containerFile)
|
||||
{
|
||||
$fixturesPath = __DIR__.'/../Fixtures';
|
||||
$container = require $fixturesPath.'/containers/'.$containerFile.'.php';
|
||||
$container->compile();
|
||||
$dumper = new XmlDumper($container);
|
||||
$dumper->dump();
|
||||
}
|
||||
|
||||
public function provideCompiledContainerData()
|
||||
{
|
||||
return array(
|
||||
array('container8'),
|
||||
array('container11'),
|
||||
array('container12'),
|
||||
array('container14'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,14 @@ namespace Container14;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class ProjectServiceContainer extends ContainerBuilder
|
||||
{
|
||||
/**
|
||||
* This file is included in Tests\Dumper\GraphvizDumperTest::testDumpWithFrozenCustomClassContainer
|
||||
* and Tests\Dumper\XmlDumperTest::testCompiledContainerCanBeDumped.
|
||||
*/
|
||||
if (!class_exists('Container14\ProjectServiceContainer')) {
|
||||
class ProjectServiceContainer extends ContainerBuilder
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return new ProjectServiceContainer();
|
||||
|
@ -46,6 +46,7 @@ class ProjectServiceContainer extends Container
|
||||
'foo_bar' => 'getFooBarService',
|
||||
'foo_with_inline' => 'getFooWithInlineService',
|
||||
'method_call1' => 'getMethodCall1Service',
|
||||
'new_factory' => 'getNewFactoryService',
|
||||
'new_factory_service' => 'getNewFactoryServiceService',
|
||||
'request' => 'getRequestService',
|
||||
'service_from_static_method' => 'getServiceFromStaticMethodService',
|
||||
@ -264,10 +265,7 @@ class ProjectServiceContainer extends Container
|
||||
*/
|
||||
protected function getNewFactoryServiceService()
|
||||
{
|
||||
$a = new \FactoryClass();
|
||||
$a->foo = 'bar';
|
||||
|
||||
$this->services['new_factory_service'] = $instance = $a->getInstance();
|
||||
$this->services['new_factory_service'] = $instance = $this->get('new_factory')->getInstance();
|
||||
|
||||
$instance->foo = 'bar';
|
||||
|
||||
@ -300,6 +298,27 @@ class ProjectServiceContainer extends Container
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'new_factory' service.
|
||||
*
|
||||
* This service is shared.
|
||||
* This method always returns the same instance of the service.
|
||||
*
|
||||
* This service is private.
|
||||
* If you want to be able to request this service from the container directly,
|
||||
* make it public, otherwise you might end up with broken code.
|
||||
*
|
||||
* @return \FactoryClass A FactoryClass instance.
|
||||
*/
|
||||
protected function getNewFactoryService()
|
||||
{
|
||||
$this->services['new_factory'] = $instance = new \FactoryClass();
|
||||
|
||||
$instance->foo = 'bar';
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -314,12 +314,20 @@ class Parser
|
||||
if (
|
||||
$token->type !== Token::NAME_TYPE
|
||||
&&
|
||||
$token->type !== Token::NUMBER_TYPE
|
||||
&&
|
||||
// operators line "not" are valid method or property names
|
||||
($token->type !== Token::OPERATOR_TYPE && preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A', $token->value))
|
||||
// Operators like "not" and "matches" are valid method or property names,
|
||||
//
|
||||
// In other words, besides NAME_TYPE, OPERATOR_TYPE could also be parsed as a property or method.
|
||||
// This is because operators are processed by the lexer prior to names. So "not" in "foo.not()" or "matches" in "foo.matches" will be recognized as an operator first.
|
||||
// But in fact, "not" and "matches" in such expressions shall be parsed as method or property names.
|
||||
//
|
||||
// And this ONLY works if the operator consists of valid characters for a property or method name.
|
||||
//
|
||||
// Other types, such as STRING_TYPE and NUMBER_TYPE, can't be parsed as property nor method names.
|
||||
//
|
||||
// As a result, if $token is NOT an operator OR $token->value is NOT a valid property or method name, an exception shall be thrown.
|
||||
($token->type !== Token::OPERATOR_TYPE || !preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A', $token->value))
|
||||
) {
|
||||
throw new SyntaxError('Expected name or number', $token->cursor);
|
||||
throw new SyntaxError('Expected name', $token->cursor);
|
||||
}
|
||||
|
||||
$arg = new Node\ConstantNode($token->value);
|
||||
|
@ -161,4 +161,37 @@ class ParserTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
return new Node\GetAttrNode($node, new Node\ConstantNode($item), new Node\ArgumentsNode(), $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidPostfixData
|
||||
* @expectedException \Symfony\Component\ExpressionLanguage\SyntaxError
|
||||
*/
|
||||
public function testParseWithInvalidPostfixData($expr, $names = array())
|
||||
{
|
||||
$lexer = new Lexer();
|
||||
$parser = new Parser(array());
|
||||
$parser->parse($lexer->tokenize($expr), $names);
|
||||
}
|
||||
|
||||
public function getInvalidPostfixData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'foo."#"',
|
||||
array('foo'),
|
||||
),
|
||||
array(
|
||||
'foo."bar"',
|
||||
array('foo'),
|
||||
),
|
||||
array(
|
||||
'foo.**',
|
||||
array('foo'),
|
||||
),
|
||||
array(
|
||||
'foo.123',
|
||||
array('foo'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
@ -68,6 +69,10 @@ class PropertyNormalizer extends AbstractNormalizer
|
||||
$attributeValue = call_user_func($this->callbacks[$property->name], $attributeValue);
|
||||
}
|
||||
if (null !== $attributeValue && !is_scalar($attributeValue)) {
|
||||
if (!$this->serializer instanceof NormalizerInterface) {
|
||||
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $property->name));
|
||||
}
|
||||
|
||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
||||
}
|
||||
|
||||
|
@ -350,6 +350,22 @@ class PropertyNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\PropertyDummy')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\LogicException
|
||||
* @expectedExceptionMessage Cannot normalize attribute "bar" because injected serializer is not a normalizer
|
||||
*/
|
||||
public function testUnableToNormalizeObjectAttribute()
|
||||
{
|
||||
$serializer = $this->getMock('Symfony\Component\Serializer\SerializerInterface');
|
||||
$this->normalizer->setSerializer($serializer);
|
||||
|
||||
$obj = new PropertyDummy();
|
||||
$object = new \stdClass();
|
||||
$obj->setBar($object);
|
||||
|
||||
$this->normalizer->normalize($obj, 'any');
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyDummy
|
||||
|
Reference in New Issue
Block a user