Merge branch '4.0'

* 4.0:
  [Form] Fixed ContextErrorException in FileType
  [DI] Fix handling of inlined definitions by ContainerBuilder
  [Security] remove unused variable
  [DI] Fix infinite loop when analyzing references
  [Lock][Process][FrameworkBundle] fix tests
  Display a nice error message if the form/serializer component is missing.
  [SecurityBundle] providerIds is undefined error when firewall provider is not specified
  [SecurityBundle] providerIds is undefined error when firewall provider is not specified
  [SecurityBundle] providerIds is undefined error when firewall provider is not specified
  Force phpunit-bridge update (bis)
  [Bridge/PhpUnit] Fix disabling global state preservation
  Incorrect dot on method loadChoices in upgrade doc
This commit is contained in:
Nicolas Grekas 2017-11-23 12:04:09 +01:00
commit cfdc145dab
13 changed files with 100 additions and 48 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
// Cache-Id: https://github.com/symfony/phpunit-bridge/commit/3646664aa952fe13e9a612a726cbb38e02249793
// Cache-Id: https://github.com/symfony/phpunit-bridge/commit/66ffffcd8a6bb23aec847c8bdfb918610399499a
if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) {
echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n";

View File

@ -137,10 +137,6 @@ class FrameworkExtension extends Extension
throw new LogicException('Translation support cannot be enabled as the Translation component is not installed.');
}
if (!class_exists('Symfony\Component\Translation\Translator') && $this->isConfigEnabled($container, $config['validation'])) {
throw new LogicException('Validation support cannot be enabled as the Translation component is not installed.');
}
if (class_exists(Translator::class)) {
$loader->load('identity_translator.xml');
}
@ -184,6 +180,10 @@ class FrameworkExtension extends Extension
}
if ($this->isConfigEnabled($container, $config['form'])) {
if (!class_exists('Symfony\Component\Form\Form')) {
throw new LogicException('Form support cannot be enabled as the Form component is not installed.');
}
$this->formConfigEnabled = true;
$this->registerFormConfiguration($config, $container, $loader);
@ -231,6 +231,10 @@ class FrameworkExtension extends Extension
$this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader);
if ($this->isConfigEnabled($container, $config['serializer'])) {
if (!class_exists('Symfony\Component\Serializer\Serializer')) {
throw new LogicException('Serializer support cannot be enabled as the Serializer component is not installed.');
}
$this->registerSerializerConfiguration($config['serializer'], $container, $loader);
}
@ -923,6 +927,7 @@ class FrameworkExtension extends Extension
return 2 === substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename());
})
->in($dirs)
->sortByName()
;
foreach ($finder as $file) {
@ -1032,7 +1037,7 @@ class FrameworkExtension extends Extension
private function registerMappingFilesFromDir($dir, callable $fileRecorder)
{
foreach (Finder::create()->followLinks()->files()->in($dir)->name('/\.(xml|ya?ml)$/') as $file) {
foreach (Finder::create()->followLinks()->files()->in($dir)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) {
$fileRecorder($file->getExtension(), $file->getRealPath());
}
}

View File

@ -349,7 +349,7 @@ class SecurityExtension extends Extension
// Switch user listener
if (isset($firewall['switch_user'])) {
$listenerKeys[] = 'switch_user';
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider, $firewall['stateless']));
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider, $firewall['stateless'], $providerIds));
}
// Access listener
@ -594,7 +594,7 @@ class SecurityExtension extends Extension
return $exceptionListenerId;
}
private function createSwitchUserListener($container, $id, $config, $defaultProvider = null, $stateless)
private function createSwitchUserListener($container, $id, $config, $defaultProvider, $stateless, $providerIds)
{
$userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider;

View File

@ -30,7 +30,7 @@
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/form": "~3.4|~4.0",
"symfony/framework-bundle": "~3.4|~4.0",
"symfony/framework-bundle": "~3.4-rc1|~4.0-rc1",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/twig-bundle": "~3.4|~4.0",
@ -40,7 +40,7 @@
"symfony/var-dumper": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"doctrine/doctrine-bundle": "~1.4",
"doctrine/doctrine-bundle": "~1.5",
"twig/twig": "~1.34|~2.4"
},
"conflict": {

View File

@ -544,7 +544,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$this->{$loading}[$id] = true;
try {
$service = $this->createService($definition, $id);
$service = $this->createService($definition, new \SplObjectStorage(), $id);
} finally {
unset($this->{$loading}[$id]);
}
@ -978,8 +978,12 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @throws RuntimeException When the service is a synthetic service
* @throws InvalidArgumentException When configure callable is not callable
*/
private function createService(Definition $definition, $id, $tryProxy = true)
private function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true)
{
if (null === $id && isset($inlinedDefinitions[$definition])) {
return $inlinedDefinitions[$definition];
}
if ($definition instanceof ChildDefinition) {
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
}
@ -998,11 +1002,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
->instantiateProxy(
$this,
$definition,
$id, function () use ($definition, $id) {
return $this->createService($definition, $id, false);
$id, function () use ($definition, $inlinedDefinitions, $id) {
return $this->createService($definition, $inlinedDefinitions, $id, false);
}
);
$this->shareService($definition, $proxy, $id);
$this->shareService($definition, $proxy, $id, $inlinedDefinitions);
return $proxy;
}
@ -1013,7 +1017,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
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 !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) {
return $this->services[$id];
@ -1021,7 +1025,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if (null !== $factory = $definition->getFactory()) {
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)) {
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
}
@ -1047,16 +1051,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($tryProxy || !$definition->isLazy()) {
// 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) {
$service->$name = $value;
}
foreach ($definition->getMethodCalls() as $call) {
$this->callMethod($service, $call);
$this->callMethod($service, $call, $inlinedDefinitions);
}
if ($callable = $definition->getConfigurator()) {
@ -1066,7 +1070,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($callable[0] instanceof Reference) {
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
} elseif ($callable[0] instanceof Definition) {
$callable[0] = $this->createService($callable[0], null);
$callable[0] = $this->createService($callable[0], $inlinedDefinitions);
}
}
@ -1089,10 +1093,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* the real service instances and all expressions evaluated
*/
public function resolveServices($value)
{
return $this->doResolveServices($value, new \SplObjectStorage());
}
private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions)
{
if (is_array($value)) {
foreach ($value as $k => $v) {
$value[$k] = $this->resolveServices($v);
$value[$k] = $this->doResolveServices($v, $inlinedDefinitions);
}
} elseif ($value instanceof ServiceClosureArgument) {
$reference = $value->getValues()[0];
@ -1137,7 +1146,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
} elseif ($value instanceof Reference) {
$value = $this->get((string) $value, $value->getInvalidBehavior());
} elseif ($value instanceof Definition) {
$value = $this->createService($value, null);
$value = $this->createService($value, $inlinedDefinitions);
} elseif ($value instanceof Expression) {
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
}
@ -1434,7 +1443,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $this->proxyInstantiator;
}
private function callMethod($service, $call)
private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions)
{
foreach (self::getServiceConditionals($call[1]) as $s) {
if (!$this->has($s)) {
@ -1447,7 +1456,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));
}
/**
@ -1457,9 +1466,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @param object $service
* @param string|null $id
*/
private function shareService(Definition $definition, $service, $id)
private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions)
{
if (null !== $id && $definition->isShared()) {
if (!$definition->isShared()) {
return;
}
if (null === $id) {
$inlinedDefinitions[$definition] = $service;
} else {
$this->services[$id] = $service;
unset($this->loading[$id], $this->alreadyLoading[$id]);
}

View File

@ -353,6 +353,7 @@ EOTXT
if (isset($checkedNodes[$id])) {
continue;
}
$checkedNodes[$id] = true;
if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) {
// no-op
@ -364,10 +365,8 @@ EOTXT
} else {
$currentPath[$id] = $id;
$this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath);
array_pop($currentPath);
}
$checkedNodes[$id] = true;
array_pop($currentPath);
}
}

View File

@ -1051,6 +1051,28 @@ class ContainerBuilderTest extends TestCase
$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()
{
$container = new ContainerBuilder();

View File

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

View File

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

View File

@ -159,6 +159,24 @@ class FileTypeTest extends BaseTypeTest
$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()
{
return array(

View File

@ -26,7 +26,10 @@ class MemcachedStoreTest extends AbstractStoreTest
{
$memcached = new \Memcached();
$memcached->addServer(getenv('MEMCACHED_HOST'), 11211);
if (false === $memcached->getStats()) {
$memcached->get('foo');
$code = $memcached->getResultCode();
if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
self::markTestSkipped('Unable to connect to the memcache host');
}
}

View File

@ -1452,20 +1452,7 @@ Array
)
EOTXT;
if (\PHP_VERSION_ID >= 70200) {
$expected = <<<EOTXT
Array
(
[0] => Standard input code
[1] => a
[2] =>
[3] => b
)
EOTXT;
}
$this->assertSame($expected, $p->getOutput());
$this->assertSame($expected, str_replace('Standard input code', '-', $p->getOutput()));
}
public function provideEscapeArgument()

View File

@ -43,7 +43,6 @@ class ContextListener implements ListenerInterface
private $dispatcher;
private $registered;
private $trustResolver;
private $logoutOnUserChange = true;
/**
* @param TokenStorageInterface $tokenStorage