Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 970f592

Browse filesBrowse files
[DI] Add getter injection
1 parent 5921530 commit 970f592
Copy full SHA for 970f592

33 files changed

+824
-47
lines changed

‎src/Symfony/Component/DependencyInjection/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.3.0
55
-----
66

7+
* added support for getter-injection
78
* deprecated case insensitivity of service identifiers
89
* added "iterator" argument type for lazy iteration over a set of values and services
910
* added "closure-proxy" argument type for turning services' methods into lazy callables

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public function process(ContainerBuilder $container)
7676

7777
if (!$this->onlyConstructorArguments) {
7878
$this->processArguments($definition->getMethodCalls());
79+
$this->processArguments($definition->getOverriddenGetters());
7980
$this->processArguments($definition->getProperties());
8081
if ($definition->getConfigurator()) {
8182
$this->processArguments(array($definition->getConfigurator()));
@@ -115,6 +116,7 @@ private function processArguments(array $arguments, $lazy = false)
115116
} elseif ($argument instanceof Definition) {
116117
$this->processArguments($argument->getArguments());
117118
$this->processArguments($argument->getMethodCalls());
119+
$this->processArguments($argument->getOverriddenGetters());
118120
$this->processArguments($argument->getProperties());
119121

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ private function processDefinition(Definition $definition)
4242
{
4343
$this->processReferences($definition->getArguments());
4444
$this->processReferences($definition->getMethodCalls());
45+
$this->processReferences($definition->getOverriddenGetters());
4546
$this->processReferences($definition->getProperties());
4647
}
4748

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public function process(ContainerBuilder $container)
4848

4949
$this->validateReferences($definition->getArguments());
5050
$this->validateReferences($definition->getMethodCalls());
51+
$this->validateReferences($definition->getOverriddenGetters());
5152
$this->validateReferences($definition->getProperties());
5253
}
5354
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ private function inlineArguments(ContainerBuilder $container, array $arguments,
8787
} elseif ($argument instanceof Definition) {
8888
$argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
8989
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
90+
$argument->setOverriddenGetters($this->inlineArguments($container, $argument->getOverriddenGetters()));
9091
$argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
9192

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public function process(ContainerBuilder $container)
7777
foreach ($container->getDefinitions() as $definitionId => $definition) {
7878
$definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments()));
7979
$definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls()));
80+
$definition->setOverriddenGetters($this->updateArgumentReferences($replacements, $definitionId, $definition->getOverriddenGetters()));
8081
$definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties()));
8182
$definition->setFactory($this->updateFactoryReference($replacements, $definition->getFactory()));
8283
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ private function resolveArguments(ContainerBuilder $container, array $arguments,
7575
}
7676
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
7777
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
78+
$argument->setOverriddenGetters($this->resolveArguments($container, $argument->getOverriddenGetters()));
7879
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
7980

8081
$configurator = $this->resolveArguments($container, array($argument->getConfigurator()));
@@ -134,6 +135,7 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
134135
$def->setClass($parentDef->getClass());
135136
$def->setArguments($parentDef->getArguments());
136137
$def->setMethodCalls($parentDef->getMethodCalls());
138+
$def->setOverriddenGetters($parentDef->getOverriddenGetters());
137139
$def->setProperties($parentDef->getProperties());
138140
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
139141
if ($parentDef->isDeprecated()) {
@@ -206,6 +208,11 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
206208
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
207209
}
208210

211+
// merge overridden getters
212+
foreach ($definition->getOverriddenGetters() as $k => $v) {
213+
$def->setOverriddenGetter($k, $v);
214+
}
215+
209216
// merge autowiring types
210217
foreach ($definition->getAutowiringTypes() as $autowiringType) {
211218
$def->addAutowiringType($autowiringType);

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ public function process(ContainerBuilder $container)
5454
}
5555
$definition->setMethodCalls($calls);
5656

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php
+1Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function process(ContainerBuilder $container)
4242

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

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+122-2Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Config\Resource\ResourceInterface;
3030
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
3131
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
32+
use Symfony\Component\DependencyInjection\LazyProxy\GetterProxyInterface;
3233
use Symfony\Component\ExpressionLanguage\Expression;
3334
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
3435

@@ -890,6 +891,9 @@ private function createService(Definition $definition, $id, $tryProxy = true)
890891
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
891892

892893
if (null !== $factory = $definition->getFactory()) {
894+
if ($definition->getOverriddenGetters()) {
895+
throw new RuntimeException(sprintf('Cannot create service "%s": factories and overridden getters are incompatible with each other.', $id));
896+
}
893897
if (is_array($factory)) {
894898
$factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
895899
} elseif (!is_string($factory)) {
@@ -908,11 +912,31 @@ private function createService(Definition $definition, $id, $tryProxy = true)
908912
} else {
909913
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
910914

911-
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
912-
913915
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
914916
@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);
915917
}
918+
if ($definition->getOverriddenGetters()) {
919+
static $salt;
920+
if (null === $salt) {
921+
$salt = str_replace('.', '', uniqid('', true));
922+
}
923+
$service = sprintf('%s implements \\%s { private $container%4$s; private $values%4$s; %s }', $r->name, GetterProxyInterface::class, $this->generateOverriddenGetters($id, $definition, $r, $salt), $salt);
924+
if (!class_exists($proxyClass = 'SymfonyProxy_'.md5($service), false)) {
925+
eval(sprintf('class %s extends %s', $proxyClass, $service));
926+
}
927+
$r = new \ReflectionClass($proxyClass);
928+
$constructor = $r->getConstructor();
929+
if ($constructor && !defined('HHVM_VERSION') && $constructor->getDeclaringClass()->isInternal()) {
930+
$constructor = null;
931+
}
932+
$service = $constructor ? $r->newInstanceWithoutConstructor() : $r->newInstanceArgs($arguments);
933+
call_user_func(\Closure::bind(function ($c, $v, $s) { $this->{'container'.$s} = $c; $this->{'values'.$s} = $v; }, $service, $service), $this, $definition->getOverriddenGetters(), $salt);
934+
if ($constructor) {
935+
$constructor->invokeArgs($service, $arguments);
936+
}
937+
} else {
938+
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
939+
}
916940
}
917941

918942
if ($tryProxy || !$definition->isLazy()) {
@@ -1155,6 +1179,102 @@ public function getEnvCounters()
11551179
return $this->envCounters;
11561180
}
11571181

1182+
private function generateOverriddenGetters($id, Definition $definition, \ReflectionClass $class, $salt)
1183+
{
1184+
if ($class->isFinal()) {
1185+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": class "%s" cannot be marked as final.', $id, $class->name));
1186+
}
1187+
$getters = '';
1188+
foreach ($definition->getOverriddenGetters() as $name => $returnValue) {
1189+
$r = self::getGetterReflector($class, $name, $id, $type);
1190+
$visibility = $r->isProtected() ? 'protected' : 'public';
1191+
$name = var_export($name, true);
1192+
$getters .= <<<EOF
1193+
1194+
{$visibility} function {$r->name}(){$type} {
1195+
\$c = \$this->container{$salt};
1196+
\$b = \$c->getParameterBag();
1197+
\$v = \$this->values{$salt}[{$name}];
1198+
1199+
foreach (\$c->getServiceConditionals(\$v) as \$s) {
1200+
if (!\$c->has(\$s)) {
1201+
return parent::{$r->name}();
1202+
}
1203+
}
1204+
1205+
return \$c->resolveServices(\$b->unescapeValue(\$b->resolveValue(\$v)));
1206+
}
1207+
EOF;
1208+
}
1209+
1210+
return $getters;
1211+
}
1212+
1213+
/**
1214+
* @internal
1215+
*/
1216+
public static function getGetterReflector(\ReflectionClass $class, $name, $id, &$type)
1217+
{
1218+
if (!$class->hasMethod($name)) {
1219+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" does not exist.', $id, $class->name, $name));
1220+
}
1221+
$r = $class->getMethod($name);
1222+
if ($r->isPrivate()) {
1223+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" must be public or protected.', $id, $class->name, $r->name));
1224+
}
1225+
if ($r->isStatic()) {
1226+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot be static.', $id, $class->name, $r->name));
1227+
}
1228+
if ($r->isFinal()) {
1229+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot be marked as final.', $id, $class->name, $r->name));
1230+
}
1231+
if ($r->returnsReference()) {
1232+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot return by reference.', $id, $class->name, $r->name));
1233+
}
1234+
if (0 < $r->getNumberOfParameters()) {
1235+
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot have any arguments.', $id, $class->name, $r->name));
1236+
}
1237+
if ($type = method_exists($r, 'getReturnType') ? $r->getReturnType() : null) {
1238+
$type = ': '.($type->allowsNull() ? '?' : '').self::generateTypeHint($type, $r);
1239+
}
1240+
1241+
return $r;
1242+
}
1243+
1244+
/**
1245+
* @internal
1246+
*/
1247+
public static function generateTypeHint($type, \ReflectionFunctionAbstract $r)
1248+
{
1249+
if (is_string($type)) {
1250+
$name = $type;
1251+
1252+
if ('callable' === $name || 'array' === $name) {
1253+
return $name;
1254+
}
1255+
} else {
1256+
$name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString();
1257+
1258+
if ($type->isBuiltin()) {
1259+
return $name;
1260+
}
1261+
}
1262+
$lcName = strtolower($name);
1263+
1264+
if ('self' !== $lcName && 'parent' !== $lcName) {
1265+
return '\\'.$name;
1266+
}
1267+
if (!$r instanceof \ReflectionMethod) {
1268+
return;
1269+
}
1270+
if ('self' === $lcName) {
1271+
return '\\'.$r->getDeclaringClass()->name;
1272+
}
1273+
if ($parent = $r->getDeclaringClass()->getParentClass()) {
1274+
return '\\'.$parent->name;
1275+
}
1276+
}
1277+
11581278
/**
11591279
* @internal
11601280
*/

‎src/Symfony/Component/DependencyInjection/Definition.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Definition.php
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Definition
2929
private $deprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.';
3030
private $properties = array();
3131
private $calls = array();
32+
private $getters = array();
3233
private $configurator;
3334
private $tags = array();
3435
private $public = true;
@@ -319,6 +320,28 @@ public function getMethodCalls()
319320
return $this->calls;
320321
}
321322

323+
public function setOverriddenGetter($name, $returnValue)
324+
{
325+
if (!$name) {
326+
throw new InvalidArgumentException(sprintf('Getter name cannot be empty.'));
327+
}
328+
$this->getters[strtolower($name)] = $returnValue;
329+
330+
return $this;
331+
}
332+
333+
public function setOverriddenGetters(array $getters)
334+
{
335+
$this->getters = array_change_key_case($getters, CASE_LOWER);
336+
337+
return $this;
338+
}
339+
340+
public function getOverriddenGetters()
341+
{
342+
return $this->getters;
343+
}
344+
322345
/**
323346
* Sets tags for this definition.
324347
*

‎src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ public function dump(array $options = array())
8080
$this->findEdges($id, $call[1], false, $call[0].'()')
8181
);
8282
}
83+
84+
foreach ($definition->getOverriddenGetters() as $name => $value) {
85+
$this->edges[$id] = array_merge(
86+
$this->edges[$id],
87+
$this->findEdges($id, $value, false, $name.'()')
88+
);
89+
}
8390
}
8491

8592
return $this->container->resolveEnvPlaceholders($this->startDot().$this->addNodes().$this->addEdges().$this->endDot(), '__ENV_%s__');

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.