Skip to content

Commit e72f59f

Browse files
[DI] Add "PHP fluent format" for configuring the container
1 parent fd16993 commit e72f59f

20 files changed

+1337
-2
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function registerClasses(Definition $prototype, $namespace, $resource, $e
7373
* @param string $id
7474
* @param Definition $definition
7575
*/
76-
protected function setDefinition($id, Definition $definition)
76+
public function setDefinition($id, Definition $definition)
7777
{
7878
if ($this->isLoadingInstanceof) {
7979
if (!$definition instanceof ChildDefinition) {

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

+89-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,17 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Loader;
1313

14-
use Symfony\Component\Config\Resource\FileResource;
14+
require_once __DIR__.'/PhpFileLoader/functions.php';
15+
16+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
17+
use Symfony\Component\DependencyInjection\Definition;
18+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
19+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader\InlineConfigurator;
20+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader\Internal\AbstractRootConfigurator;
21+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader\ReferenceConfigurator;
22+
use Symfony\Component\DependencyInjection\Parameter;
23+
use Symfony\Component\DependencyInjection\Reference;
24+
use Symfony\Component\ExpressionLanguage\Expression;
1525

1626
/**
1727
* PhpFileLoader loads service definitions from a PHP file.
@@ -23,6 +33,8 @@
2333
*/
2434
class PhpFileLoader extends FileLoader
2535
{
36+
private $defaults;
37+
2638
/**
2739
* {@inheritdoc}
2840
*/
@@ -35,6 +47,8 @@ public function load($resource, $type = null)
3547
$path = $this->locator->locate($resource);
3648
$this->setCurrentDir(dirname($path));
3749
$this->container->fileExists($path);
50+
$this->defaults = new Definition();
51+
$this->instanceof = array();
3852

3953
include $path;
4054
}
@@ -54,4 +68,78 @@ public function supports($resource, $type = null)
5468

5569
return 'php' === $type;
5670
}
71+
72+
/**
73+
* @internal
74+
*/
75+
public static function call(\Closure $callback)
76+
{
77+
$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 4);
78+
if (!isset($trace[3]['object']) || !$trace[3]['object'] instanceof self) {
79+
throw new \ErrorException(sprintf('Function "%s()" must be called in a "%s" context.', $trace[1]['function'], __CLASS__), 0, E_ERROR, $trace[1]['file'], $trace[1]['line']);
80+
}
81+
$callback = $callback->bindTo($trace[3]['object'], __CLASS__);
82+
83+
return $callback($trace[3]['object']->defaults, $trace[1]['file']);
84+
}
85+
86+
/**
87+
* @internal
88+
*/
89+
public static function processValue($value)
90+
{
91+
if (is_array($value)) {
92+
foreach ($value as $k => $v) {
93+
$value[$k] = self::processValue($v);
94+
}
95+
96+
return $value;
97+
}
98+
99+
if ($value instanceof ReferenceConfigurator) {
100+
static $refCast;
101+
102+
if (!$refCast) {
103+
$refCast = \Closure::bind(function ($value) {
104+
return new Reference($value->id, $value->invalidBehavior);
105+
}, $value, $value);
106+
}
107+
108+
// cast ReferenceConfigurator to Reference
109+
return $refCast($value);
110+
}
111+
112+
if ($value instanceof InlineConfigurator) {
113+
static $defCast;
114+
115+
if (!$defCast) {
116+
$defCast = \Closure::bind(function ($value) {
117+
$def = $value->definition;
118+
$value->definition = null;
119+
120+
return $def;
121+
}, $value, $value);
122+
}
123+
124+
// cast InlineConfigurator to Definition
125+
return $defCast($value);
126+
}
127+
128+
if ($value instanceof AbstractRootConfigurator) {
129+
throw new InvalidArgumentException(sprintf('"%s()" can be used only at the root of service configuration files.', $value::FACTORY));
130+
}
131+
132+
switch (true) {
133+
case null === $value:
134+
case is_scalar($value):
135+
case $value instanceof ArgumentInterface:
136+
case $value instanceof Definition:
137+
case $value instanceof Expression:
138+
case $value instanceof Parameter:
139+
case $value instanceof Reference:
140+
return $value;
141+
}
142+
143+
throw new InvalidArgumentException(sprintf('Cannot use values of type "%s" in service configuration files.', is_object($value) ? get_class($value) : gettype($value)));
144+
}
57145
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Loader\PhpFileLoader;
13+
14+
use Symfony\Component\DependencyInjection\Alias;
15+
16+
/**
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @method $this public()
20+
* @method $this private()
21+
*/
22+
class AliasConfigurator extends Internal\AbstractRootConfigurator
23+
{
24+
const FACTORY = 'alias';
25+
26+
private $alias;
27+
28+
public function __construct(Alias $alias)
29+
{
30+
$this->alias = $alias;
31+
}
32+
33+
/**
34+
* @return $this
35+
*/
36+
protected function setPublic()
37+
{
38+
$this->alias->setPublic(true);
39+
40+
return $this;
41+
}
42+
43+
/**
44+
* @return $this
45+
*/
46+
protected function setPrivate()
47+
{
48+
$this->alias->setPublic(false);
49+
50+
return $this;
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Loader\PhpFileLoader;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*
17+
* @method $this class()
18+
* @method $this parent()
19+
*/
20+
class ChildConfigurator extends Internal\AbstractPrototypeConfigurator
21+
{
22+
const FACTORY = 'service';
23+
24+
/**
25+
* Sets the Definition being decorated.
26+
*
27+
* @param string $parent
28+
*
29+
* @return $this
30+
*/
31+
protected function setParent($parent)
32+
{
33+
$this->definition->setParent($parent);
34+
35+
return $this;
36+
}
37+
38+
/**
39+
* Sets the service that this service is decorating.
40+
*
41+
* @param null|string $id The decorated service id, use null to remove decoration
42+
* @param null|string $renamedId The new decorated service id
43+
* @param int $priority The priority of decoration
44+
*
45+
* @return $this
46+
*
47+
* @throws InvalidArgumentException In case the decorated service id and the new decorated service id are equals.
48+
*/
49+
public function decorate($id, $renamedId = null, $priority = 0)
50+
{
51+
$this->definition->setDecoratedService($id, $renamedId, $priority);
52+
53+
return $this;
54+
}
55+
56+
/**
57+
* Sets the service class.
58+
*
59+
* @param string $class The service class
60+
*
61+
* @return $this
62+
*/
63+
protected function setClass($class)
64+
{
65+
$this->definition->setClass($class);
66+
67+
return $this;
68+
}
69+
70+
/**
71+
* Sets a file to require before creating the service.
72+
*
73+
* @param string $file A full pathname to include
74+
*
75+
* @return $this
76+
*/
77+
public function file($file)
78+
{
79+
$this->definition->setFile($file);
80+
81+
return $this;
82+
}
83+
84+
/**
85+
* Sets whether this definition is synthetic, that is not constructed by the
86+
* container, but dynamically injected.
87+
*
88+
* @param bool $synthetic
89+
*
90+
* @return $this
91+
*/
92+
public function synthetic($synthetic = true)
93+
{
94+
$this->definition->setSynthetic($synthetic);
95+
96+
return $this;
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Loader\PhpFileLoader;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*/
17+
class DefaultsConfigurator extends Internal\AbstractDefaultsConfigurator
18+
{
19+
const FACTORY = '_defaults';
20+
21+
use Internal\BindTrait;
22+
23+
/**
24+
* Sets whether or not instanceof conditionals should be prepended with a global set.
25+
*
26+
* @return $this
27+
*/
28+
public function autoconfigure($autoconfigured = true)
29+
{
30+
$this->definition->setAutoconfigured($autoconfigured);
31+
32+
return $this;
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Loader\PhpFileLoader;
13+
14+
use Symfony\Component\DependencyInjection\ChildDefinition;
15+
use Symfony\Component\DependencyInjection\Definition;
16+
17+
/**
18+
* @author Nicolas Grekas <p@tchwork.com>
19+
*/
20+
class InlineConfigurator extends ChildConfigurator
21+
{
22+
use Internal\BindTrait;
23+
24+
public function __construct($class)
25+
{
26+
$this->definition = new Definition();
27+
$this->definition->setPublic(false);
28+
$this->definition->setClass($class);
29+
}
30+
31+
/**
32+
* Sets the Definition to inherit from.
33+
*
34+
* @param string $parent
35+
*
36+
* @return ChildConfigurator
37+
*/
38+
protected function setParent($parent)
39+
{
40+
// cast Definition to ChildDefinition
41+
$definition = serialize($this->definition);
42+
$definition = substr_replace($definition, '53', 2, 2);
43+
$definition = substr_replace($definition, 'Child', 44, 0);
44+
$definition = unserialize($definition);
45+
$definition->setParent($parent);
46+
47+
return new ChildConfigurator(null, $this->definition = $definition, $this->defaultTags);
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Loader\PhpFileLoader;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*/
17+
class InstanceofConfigurator extends Internal\AbstractInstanceofConfigurator
18+
{
19+
const FACTORY = '_instanceof';
20+
}

0 commit comments

Comments
 (0)