Skip to content

Commit 23db36b

Browse files
[DI] Add getter injection
1 parent dd1fd31 commit 23db36b

29 files changed

+295
-7
lines changed

src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public function process(ContainerBuilder $container)
7575

7676
if (!$this->onlyConstructorArguments) {
7777
$this->processArguments($definition->getMethodCalls());
78+
$this->processArguments($definition->getOverriddenGetters());
7879
$this->processArguments($definition->getProperties());
7980
if ($definition->getConfigurator()) {
8081
$this->processArguments(array($definition->getConfigurator()));
@@ -108,6 +109,7 @@ private function processArguments(array $arguments)
108109
} elseif ($argument instanceof Definition) {
109110
$this->processArguments($argument->getArguments());
110111
$this->processArguments($argument->getMethodCalls());
112+
$this->processArguments($argument->getOverriddenGetters());
111113
$this->processArguments($argument->getProperties());
112114

113115
if (is_array($argument->getFactory())) {

src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ private function processDefinition(Definition $definition)
4141
{
4242
$this->processReferences($definition->getArguments());
4343
$this->processReferences($definition->getMethodCalls());
44+
$this->processReferences($definition->getOverriddenGetters());
4445
$this->processReferences($definition->getProperties());
4546
}
4647

src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function process(ContainerBuilder $container)
4747

4848
$this->validateReferences($definition->getArguments());
4949
$this->validateReferences($definition->getMethodCalls());
50+
$this->validateReferences($definition->getOverriddenGetters());
5051
$this->validateReferences($definition->getProperties());
5152
}
5253
}

src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ private function inlineArguments(ContainerBuilder $container, array $arguments,
8484
} elseif ($argument instanceof Definition) {
8585
$argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
8686
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
87+
$argument->setOverriddenGetters($this->inlineArguments($container, $argument->getOverriddenGetters()));
8788
$argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
8889

8990
$configurator = $this->inlineArguments($container, array($argument->getConfigurator()));

src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public function process(ContainerBuilder $container)
7676
foreach ($container->getDefinitions() as $definitionId => $definition) {
7777
$definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments()));
7878
$definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls()));
79+
$definition->setOverriddenGetters($this->updateArgumentReferences($replacements, $definitionId, $definition->getOverriddenGetters()));
7980
$definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties()));
8081
$definition->setFactory($this->updateFactoryReference($replacements, $definition->getFactory()));
8182
}

src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ private function resolveArguments(ContainerBuilder $container, array $arguments,
7272
}
7373
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
7474
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
75+
$argument->setOverriddenGetters($this->resolveArguments($container, $argument->getOverriddenGetters()));
7576
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
7677

7778
$configurator = $this->resolveArguments($container, array($argument->getConfigurator()));
@@ -131,6 +132,7 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
131132
$def->setClass($parentDef->getClass());
132133
$def->setArguments($parentDef->getArguments());
133134
$def->setMethodCalls($parentDef->getMethodCalls());
135+
$def->setOverriddenGetters($parentDef->getOverriddenGetters());
134136
$def->setProperties($parentDef->getProperties());
135137
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
136138
if ($parentDef->isDeprecated()) {
@@ -203,6 +205,11 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
203205
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
204206
}
205207

208+
// merge overridden getters
209+
foreach ($definition->getOverriddenGetters() as $k => $v) {
210+
$def->setOverriddenGetter($k, $v);
211+
}
212+
206213
// merge autowiring types
207214
foreach ($definition->getAutowiringTypes() as $autowiringType) {
208215
$def->addAutowiringType($autowiringType);

src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ public function process(ContainerBuilder $container)
5353
}
5454
$definition->setMethodCalls($calls);
5555

56+
$getters = array();
57+
foreach ($definition->getOverriddenGetters() as $name => $value) {
58+
try {
59+
$value = $this->processArguments(array($value), true);
60+
$getters[$name] = reset($value);
61+
} catch (RuntimeException $e) {
62+
// this call is simply removed
63+
}
64+
}
65+
$definition->setOverriddenGetters($getters);
66+
5667
$properties = array();
5768
foreach ($definition->getProperties() as $name => $value) {
5869
try {

src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function process(ContainerBuilder $container)
5151
}
5252
$definition->setMethodCalls($calls);
5353

54+
$definition->setOverriddenGetters($parameterBag->resolveValue($definition->getOverriddenGetters()));
5455
$definition->setProperties($parameterBag->resolveValue($definition->getProperties()));
5556
} catch (ParameterNotFoundException $e) {
5657
$e->setSourceId($id);

src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function process(ContainerBuilder $container)
4141

4242
$definition->setArguments($this->processArguments($definition->getArguments()));
4343
$definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));
44+
$definition->setOverriddenGetters($this->processArguments($definition->getOverriddenGetters()));
4445
$definition->setProperties($this->processArguments($definition->getProperties()));
4546
$definition->setFactory($this->processFactory($definition->getFactory()));
4647
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,9 @@ private function createService(Definition $definition, $id, $tryProxy = true)
887887
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
888888

889889
if (null !== $factory = $definition->getFactory()) {
890+
if ($definition->getOverriddenGetters()) {
891+
throw new RuntimeException(sprintf('Cannot dump definition: The "%s" service has both a factory and overridden getters but these are incompatible.', $id));
892+
}
890893
if (is_array($factory)) {
891894
$factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
892895
} elseif (!is_string($factory)) {
@@ -905,11 +908,16 @@ private function createService(Definition $definition, $id, $tryProxy = true)
905908
} else {
906909
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
907910

908-
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
909-
910911
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
911912
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED);
912913
}
914+
if ($definition->getOverriddenGetters()) {
915+
$salt = str_replace('.', '', uniqid('', true));
916+
$service = eval(sprintf('return new class(...$arguments) extends %s { private $container%3$s; private $values%3$s; %s };', $r->name, $this->addOverriddenGetters($id, $definition, $r, $salt), $salt));
917+
call_user_func(\Closure::bind(function ($c, $v, $s) { $this->{'container'.$s} = $c; $this->{'values'.$s} = $v; }, $service, $service), $this, $definition->getOverriddenGetters(), $salt);
918+
} else {
919+
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
920+
}
913921
}
914922

915923
if ($tryProxy || !$definition->isLazy()) {
@@ -1114,6 +1122,58 @@ public function getEnvCounters()
11141122
return $this->envCounters;
11151123
}
11161124

1125+
private function addOverriddenGetters($id, Definition $definition, \ReflectionClass $class, $salt)
1126+
{
1127+
if (PHP_VERSION_ID < 70000) {
1128+
throw new RuntimeException(sprintf('Getter-based injection requires PHP 7 or more as used for service "%s".', $id));
1129+
}
1130+
if ($class->isFinal()) {
1131+
throw new RuntimeException(sprintf('Invalid getter for service "%s": class "%s" is final.', $id, $class->name));
1132+
}
1133+
$getters = '';
1134+
foreach ($definition->getOverriddenGetters() as $name => $returnValue) {
1135+
if (!$class->hasMethod($name)) {
1136+
throw new RuntimeException(sprintf('Invalid getter for service "%s": method "%s::%s" does not exist.', $id, $class->name, $name));
1137+
}
1138+
$r = $class->getMethod($name);
1139+
if ($r->isPrivate()) {
1140+
throw new RuntimeException(sprintf('Invalid getter for service "%s": method "%s::%s" is private.', $id, $class->name, $name));
1141+
}
1142+
if ($r->isFinal()) {
1143+
throw new RuntimeException(sprintf('Invalid getter for service "%s": method "%s::%s" is final.', $id, $class->name, $name));
1144+
}
1145+
if ($r->returnsReference()) {
1146+
throw new RuntimeException(sprintf('Invalid getter for service "%s": method "%s::%s" returns by reference.', $id, $class->name, $name));
1147+
}
1148+
if (0 < $r->getNumberOfParameters()) {
1149+
throw new RuntimeException(sprintf('Invalid getter for service "%s": method "%s::%s" has parameters.', $id, $class->name, $name));
1150+
}
1151+
if ($type = $r->getReturnType()) {
1152+
$type = ': '.($type->allowsNull() ? '?' : '').$this->generateTypeHint($type, $r);
1153+
}
1154+
$visibility = $r->isProtected() ? 'protected' : 'public';
1155+
$nameExport = var_export($name, true);
1156+
$getters .= <<<EOF
1157+
1158+
{$visibility} function {$name}(){$type} {
1159+
\$c = \$this->container{$salt};
1160+
\$b = \$c->getParameterBag();
1161+
\$v = \$this->values{$salt}[{$nameExport}];
1162+
1163+
foreach (\$c->getServiceConditionals(\$v) as \$s) {
1164+
if (!\$c->has(\$s)) {
1165+
return parent::{$name}();
1166+
}
1167+
}
1168+
1169+
return \$c->resolveServices(\$b->unescapeValue(\$b->resolveValue(\$v)));
1170+
}
1171+
EOF;
1172+
}
1173+
1174+
return $getters;
1175+
}
1176+
11171177
/**
11181178
* Returns the Service Conditionals.
11191179
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy