Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c25abd9

Browse files
committed
[DependencyInjection] added support for expressions in the service container
1 parent 3a41781 commit c25abd9

21 files changed

+136
-6
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
2.4.0
55
-----
66

7+
* added support for expressions in service definitions
78
* added ContainerAwareTrait to add default container aware behavior to a class
89

910
2.2.0

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use Symfony\Component\Config\Resource\ResourceInterface;
2525
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
2626
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
27+
use Symfony\Component\DependencyInjection\ExpressionLanguage;
28+
use Symfony\Component\ExpressionLanguage\Expression;
2729

2830
/**
2931
* ContainerBuilder is a DI container that provides an API to easily describe services.
@@ -78,6 +80,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
7880
*/
7981
private $proxyInstantiator;
8082

83+
/**
84+
* @var ExpressionLanguage|null
85+
*/
86+
private $expressionLanguage;
87+
8188
/**
8289
* Sets the track resources flag.
8390
*
@@ -983,11 +990,12 @@ public function createService(Definition $definition, $id, $tryProxy = true)
983990
}
984991

985992
/**
986-
* Replaces service references by the real service instance.
993+
* Replaces service references by the real service instance and evaluates expressions.
987994
*
988995
* @param mixed $value A value
989996
*
990-
* @return mixed The same value with all service references replaced by the real service instances
997+
* @return mixed The same value with all service references replaced by
998+
* the real service instances and all expressions evaluated
991999
*/
9921000
public function resolveServices($value)
9931001
{
@@ -999,6 +1007,8 @@ public function resolveServices($value)
9991007
$value = $this->get((string) $value, $value->getInvalidBehavior());
10001008
} elseif ($value instanceof Definition) {
10011009
$value = $this->createService($value, null);
1010+
} elseif ($value instanceof Expression) {
1011+
$value = $this->getExpressionLanguage()->evaluate($value, array('this' => $this));
10021012
}
10031013

10041014
return $value;
@@ -1149,4 +1159,16 @@ private function shareService(Definition $definition, $service, $id)
11491159
}
11501160
}
11511161
}
1162+
1163+
private function getExpressionLanguage()
1164+
{
1165+
if (null === $this->expressionLanguage) {
1166+
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1167+
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1168+
}
1169+
$this->expressionLanguage = new ExpressionLanguage();
1170+
}
1171+
1172+
return $this->expressionLanguage;
1173+
}
11521174
}

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
2424
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
2525
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
26+
use Symfony\Component\DependencyInjection\ExpressionLanguage;
27+
use Symfony\Component\ExpressionLanguage\Expression;
2628

2729
/**
2830
* PhpDumper dumps a service container as a PHP class.
@@ -51,6 +53,7 @@ class PhpDumper extends Dumper
5153
private $referenceVariables;
5254
private $variableCount;
5355
private $reservedVariables = array('instance', 'class');
56+
private $expressionLanguage;
5457

5558
/**
5659
* @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
@@ -1197,6 +1200,8 @@ private function dumpValue($value, $interpolate = true)
11971200
}
11981201

11991202
return $this->getServiceCall((string) $value, $value);
1203+
} elseif ($value instanceof Expression) {
1204+
return $this->getExpressionLanguage()->compile((string) $value, array('this'));
12001205
} elseif ($value instanceof Parameter) {
12011206
return $this->dumpParameter($value);
12021207
} elseif (true === $interpolate && is_string($value)) {
@@ -1319,4 +1324,16 @@ private function getNextVariableName()
13191324
return $name;
13201325
}
13211326
}
1327+
1328+
private function getExpressionLanguage()
1329+
{
1330+
if (null === $this->expressionLanguage) {
1331+
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1332+
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1333+
}
1334+
$this->expressionLanguage = new ExpressionLanguage();
1335+
}
1336+
1337+
return $this->expressionLanguage;
1338+
}
13221339
}

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\DependencyInjection\Definition;
1818
use Symfony\Component\DependencyInjection\Alias;
1919
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
20+
use Symfony\Component\ExpressionLanguage\Expression;
2021

2122
/**
2223
* XmlDumper dumps a service container as an XML string.
@@ -259,6 +260,10 @@ private function convertParameters($parameters, $type, \DOMElement $parent, $key
259260
} elseif ($value instanceof Definition) {
260261
$element->setAttribute('type', 'service');
261262
$this->addService($value, null, $element);
263+
} elseif ($value instanceof Expression) {
264+
$element->setAttribute('type', 'expression');
265+
$text = $this->document->createTextNode(self::phpToXml((string) $value));
266+
$element->appendChild($text);
262267
} else {
263268
if (in_array($value, array('null', 'true', 'false'), true)) {
264269
$element->setAttribute('type', 'string');

src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Reference;
2020
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2121
use Symfony\Component\DependencyInjection\ContainerBuilder;
22+
use Symfony\Component\ExpressionLanguage\Expression;
2223

2324
/**
2425
* YamlDumper dumps a service container as a YAML string.
@@ -231,6 +232,8 @@ private function dumpValue($value)
231232
return $this->getServiceCall((string) $value, $value);
232233
} elseif ($value instanceof Parameter) {
233234
return $this->getParameterCall((string) $value);
235+
} elseif ($value instanceof Expression) {
236+
return $this->getExpressionCall((string) $value);
234237
} elseif (is_object($value) || is_resource($value)) {
235238
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
236239
}
@@ -267,6 +270,11 @@ private function getParameterCall($id)
267270
return sprintf('%%%s%%', $id);
268271
}
269272

273+
private function getExpressionCall($expression)
274+
{
275+
return sprintf('@=%s', $expression);
276+
}
277+
270278
/**
271279
* Prepares parameters.
272280
*
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection;
13+
14+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;
15+
16+
/**
17+
* Adds some function to the default ExpressionLanguage.
18+
*
19+
* To get a service, use service('request').
20+
* To get a parameter, use parameter('kernel.debug').
21+
*
22+
* @author Fabien Potencier <[email protected]>
23+
*/
24+
class ExpressionLanguage extends BaseExpressionLanguage
25+
{
26+
protected function registerFunctions()
27+
{
28+
parent::registerFunctions();
29+
30+
$this->addFunction('service', function ($arg) {
31+
return sprintf('$this->get(%s)', $arg);
32+
}, function (array $variables, $value) {
33+
return $variables['container']->get($value);
34+
});
35+
36+
$this->addFunction('parameter', function ($arg) {
37+
return sprintf('$this->getParameter(%s)', $arg);
38+
}, function (array $variables, $value) {
39+
return $variables['container']->getParameter($value);
40+
});
41+
}
42+
}

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
2020
use Symfony\Component\Config\Resource\FileResource;
2121
use Symfony\Component\Yaml\Parser as YamlParser;
22+
use Symfony\Component\ExpressionLanguage\Expression;
2223

2324
/**
2425
* YamlFileLoader loads YAML files service definitions.
@@ -311,6 +312,8 @@ private function resolveServices($value)
311312
{
312313
if (is_array($value)) {
313314
$value = array_map(array($this, 'resolveServices'), $value);
315+
} elseif (is_string($value) && 0 === strpos($value, '@=')) {
316+
return new Expression(substr($value, 2));
314317
} elseif (is_string($value) && 0 === strpos($value, '@')) {
315318
if (0 === strpos($value, '@@')) {
316319
$value = substr($value, 1);

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
<xsd:restriction base="xsd:string">
165165
<xsd:enumeration value="collection" />
166166
<xsd:enumeration value="service" />
167+
<xsd:enumeration value="expression" />
167168
<xsd:enumeration value="string" />
168169
<xsd:enumeration value="constant" />
169170
</xsd:restriction>

src/Symfony/Component/DependencyInjection/SimpleXMLElement.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection;
1313

1414
use Symfony\Component\Config\Util\XmlUtils;
15+
use Symfony\Component\ExpressionLanguage\Expression;
1516

1617
/**
1718
* SimpleXMLElement class.
@@ -77,6 +78,9 @@ public function getArgumentsAsPhp($name, $lowercase = true)
7778

7879
$arguments[$key] = new Reference((string) $arg['id'], $invalidBehavior, $strict);
7980
break;
81+
case 'expression':
82+
$arguments[$key] = new Expression((string) $arg);
83+
break;
8084
case 'collection':
8185
$arguments[$key] = $arg->getArgumentsAsPhp($name, false);
8286
break;

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
2626
use Symfony\Component\DependencyInjection\Scope;
2727
use Symfony\Component\Config\Resource\FileResource;
28+
use Symfony\Component\ExpressionLanguage\Expression;
2829

2930
class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
3031
{
@@ -377,6 +378,15 @@ public function testCreateSyntheticService()
377378
$builder->get('foo');
378379
}
379380

381+
public function testCreateServiceWithExpression()
382+
{
383+
$builder = new ContainerBuilder();
384+
$builder->setParameter('bar', 'bar');
385+
$builder->register('bar', 'BarClass');
386+
$builder->register('foo', 'FooClass')->addArgument(array('foo' => new Expression('service("bar").foo ~ parameter("bar")')));
387+
$this->assertEquals('foobar', $builder->get('foo')->arguments['foo']);
388+
}
389+
380390
/**
381391
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::resolveServices
382392
*/
@@ -386,6 +396,7 @@ public function testResolveServices()
386396
$builder->register('foo', 'FooClass');
387397
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances');
388398
$this->assertEquals(array('foo' => array('foo', $builder->get('foo'))), $builder->resolveServices(array('foo' => array('foo', new Reference('foo')))), '->resolveServices() resolves service references to service instances in nested arrays');
399+
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions');
389400
}
390401

391402
/**

src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Symfony\Component\DependencyInjection\ContainerBuilder;
77
use Symfony\Component\DependencyInjection\Reference;
88
use Symfony\Component\DependencyInjection\Parameter;
9+
use Symfony\Component\ExpressionLanguage\Expression;
910

1011
$container = new ContainerBuilder();
1112
$container->
@@ -50,7 +51,8 @@
5051
addMethodCall('setBar', array(new Reference('foo')))->
5152
addMethodCall('setBar', array(new Reference('foo2', ContainerInterface::NULL_ON_INVALID_REFERENCE)))->
5253
addMethodCall('setBar', array(new Reference('foo3', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))->
53-
addMethodCall('setBar', array(new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))
54+
addMethodCall('setBar', array(new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))->
55+
addMethodCall('setBar', array(new Expression('service("foo").foo() ~ parameter("foo")')))
5456
;
5557
$container->
5658
register('factory_service', 'Bar')->

src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ function sc_configure($instance)
88
class BarClass
99
{
1010
protected $baz;
11+
public $foo = 'foo';
1112

1213
public function setBaz(BazClass $baz)
1314
{

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ protected function getMethodCall1Service()
198198
if ($this->has('foobaz')) {
199199
$instance->setBar($this->get('foobaz', ContainerInterface::NULL_ON_INVALID_REFERENCE));
200200
}
201+
$instance->setBar(($this->get("foo")->foo() . $this->getParameter("foo")));
201202

202203
return $instance;
203204
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ protected function getMethodCall1Service()
203203

204204
$instance->setBar($this->get('foo'));
205205
$instance->setBar(NULL);
206+
$instance->setBar(($this->get("foo")->foo() . $this->getParameter("foo")));
206207

207208
return $instance;
208209
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
</service>
3333
<service id="method_call1" class="FooClass">
3434
<call method="setBar" />
35+
<call method="setBar">
36+
<argument type="expression">service("foo").foo() ~ parameter("foo")</argument>
37+
</call>
3538
</service>
3639
<service id="method_call2" class="FooClass">
3740
<call method="setBar">

src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
<call method="setBar">
5050
<argument type="service" id="foobaz" on-invalid="ignore"/>
5151
</call>
52+
<call method="setBar">
53+
<argument type="expression">service("foo").foo() ~ parameter("foo")</argument>
54+
</call>
5255
</service>
5356
<service id="factory_service" class="Bar" factory-method="getInstance" factory-service="foo.baz"/>
5457
<service id="foo_with_inline" class="Foo">

src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ services:
1515
calls:
1616
- [ setBar, [] ]
1717
- [ setBar ]
18+
- [ setBar, ['@=service("foo").foo() ~ parameter("foo")'] ]
1819
method_call2:
1920
class: FooClass
2021
calls:

src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ services:
3838
- [setBar, ['@?foo2']]
3939
- [setBar, ['@?foo3']]
4040
- [setBar, ['@?foobaz']]
41+
- [setBar, ['@=service("foo").foo() ~ parameter("foo")']]
4142

4243
factory_service:
4344
class: Bar

src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2323
use Symfony\Component\Config\Loader\LoaderResolver;
2424
use Symfony\Component\Config\FileLocator;
25+
use Symfony\Component\ExpressionLanguage\Expression;
2526

2627
class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
2728
{
@@ -211,7 +212,7 @@ public function testLoadServices()
211212
$this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag');
212213
$this->assertEquals(array(new Reference('baz', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false), 'configure'), $services['configurator2']->getConfigurator(), '->load() parses the configurator tag');
213214
$this->assertEquals(array('BazClass', 'configureStatic'), $services['configurator3']->getConfigurator(), '->load() parses the configurator tag');
214-
$this->assertEquals(array(array('setBar', array())), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag');
215+
$this->assertEquals(array(array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ parameter("foo")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag');
215216
$this->assertEquals(array(array('setBar', array('foo', new Reference('foo'), array(true, false)))), $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag');
216217
$this->assertNull($services['factory_service']->getClass());
217218
$this->assertEquals('getInstance', $services['factory_service']->getFactoryMethod());

src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2121
use Symfony\Component\Config\Loader\LoaderResolver;
2222
use Symfony\Component\Config\FileLocator;
23+
use Symfony\Component\ExpressionLanguage\Expression;
2324

2425
class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
2526
{
@@ -113,7 +114,7 @@ public function testLoadServices()
113114
$this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag');
114115
$this->assertEquals(array(new Reference('baz'), 'configure'), $services['configurator2']->getConfigurator(), '->load() parses the configurator tag');
115116
$this->assertEquals(array('BazClass', 'configureStatic'), $services['configurator3']->getConfigurator(), '->load() parses the configurator tag');
116-
$this->assertEquals(array(array('setBar', array()), array('setBar', array())), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag');
117+
$this->assertEquals(array(array('setBar', array()), array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ parameter("foo")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag');
117118
$this->assertEquals(array(array('setBar', array('foo', new Reference('foo'), array(true, false)))), $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag');
118119
$this->assertEquals('baz_factory', $services['factory_service']->getFactoryService());
119120

0 commit comments

Comments
 (0)