Skip to content

Commit

Permalink
[FrameworkBundle] Restore 3.2-like behavior for FormPass, to help BC …
Browse files Browse the repository at this point in the history
…with Sonata
  • Loading branch information
nicolas-grekas committed Apr 20, 2017
1 parent 9c0067b commit c97b08e
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,76 @@

@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use Symfony\Component\Form\DependencyInjection\FormPass instead.', FormPass::class), E_USER_DEPRECATED);

use Symfony\Component\Form\DependencyInjection\FormPass as BaseFormPass;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
* Adds all services with the tags "form.type" and "form.type_guesser" as
* arguments of the "form.extension" service.
*
* @deprecated since version 3.3, to be removed in 4.0. Use {@link BaseFormPass} instead.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since version 3.3, to be removed in 4.0. Use FormPass in the Form component instead.
*/
class FormPass extends BaseFormPass
class FormPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;

public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('form.extension')) {
return;
}

$definition = $container->getDefinition('form.extension');

// Builds an array with fully-qualified type class names as keys and service IDs as values
$types = array();

foreach ($container->findTaggedServiceIds('form.type') as $serviceId => $tag) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
$serviceDefinition->setPublic(true);
}

// Support type access by FQCN
$types[$serviceDefinition->getClass()] = $serviceId;
}

$definition->replaceArgument(1, $types);

$typeExtensions = array();

foreach ($this->findAndSortTaggedServices('form.type_extension', $container) as $reference) {
$serviceId = (string) $reference;
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
$serviceDefinition->setPublic(true);
}

$tag = $serviceDefinition->getTag('form.type_extension');
if (isset($tag[0]['extended_type'])) {
$extendedType = $tag[0]['extended_type'];
} else {
throw new InvalidArgumentException(sprintf('Tagged form type extension must have the extended type configured using the extended_type/extended-type attribute, none was configured for the "%s" service.', $serviceId));
}

$typeExtensions[$extendedType][] = $serviceId;
}

$definition->replaceArgument(2, $typeExtensions);

// Find all services annotated with "form.type_guesser"
$guessers = array_keys($container->findTaggedServiceIds('form.type_guesser'));
foreach ($guessers as $serviceId) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
$serviceDefinition->setPublic(true);
}
}

$definition->replaceArgument(3, $guessers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<argument /><!-- All services with tag "form.type" are stored in a service locator by FormPass -->
<argument type="collection" /><!-- All services with tag "form.type_extension" are stored here by FormPass -->
<argument type="iterator" /><!-- All services with tag "form.type_guesser" are stored here by FormPass -->
<argument>null</argument><!-- @deprecated argument in 3.3, to be removed in 4.0 -->
</service>

<!-- ValidatorTypeGuesser -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@

use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\Form\AbstractType;

/**
Expand All @@ -30,7 +27,8 @@ class FormPassTest extends TestCase
{
public function testDoNothingIfFormExtensionNotLoaded()
{
$container = $this->createContainerBuilder();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$container->compile();

Expand All @@ -39,33 +37,47 @@ public function testDoNothingIfFormExtensionNotLoaded()

public function testAddTaggedTypes()
{
$container = $this->createContainerBuilder();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$container->setDefinition('form.extension', $this->createExtensionDefinition());
$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension');
$extDefinition->setArguments(array(
new Reference('service_container'),
array(),
array(),
array(),
));

$container->setDefinition('form.extension', $extDefinition);
$container->register('my.type1', __CLASS__.'_Type1')->addTag('form.type');
$container->register('my.type2', __CLASS__.'_Type2')->addTag('form.type');

$container->compile();

$extDefinition = $container->getDefinition('form.extension');

$this->assertEquals(
(new Definition(ServiceLocator::class, array(array(
__CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')),
__CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')),
))))->addTag('container.service_locator')->setPublic(false),
$extDefinition->getArgument(0)
);
$this->assertEquals(array(
__CLASS__.'_Type1' => 'my.type1',
__CLASS__.'_Type2' => 'my.type2',
), $extDefinition->getArgument(1));
}

/**
* @dataProvider addTaggedTypeExtensionsDataProvider
*/
public function testAddTaggedTypeExtensions(array $extensions, array $expectedRegisteredExtensions)
{
$container = $this->createContainerBuilder();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$container->setDefinition('form.extension', $this->createExtensionDefinition());
$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension', array(
new Reference('service_container'),
array(),
array(),
array(),
));

$container->setDefinition('form.extension', $extDefinition);

foreach ($extensions as $serviceId => $tag) {
$container->register($serviceId, 'stdClass')->addTag('form.type_extension', $tag);
Expand All @@ -74,7 +86,7 @@ public function testAddTaggedTypeExtensions(array $extensions, array $expectedRe
$container->compile();

$extDefinition = $container->getDefinition('form.extension');
$this->assertEquals($expectedRegisteredExtensions, $extDefinition->getArgument(1));
$this->assertSame($expectedRegisteredExtensions, $extDefinition->getArgument(2));
}

/**
Expand All @@ -90,11 +102,8 @@ public function addTaggedTypeExtensionsDataProvider()
'my.type_extension3' => array('extended_type' => 'type2'),
),
array(
'type1' => new IteratorArgument(array(
new Reference('my.type_extension1'),
new Reference('my.type_extension2'),
)),
'type2' => new IteratorArgument(array(new Reference('my.type_extension3'))),
'type1' => array('my.type_extension1', 'my.type_extension2'),
'type2' => array('my.type_extension3'),
),
),
array(
Expand All @@ -107,16 +116,8 @@ public function addTaggedTypeExtensionsDataProvider()
'my.type_extension6' => array('extended_type' => 'type2', 'priority' => 1),
),
array(
'type1' => new IteratorArgument(array(
new Reference('my.type_extension2'),
new Reference('my.type_extension1'),
new Reference('my.type_extension3'),
)),
'type2' => new IteratorArgument(array(
new Reference('my.type_extension4'),
new Reference('my.type_extension5'),
new Reference('my.type_extension6'),
)),
'type1' => array('my.type_extension2', 'my.type_extension1', 'my.type_extension3'),
'type2' => array('my.type_extension4', 'my.type_extension5', 'my.type_extension6'),
),
),
);
Expand All @@ -128,9 +129,17 @@ public function addTaggedTypeExtensionsDataProvider()
*/
public function testAddTaggedFormTypeExtensionWithoutExtendedTypeAttribute()
{
$container = $this->createContainerBuilder();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension', array(
new Reference('service_container'),
array(),
array(),
array(),
));

$container->setDefinition('form.extension', $this->createExtensionDefinition());
$container->setDefinition('form.extension', $extDefinition);
$container->register('my.type_extension', 'stdClass')
->addTag('form.type_extension');

Expand All @@ -139,102 +148,67 @@ public function testAddTaggedFormTypeExtensionWithoutExtendedTypeAttribute()

public function testAddTaggedGuessers()
{
$container = $this->createContainerBuilder();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension');
$extDefinition->setArguments(array(
new Reference('service_container'),
array(),
array(),
array(),
));

$definition1 = new Definition('stdClass');
$definition1->addTag('form.type_guesser');
$definition2 = new Definition('stdClass');
$definition2->addTag('form.type_guesser');

$container->setDefinition('form.extension', $this->createExtensionDefinition());
$container->setDefinition('form.extension', $extDefinition);
$container->setDefinition('my.guesser1', $definition1);
$container->setDefinition('my.guesser2', $definition2);

$container->compile();

$extDefinition = $container->getDefinition('form.extension');

$this->assertEquals(
new IteratorArgument(array(
new Reference('my.guesser1'),
new Reference('my.guesser2'),
)),
$extDefinition->getArgument(2)
);
$this->assertSame(array(
'my.guesser1',
'my.guesser2',
), $extDefinition->getArgument(3));
}

/**
* @dataProvider privateTaggedServicesProvider
*/
public function testPrivateTaggedServices($id, $tagName, callable $assertion, array $tagAttributes = array())
public function testPrivateTaggedServices($id, $tagName)
{
$formPass = new FormPass();
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

$container->setDefinition('form.extension', $this->createExtensionDefinition());
$container->register($id, 'stdClass')->setPublic(false)->addTag($tagName, $tagAttributes);
$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension');
$extDefinition->setArguments(array(
new Reference('service_container'),
array(),
array(),
array(),
));

$formPass->process($container);
$container->setDefinition('form.extension', $extDefinition);
$container->register($id, 'stdClass')->setPublic(false)->addTag($tagName, array('extended_type' => 'Foo'));

$assertion($container);
$container->compile();
$this->assertTrue($container->getDefinition($id)->isPublic());
}

public function privateTaggedServicesProvider()
{
return array(
array(
'my.type',
'form.type',
function (ContainerBuilder $container) {
$formTypes = $container->getDefinition('form.extension')->getArgument(0);

$this->assertInstanceOf(Reference::class, $formTypes);

$locator = $container->getDefinition((string) $formTypes);
$expectedLocatorMap = array(
'stdClass' => new ServiceClosureArgument(new Reference('my.type')),
);

$this->assertInstanceOf(Definition::class, $locator);
$this->assertEquals($expectedLocatorMap, $locator->getArgument(0));
},
),
array(
'my.type_extension',
'form.type_extension',
function (ContainerBuilder $container) {
$this->assertEquals(
array('Symfony\Component\Form\Extension\Core\Type\FormType' => new IteratorArgument(array(new Reference('my.type_extension')))),
$container->getDefinition('form.extension')->getArgument(1)
);
},
array('extended_type' => 'Symfony\Component\Form\Extension\Core\Type\FormType'),
),
array('my.guesser', 'form.type_guesser', function (ContainerBuilder $container) {
$this->assertEquals(new IteratorArgument(array(new Reference('my.guesser'))), $container->getDefinition('form.extension')->getArgument(2));
}),
array('my.type', 'form.type'),
array('my.type_extension', 'form.type_extension'),
array('my.guesser', 'form.type_guesser'),
);
}

private function createContainerBuilder()
{
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());

return $container;
}

private function createExtensionDefinition()
{
$definition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension');
$definition->setArguments(array(
array(),
array(),
new IteratorArgument(array()),
));

return $definition;
}
}

class FormPassTest_Type1 extends AbstractType
Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Component/Form/DependencyInjection/FormPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public function process(ContainerBuilder $container)
}

$definition = $container->getDefinition($this->formExtensionService);
if (new IteratorArgument(array()) != $definition->getArgument(2)) {
return;
}
$definition->replaceArgument(0, $this->processFormTypes($container, $definition));
$definition->replaceArgument(1, $this->processFormTypeExtensions($container));
$definition->replaceArgument(2, $this->processFormTypeGuessers($container));
Expand Down

0 comments on commit c97b08e

Please sign in to comment.