Skip to content

Commit ee33ceb

Browse files
author
Hugo Hamon
committed
[Form] use new service locator in DependencyInjectionExtension class, so that form types can be made private at some point.
1 parent 989b7cc commit ee33ceb

File tree

5 files changed

+234
-153
lines changed

5 files changed

+234
-153
lines changed

DependencyInjection/FormPass.php

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111

1212
namespace Symfony\Component\Form\DependencyInjection;
1313

14+
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
15+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1416
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
1517
use Symfony\Component\DependencyInjection\ContainerBuilder;
1618
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
19+
use Symfony\Component\DependencyInjection\Definition;
1720
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
21+
use Symfony\Component\DependencyInjection\Reference;
1822

1923
/**
20-
* Adds all services with the tags "form.type" and "form.type_guesser" as
21-
* arguments of the "form.extension" service.
24+
* Adds all services with the tags "form.type", "form.type_extension" and
25+
* "form.type_guesser" as arguments of the "form.extension" service.
2226
*
2327
* @author Bernhard Schussek <bschussek@gmail.com>
2428
*/
@@ -46,29 +50,37 @@ public function process(ContainerBuilder $container)
4650
}
4751

4852
$definition = $container->getDefinition($this->formExtensionService);
53+
$definition->replaceArgument(0, $this->processFormTypes($container, $definition));
54+
$definition->replaceArgument(1, $this->processFormTypeExtensions($container));
55+
$definition->replaceArgument(2, $this->processFormTypeGuessers($container));
56+
}
57+
58+
private function processFormTypes(ContainerBuilder $container, Definition $definition)
59+
{
60+
// Get service locator argument
61+
$servicesMap = array();
62+
$locator = $definition->getArgument(0);
63+
if ($locator instanceof ServiceLocatorArgument) {
64+
$servicesMap = $locator->getValues();
65+
}
4966

5067
// Builds an array with fully-qualified type class names as keys and service IDs as values
51-
$types = array();
5268
foreach ($container->findTaggedServiceIds($this->formTypeTag) as $serviceId => $tag) {
5369
$serviceDefinition = $container->getDefinition($serviceId);
54-
if (!$serviceDefinition->isPublic()) {
55-
throw new InvalidArgumentException(sprintf('The service "%s" must be public as form types are lazy-loaded.', $serviceId));
56-
}
5770

58-
// Support type access by FQCN
59-
$types[$serviceDefinition->getClass()] = $serviceId;
71+
// Add form type service to the service locator
72+
$servicesMap[$serviceDefinition->getClass()] = new Reference($serviceId);
6073
}
6174

62-
$definition->replaceArgument(1, $types);
75+
return new ServiceLocatorArgument($servicesMap);
76+
}
6377

78+
private function processFormTypeExtensions(ContainerBuilder $container)
79+
{
6480
$typeExtensions = array();
65-
6681
foreach ($this->findAndSortTaggedServices($this->formTypeExtensionTag, $container) as $reference) {
6782
$serviceId = (string) $reference;
6883
$serviceDefinition = $container->getDefinition($serviceId);
69-
if (!$serviceDefinition->isPublic()) {
70-
throw new InvalidArgumentException(sprintf('The service "%s" must be public as form type extensions are lazy-loaded.', $serviceId));
71-
}
7284

7385
$tag = $serviceDefinition->getTag($this->formTypeExtensionTag);
7486
if (isset($tag[0]['extended_type'])) {
@@ -77,19 +89,23 @@ public function process(ContainerBuilder $container)
7789
throw new InvalidArgumentException(sprintf('"%s" tagged services must have the extended type configured using the extended_type/extended-type attribute, none was configured for the "%s" service.', $this->formTypeExtensionTag, $serviceId));
7890
}
7991

80-
$typeExtensions[$extendedType][] = $serviceId;
92+
$typeExtensions[$extendedType][] = new Reference($serviceId);
8193
}
8294

83-
$definition->replaceArgument(2, $typeExtensions);
95+
foreach ($typeExtensions as $extendedType => $extensions) {
96+
$typeExtensions[$extendedType] = new IteratorArgument($extensions);
97+
}
8498

85-
$guessers = array_keys($container->findTaggedServiceIds($this->formTypeGuesserTag));
86-
foreach ($guessers as $serviceId) {
87-
$serviceDefinition = $container->getDefinition($serviceId);
88-
if (!$serviceDefinition->isPublic()) {
89-
throw new InvalidArgumentException(sprintf('The service "%s" must be public as form type guessers are lazy-loaded.', $serviceId));
90-
}
99+
return $typeExtensions;
100+
}
101+
102+
private function processFormTypeGuessers(ContainerBuilder $container)
103+
{
104+
$guessers = array();
105+
foreach ($container->findTaggedServiceIds($this->formTypeGuesserTag) as $serviceId => $tags) {
106+
$guessers[] = new Reference($serviceId);
91107
}
92108

93-
$definition->replaceArgument(3, $guessers);
109+
return new IteratorArgument($guessers);
94110
}
95111
}

Extension/DependencyInjection/DependencyInjectionExtension.php

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,80 @@
1111

1212
namespace Symfony\Component\Form\Extension\DependencyInjection;
1313

14+
use Psr\Container\ContainerInterface;
1415
use Symfony\Component\Form\FormExtensionInterface;
1516
use Symfony\Component\Form\FormTypeGuesserChain;
1617
use Symfony\Component\Form\Exception\InvalidArgumentException;
17-
use Symfony\Component\DependencyInjection\ContainerInterface;
1818

1919
class DependencyInjectionExtension implements FormExtensionInterface
2020
{
21-
private $container;
22-
private $typeServiceIds;
23-
private $typeExtensionServiceIds;
24-
private $guesserServiceIds;
2521
private $guesser;
2622
private $guesserLoaded = false;
23+
private $typeContainer;
24+
private $typeExtensionServices;
25+
private $guesserServices;
26+
27+
// @deprecated to be removed in Symfony 4.0
28+
private $typeServiceIds;
29+
private $guesserServiceIds;
2730

28-
public function __construct(ContainerInterface $container, array $typeServiceIds, array $typeExtensionServiceIds, array $guesserServiceIds)
31+
/**
32+
* Constructor.
33+
*
34+
* @param ContainerInterface $typeContainer
35+
* @param iterable[] $typeExtensionServices
36+
* @param iterable $guesserServices
37+
*/
38+
public function __construct(ContainerInterface $typeContainer, array $typeExtensionServices, $guesserServices, array $guesserServiceIds = null)
2939
{
30-
$this->container = $container;
31-
$this->typeServiceIds = $typeServiceIds;
32-
$this->typeExtensionServiceIds = $typeExtensionServiceIds;
33-
$this->guesserServiceIds = $guesserServiceIds;
40+
if (null !== $guesserServiceIds) {
41+
@trigger_error(sprintf('Passing four arguments to the %s::__construct() method is deprecated since Symfony 3.3 and will be disallowed in Symfony 4.0. The new constructor only accepts three arguments.', __CLASS__), E_USER_DEPRECATED);
42+
$this->guesserServiceIds = $guesserServiceIds;
43+
$this->typeServiceIds = $typeExtensionServices;
44+
}
45+
46+
$this->typeContainer = $typeContainer;
47+
$this->typeExtensionServices = $typeExtensionServices;
48+
$this->guesserServices = $guesserServices;
3449
}
3550

3651
public function getType($name)
3752
{
38-
if (!isset($this->typeServiceIds[$name])) {
39-
throw new InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name));
53+
if (null !== $this->guesserServiceIds) {
54+
if (!isset($this->typeServiceIds[$name])) {
55+
throw new InvalidArgumentException(sprintf('The field type "%s" is not registered in the service container.', $name));
56+
}
57+
58+
return $this->typeContainer->get($this->typeServiceIds[$name]);
4059
}
4160

42-
return $this->container->get($this->typeServiceIds[$name]);
61+
if (!$this->typeContainer->has($name)) {
62+
throw new InvalidArgumentException(sprintf('The field type "%s" is not registered in the service container.', $name));
63+
}
64+
65+
return $this->typeContainer->get($name);
4366
}
4467

4568
public function hasType($name)
4669
{
47-
return isset($this->typeServiceIds[$name]);
70+
if (null !== $this->guesserServiceIds) {
71+
return isset($this->typeServiceIds[$name]);
72+
}
73+
74+
return $this->typeContainer->has($name);
4875
}
4976

5077
public function getTypeExtensions($name)
5178
{
5279
$extensions = array();
5380

54-
if (isset($this->typeExtensionServiceIds[$name])) {
55-
foreach ($this->typeExtensionServiceIds[$name] as $serviceId) {
56-
$extensions[] = $extension = $this->container->get($serviceId);
81+
if (isset($this->typeExtensionServices[$name])) {
82+
foreach ($this->typeExtensionServices[$name] as $serviceId => $extension) {
83+
if (null !== $this->guesserServiceIds) {
84+
$extension = $this->typeContainer->get($serviceId = $extension);
85+
}
86+
87+
$extensions[] = $extension;
5788

5889
// validate result of getExtendedType() to ensure it is consistent with the service definition
5990
if ($extension->getExtendedType() !== $name) {
@@ -73,7 +104,7 @@ public function getTypeExtensions($name)
73104

74105
public function hasTypeExtensions($name)
75106
{
76-
return isset($this->typeExtensionServiceIds[$name]);
107+
return isset($this->typeExtensionServices[$name]);
77108
}
78109

79110
public function getTypeGuesser()
@@ -82,11 +113,15 @@ public function getTypeGuesser()
82113
$this->guesserLoaded = true;
83114
$guessers = array();
84115

85-
foreach ($this->guesserServiceIds as $serviceId) {
86-
$guessers[] = $this->container->get($serviceId);
116+
foreach ($this->guesserServices as $serviceId => $service) {
117+
if (null !== $this->guesserServiceIds) {
118+
$service = $this->typeContainer->get($serviceId = $service);
119+
}
120+
121+
$guessers[] = $service;
87122
}
88123

89-
if (count($guessers) > 0) {
124+
if ($guessers) {
90125
$this->guesser = new FormTypeGuesserChain($guessers);
91126
}
92127
}

0 commit comments

Comments
 (0)