Merge branch '2.7' into 2.8

* 2.7:
  [Form] Fixed ContextErrorException in FileType
  [DI] Fix handling of inlined definitions by ContainerBuilder
This commit is contained in:
Nicolas Grekas 2017-11-23 11:48:23 +01:00
commit 10ec39e850
5 changed files with 80 additions and 21 deletions

View File

@ -460,7 +460,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$this->loading[$id] = true; $this->loading[$id] = true;
try { try {
$service = $this->createService($definition, $id); $service = $this->createService($definition, new \SplObjectStorage(), $id);
} catch (\Exception $e) { } catch (\Exception $e) {
unset($this->loading[$id]); unset($this->loading[$id]);
@ -846,8 +846,12 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* *
* @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
*/ */
public function createService(Definition $definition, $id, $tryProxy = true) public function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true)
{ {
if (null === $id && isset($inlinedDefinitions[$definition])) {
return $inlinedDefinitions[$definition];
}
if ($definition instanceof DefinitionDecorator) { if ($definition instanceof DefinitionDecorator) {
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id)); throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
} }
@ -868,11 +872,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
->instantiateProxy( ->instantiateProxy(
$container, $container,
$definition, $definition,
$id, function () use ($definition, $id, $container) { $id, function () use ($definition, $inlinedDefinitions, $id, $container) {
return $container->createService($definition, $id, false); return $container->createService($definition, $inlinedDefinitions, $id, false);
} }
); );
$this->shareService($definition, $proxy, $id); $this->shareService($definition, $proxy, $id, $inlinedDefinitions);
return $proxy; return $proxy;
} }
@ -883,11 +887,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
require_once $parameterBag->resolveValue($definition->getFile()); require_once $parameterBag->resolveValue($definition->getFile());
} }
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))); $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions);
if (null !== $factory = $definition->getFactory()) { if (null !== $factory = $definition->getFactory()) {
if (is_array($factory)) { if (is_array($factory)) {
$factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]); $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]);
} elseif (!is_string($factory)) { } elseif (!is_string($factory)) {
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
} }
@ -923,16 +927,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($tryProxy || !$definition->isLazy()) { if ($tryProxy || !$definition->isLazy()) {
// share only if proxying failed, or if not a proxy // share only if proxying failed, or if not a proxy
$this->shareService($definition, $service, $id); $this->shareService($definition, $service, $id, $inlinedDefinitions);
} }
$properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); $properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions);
foreach ($properties as $name => $value) { foreach ($properties as $name => $value) {
$service->$name = $value; $service->$name = $value;
} }
foreach ($definition->getMethodCalls() as $call) { foreach ($definition->getMethodCalls() as $call) {
$this->callMethod($service, $call); $this->callMethod($service, $call, $inlinedDefinitions);
} }
if ($callable = $definition->getConfigurator()) { if ($callable = $definition->getConfigurator()) {
@ -942,7 +946,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($callable[0] instanceof Reference) { if ($callable[0] instanceof Reference) {
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior()); $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
} elseif ($callable[0] instanceof Definition) { } elseif ($callable[0] instanceof Definition) {
$callable[0] = $this->createService($callable[0], null); $callable[0] = $this->createService($callable[0], $inlinedDefinitions);
} }
} }
@ -965,15 +969,20 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* the real service instances and all expressions evaluated * the real service instances and all expressions evaluated
*/ */
public function resolveServices($value) public function resolveServices($value)
{
return $this->doResolveServices($value, new \SplObjectStorage());
}
private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions)
{ {
if (is_array($value)) { if (is_array($value)) {
foreach ($value as $k => $v) { foreach ($value as $k => $v) {
$value[$k] = $this->resolveServices($v); $value[$k] = $this->doResolveServices($v, $inlinedDefinitions);
} }
} elseif ($value instanceof Reference) { } elseif ($value instanceof Reference) {
$value = $this->get((string) $value, $value->getInvalidBehavior()); $value = $this->get((string) $value, $value->getInvalidBehavior());
} elseif ($value instanceof Definition) { } elseif ($value instanceof Definition) {
$value = $this->createService($value, null); $value = $this->createService($value, $inlinedDefinitions);
} elseif ($value instanceof Expression) { } elseif ($value instanceof Expression) {
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this)); $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
} }
@ -1111,14 +1120,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
foreach ($definition->getMethodCalls() as $call) { foreach ($definition->getMethodCalls() as $call) {
foreach ($call[1] as $argument) { foreach ($call[1] as $argument) {
if ($argument instanceof Reference && $id == (string) $argument) { if ($argument instanceof Reference && $id == (string) $argument) {
$this->callMethod($this->get($definitionId), $call); $this->callMethod($this->get($definitionId), $call, new \SplObjectStorage());
} }
} }
} }
} }
} }
private function callMethod($service, $call) private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions)
{ {
$services = self::getServiceConditionals($call[1]); $services = self::getServiceConditionals($call[1]);
@ -1128,7 +1137,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
} }
} }
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])))); call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions));
} }
/** /**
@ -1140,9 +1149,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* *
* @throws InactiveScopeException * @throws InactiveScopeException
*/ */
private function shareService(Definition $definition, $service, $id) private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions)
{ {
if (null !== $id && $definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) { if (!$definition->isShared() || self::SCOPE_PROTOTYPE === $scope = $definition->getScope()) {
return;
}
if (null === $id) {
$inlinedDefinitions[$definition] = $service;
} else {
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) { if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
throw new InactiveScopeException($id, $scope); throw new InactiveScopeException($id, $scope);
} }

View File

@ -72,7 +72,7 @@ class ContainerBuilderTest extends TestCase
$definition->setDeprecated(true); $definition->setDeprecated(true);
$builder = new ContainerBuilder(); $builder = new ContainerBuilder();
$builder->createService($definition, 'deprecated_foo'); $builder->createService($definition, new \SplObjectStorage(), 'deprecated_foo');
} }
public function testRegister() public function testRegister()
@ -865,6 +865,28 @@ class ContainerBuilderTest extends TestCase
$this->assertTrue($classInList); $this->assertTrue($classInList);
} }
public function testInlinedDefinitions()
{
$container = new ContainerBuilder();
$definition = new Definition('BarClass');
$container->register('bar_user', 'BarUserClass')
->addArgument($definition)
->setProperty('foo', $definition);
$container->register('bar', 'BarClass')
->setProperty('foo', $definition)
->addMethodCall('setBaz', array($definition));
$barUser = $container->get('bar_user');
$bar = $container->get('bar');
$this->assertSame($barUser->foo, $barUser->bar);
$this->assertSame($bar->foo, $bar->getBaz());
$this->assertNotSame($bar->foo, $barUser->foo);
}
public function testInitializePropertiesBeforeMethodCalls() public function testInitializePropertiesBeforeMethodCalls()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();

View File

@ -8,7 +8,7 @@ function sc_configure($instance)
$instance->configure(); $instance->configure();
} }
class BarClass class BarClass extends BazClass
{ {
protected $baz; protected $baz;
public $foo = 'foo'; public $foo = 'foo';

View File

@ -34,8 +34,13 @@ class FileType extends AbstractType
if ($options['multiple']) { if ($options['multiple']) {
$data = array(); $data = array();
$files = $event->getData();
foreach ($event->getData() as $file) { if (!is_array($files)) {
$files = array();
}
foreach ($files as $file) {
if ($requestHandler->isFileUpload($file)) { if ($requestHandler->isFileUpload($file)) {
$data[] = $file; $data[] = $file;
} }

View File

@ -169,6 +169,24 @@ class FileTypeTest extends BaseTypeTest
$this->assertCount(1, $form->getData()); $this->assertCount(1, $form->getData());
} }
/**
* @dataProvider requestHandlerProvider
*/
public function testSubmitNonArrayValueWhenMultiple(RequestHandlerInterface $requestHandler)
{
$form = $this->factory
->createBuilder(static::TESTED_TYPE, null, array(
'multiple' => true,
))
->setRequestHandler($requestHandler)
->getForm();
$form->submit(null);
$this->assertSame(array(), $form->getData());
$this->assertSame(array(), $form->getNormData());
$this->assertSame(array(), $form->getViewData());
}
public function requestHandlerProvider() public function requestHandlerProvider()
{ {
return array( return array(