Skip to content

Commit 0170965

Browse files
[DependencyInjection] make paths relative to __DIR__ in the generated container
1 parent 0a67629 commit 0170965

File tree

3 files changed

+182
-5
lines changed

3 files changed

+182
-5
lines changed

Dumper/PhpDumper.php

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class PhpDumper extends Dumper
5151
private $referenceVariables;
5252
private $variableCount;
5353
private $reservedVariables = array('instance', 'class');
54+
private $targetDirRegex;
55+
private $targetDirMaxMatches;
5456

5557
/**
5658
* @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
@@ -95,11 +97,35 @@ public function setProxyDumper(ProxyDumper $proxyDumper)
9597
*/
9698
public function dump(array $options = array())
9799
{
100+
$this->targetDirRegex = null;
98101
$options = array_merge(array(
99102
'class' => 'ProjectServiceContainer',
100103
'base_class' => 'Container',
101104
), $options);
102105

106+
if (!empty($options['file']) && is_dir($dir = dirname($options['file']))) {
107+
// Build a regexp where the first two root dirs are mandatory,
108+
// but every other sub-dir is optional up to the full path in $dir
109+
110+
$dir = explode(DIRECTORY_SEPARATOR, realpath($dir));
111+
$i = count($dir);
112+
113+
if (3 <= $i) {
114+
$regex = '';
115+
$this->targetDirMaxMatches = $i - 3;
116+
117+
while (2 < --$i) {
118+
$regex = sprintf('(%s%s)?', preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
119+
}
120+
121+
do {
122+
$regex = preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
123+
} while (0 < --$i);
124+
125+
$this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#';
126+
}
127+
}
128+
103129
$code = $this->startClass($options['class'], $options['base_class']);
104130

105131
if ($this->container->isFrozen()) {
@@ -114,6 +140,7 @@ public function dump(array $options = array())
114140
$this->endClass().
115141
$this->addProxyClasses()
116142
;
143+
$this->targetDirRegex = null;
117144

118145
return $code;
119146
}
@@ -979,7 +1006,7 @@ private function exportParameters($parameters, $path = '', $indent = 12)
9791006
} elseif ($value instanceof Reference) {
9801007
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
9811008
} else {
982-
$value = var_export($value, true);
1009+
$value = $this->export($value);
9831010
}
9841011

9851012
$php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
@@ -1214,14 +1241,14 @@ private function dumpValue($value, $interpolate = true)
12141241
return "'.".$that->dumpParameter(strtolower($match[2])).".'";
12151242
};
12161243

1217-
$code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, var_export($value, true)));
1244+
$code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
12181245

12191246
return $code;
12201247
}
12211248
} elseif (is_object($value) || is_resource($value)) {
12221249
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
12231250
} else {
1224-
return var_export($value, true);
1251+
return $this->export($value);
12251252
}
12261253
}
12271254

@@ -1323,4 +1350,26 @@ private function getNextVariableName()
13231350
return $name;
13241351
}
13251352
}
1353+
1354+
private function export($value)
1355+
{
1356+
if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {
1357+
$prefix = $matches[0][1] ? var_export(substr($value, 0, $matches[0][1]), true).'.' : '';
1358+
$suffix = $matches[0][1] + strlen($matches[0][0]);
1359+
$suffix = isset($value[$suffix]) ? '.'.var_export(substr($value, $suffix), true) : '';
1360+
$dirname = '__DIR__';
1361+
1362+
for ($i = $this->targetDirMaxMatches - count($matches); 0 <= $i; --$i) {
1363+
$dirname = sprintf('dirname(%s)', $dirname);
1364+
}
1365+
1366+
if ($prefix || $suffix) {
1367+
return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
1368+
}
1369+
1370+
return $dirname;
1371+
}
1372+
1373+
return var_export($value, true);
1374+
}
13261375
}

Tests/Dumper/PhpDumperTest.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,24 @@ public function testDumpOptimizationString()
8080
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services10.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class');
8181
}
8282

83+
public function testDumpRelativeDir()
84+
{
85+
$definition = new Definition();
86+
$definition->setClass('stdClass');
87+
$definition->addArgument('%foo%');
88+
$definition->addArgument(array('%foo%' => '%foo%'));
89+
90+
$container = new ContainerBuilder();
91+
$container->setDefinition('test', $definition);
92+
$container->setParameter('foo', 'wiz'.dirname(dirname(__FILE__)));
93+
$container->setParameter('bar', dirname(__FILE__));
94+
$container->setParameter('baz', '%bar%/PhpDumperTest.php');
95+
$container->compile();
96+
97+
$dumper = new PhpDumper($container);
98+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services12.php', $dumper->dump(array('file' => __FILE__)), '->dump() dumps __DIR__ relative strings');
99+
}
100+
83101
/**
84102
* @expectedException \InvalidArgumentException
85103
*/
@@ -101,13 +119,13 @@ public function testAddService()
101119
// without compilation
102120
$container = include self::$fixturesPath.'/containers/container9.php';
103121
$dumper = new PhpDumper($container);
104-
$this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services');
122+
$this->assertEquals(str_replace('%path%', str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services');
105123

106124
// with compilation
107125
$container = include self::$fixturesPath.'/containers/container9.php';
108126
$container->compile();
109127
$dumper = new PhpDumper($container);
110-
$this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9_compiled.php')), $dumper->dump(), '->dump() dumps services');
128+
$this->assertEquals(str_replace('%path%', str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9_compiled.php')), $dumper->dump(), '->dump() dumps services');
111129

112130
$dumper = new PhpDumper($container = new ContainerBuilder());
113131
$container->register('foo', 'FooClass')->addArgument(new \stdClass());

Tests/Fixtures/php/services12.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\ContainerInterface;
4+
use Symfony\Component\DependencyInjection\Container;
5+
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
6+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
7+
use Symfony\Component\DependencyInjection\Exception\LogicException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
11+
/**
12+
* ProjectServiceContainer
13+
*
14+
* This class has been auto-generated
15+
* by the Symfony Dependency Injection Component.
16+
*/
17+
class ProjectServiceContainer extends Container
18+
{
19+
/**
20+
* Constructor.
21+
*/
22+
public function __construct()
23+
{
24+
$this->parameters = $this->getDefaultParameters();
25+
26+
$this->services =
27+
$this->scopedServices =
28+
$this->scopeStacks = array();
29+
30+
$this->set('service_container', $this);
31+
32+
$this->scopes = array();
33+
$this->scopeChildren = array();
34+
$this->methodMap = array(
35+
'test' => 'getTestService',
36+
);
37+
38+
$this->aliases = array();
39+
}
40+
41+
/**
42+
* Gets the 'test' service.
43+
*
44+
* This service is shared.
45+
* This method always returns the same instance of the service.
46+
*
47+
* @return \stdClass A stdClass instance.
48+
*/
49+
protected function getTestService()
50+
{
51+
return $this->services['test'] = new \stdClass(('wiz'.dirname(__DIR__)), array(('wiz'.dirname(__DIR__)) => ('wiz'.dirname(__DIR__))));
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function getParameter($name)
58+
{
59+
$name = strtolower($name);
60+
61+
if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) {
62+
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
63+
}
64+
65+
return $this->parameters[$name];
66+
}
67+
68+
/**
69+
* {@inheritdoc}
70+
*/
71+
public function hasParameter($name)
72+
{
73+
$name = strtolower($name);
74+
75+
return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters);
76+
}
77+
78+
/**
79+
* {@inheritdoc}
80+
*/
81+
public function setParameter($name, $value)
82+
{
83+
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
84+
}
85+
86+
/**
87+
* {@inheritdoc}
88+
*/
89+
public function getParameterBag()
90+
{
91+
if (null === $this->parameterBag) {
92+
$this->parameterBag = new FrozenParameterBag($this->parameters);
93+
}
94+
95+
return $this->parameterBag;
96+
}
97+
/**
98+
* Gets the default parameters.
99+
*
100+
* @return array An array of the default parameters
101+
*/
102+
protected function getDefaultParameters()
103+
{
104+
return array(
105+
'foo' => ('wiz'.dirname(__DIR__)),
106+
'bar' => __DIR__,
107+
'baz' => (__DIR__.'/PhpDumperTest.php'),
108+
);
109+
}
110+
}

0 commit comments

Comments
 (0)