Skip to content

Commit 13edce2

Browse files
author
Hugo Hamon
committed
[DependencyInjection] deprecate access to private shared services. Fixes issue #19117.
1 parent 6e03a42 commit 13edce2

File tree

7 files changed

+134
-7
lines changed

7 files changed

+134
-7
lines changed

UPGRADE-4.0.md

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ DependencyInjection
1818

1919
* Using unsupported options to configure service aliases raises an exception.
2020

21+
* Setting or unsetting a private service with the `Container::set()` method is
22+
no longer supported. Only public services can be set or unset.
23+
24+
* Checking the existence of a private service with the `Container::has()`
25+
method is no longer supported.
26+
27+
* Requesting a private service with the `Container::get()` method is no longer
28+
supported.
29+
2130
Form
2231
----
2332

src/Symfony/Component/DependencyInjection/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ CHANGELOG
66

77
* allowed to prioritize compiler passes by introducing a third argument to `PassConfig::addPass()`, to `Compiler::addPass` and to `ContainerBuilder::addCompilerPass()`
88
* added support for PHP constants in YAML configuration files
9+
* deprecated the ability to set or unset a private service with the `Container::set()` method
10+
* deprecated the ability to check for the existence of a private service with the `Container::has()` method
11+
* deprecated the ability to request a private service with the `Container::get()` method
912

1013
3.0.0
1114
-----

src/Symfony/Component/DependencyInjection/Container.php

+16
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class Container implements ResettableContainerInterface
6565

6666
protected $services = array();
6767
protected $methodMap = array();
68+
protected $privates = array();
6869
protected $aliases = array();
6970
protected $loading = array();
7071

@@ -176,6 +177,14 @@ public function set($id, $service)
176177
if (null === $service) {
177178
unset($this->services[$id]);
178179
}
180+
181+
if (isset($this->privates[$id])) {
182+
if (null === $service) {
183+
@trigger_error(sprintf('Unsetting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED);
184+
} else {
185+
@trigger_error(sprintf('Setting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0. A new public service will be created instead.', $id), E_USER_DEPRECATED);
186+
}
187+
}
179188
}
180189

181190
/**
@@ -198,6 +207,10 @@ public function has($id)
198207
if (--$i && $id !== $lcId = strtolower($id)) {
199208
$id = $lcId;
200209
} else {
210+
if (isset($this->privates[$id])) {
211+
@trigger_error(sprintf('Checking for the existence of the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED);
212+
}
213+
201214
return method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service');
202215
}
203216
}
@@ -268,6 +281,9 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE
268281

269282
return;
270283
}
284+
if (isset($this->privates[$id])) {
285+
@trigger_error(sprintf('Requesting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED);
286+
}
271287

272288
$this->loading[$id] = true;
273289

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -559,11 +559,12 @@ public function compile()
559559
$compiler->compile($this);
560560
$this->compiled = true;
561561

562-
if ($this->trackResources) {
563-
foreach ($this->definitions as $definition) {
564-
if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
565-
$this->addClassResource(new \ReflectionClass($class));
566-
}
562+
foreach ($this->definitions as $id => $definition) {
563+
if (!$definition->isPublic()) {
564+
$this->privates[$id] = true;
565+
}
566+
if ($this->trackResources && $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
567+
$this->addClassResource(new \ReflectionClass($class));
567568
}
568569
}
569570

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

+31
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ public function __construct()
804804
EOF;
805805

806806
$code .= $this->addMethodMap();
807+
$code .= $this->addPrivateServices();
807808
$code .= $this->addAliases();
808809

809810
$code .= <<<'EOF'
@@ -888,6 +889,36 @@ private function addMethodMap()
888889
return $code." );\n";
889890
}
890891

892+
/**
893+
* Adds the privates property definition.
894+
*
895+
* @return string
896+
*/
897+
private function addPrivateServices()
898+
{
899+
if (!$definitions = $this->container->getDefinitions()) {
900+
return '';
901+
}
902+
903+
$code = '';
904+
ksort($definitions);
905+
foreach ($definitions as $id => $definition) {
906+
if (!$definition->isPublic()) {
907+
$code .= ' '.var_export($id, true)." => true,\n";
908+
}
909+
}
910+
911+
if (empty($code)) {
912+
return '';
913+
}
914+
915+
$out = " \$this->privates = array(\n";
916+
$out .= $code;
917+
$out .= " );\n";
918+
919+
return $out;
920+
}
921+
891922
/**
892923
* Adds the aliases property definition.
893924
*

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

+62-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Tests;
1313

14+
use Symfony\Bridge\PhpUnit\ErrorAssert;
1415
use Symfony\Component\DependencyInjection\Container;
1516
use Symfony\Component\DependencyInjection\ContainerInterface;
1617
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -125,7 +126,7 @@ public function testGetServiceIds()
125126

126127
$sc = new ProjectServiceContainer();
127128
$sc->set('foo', $obj = new \stdClass());
128-
$this->assertEquals(array('bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container', 'foo'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods, followed by service ids defined by set()');
129+
$this->assertEquals(array('internal', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container', 'foo'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods, followed by service ids defined by set()');
129130
}
130131

131132
public function testSet()
@@ -306,11 +307,63 @@ public function testThatCloningIsNotSupported()
306307
$this->assertFalse($class->isCloneable());
307308
$this->assertTrue($clone->isPrivate());
308309
}
310+
311+
/** @group legacy */
312+
public function testUnsetInternalPrivateServiceIsDeprecated()
313+
{
314+
$deprecations = array(
315+
'Unsetting the "internal" private service from outside of the container is deprecated since Symfony 3.2',
316+
);
317+
318+
ErrorAssert::assertDeprecationsAreTriggered($deprecations, function () {
319+
$c = new ProjectServiceContainer();
320+
$c->set('internal', null);
321+
});
322+
}
323+
324+
/** @group legacy */
325+
public function testChangeInternalPrivateServiceIsDeprecated()
326+
{
327+
$deprecations = array(
328+
'Resetting the "internal" private service from outside of the container is deprecated since Symfony 3.2',
329+
);
330+
331+
ErrorAssert::assertDeprecationsAreTriggered($deprecations, function () {
332+
$c = new ProjectServiceContainer();
333+
$c->set('internal', new \stdClass());
334+
});
335+
}
336+
337+
/** @group legacy */
338+
public function testCheckExistenceOfAnInternalPrivateServiceIsDeprecated()
339+
{
340+
$deprecations = array(
341+
'Checking for the existence of the "internal" private service is deprecated since Symfony 3.2',
342+
);
343+
344+
ErrorAssert::assertDeprecationsAreTriggered($deprecations, function () {
345+
$c = new ProjectServiceContainer();
346+
$c->has('internal');
347+
});
348+
}
349+
350+
/** @group legacy */
351+
public function testRequestAnInternalSharedPrivateServiceIsDeprecated()
352+
{
353+
$deprecations = array(
354+
'Requesting the "internal" private service is deprecated since Symfony 3.2',
355+
);
356+
357+
ErrorAssert::assertDeprecationsAreTriggered($deprecations, function () {
358+
$c = new ProjectServiceContainer();
359+
$c->get('internal');
360+
});
361+
}
309362
}
310363

311364
class ProjectServiceContainer extends Container
312365
{
313-
public $__bar, $__foo_bar, $__foo_baz;
366+
public $__bar, $__foo_bar, $__foo_baz, $__internal;
314367

315368
public function __construct()
316369
{
@@ -319,9 +372,16 @@ public function __construct()
319372
$this->__bar = new \stdClass();
320373
$this->__foo_bar = new \stdClass();
321374
$this->__foo_baz = new \stdClass();
375+
$this->__internal = new \stdClass();
376+
$this->privates = array('internal' => true);
322377
$this->aliases = array('alias' => 'bar');
323378
}
324379

380+
protected function getInternalService()
381+
{
382+
return $this->__internal;
383+
}
384+
325385
protected function getBarService()
326386
{
327387
return $this->__bar;

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

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ public function __construct()
4949
'request' => 'getRequestService',
5050
'service_from_static_method' => 'getServiceFromStaticMethodService',
5151
);
52+
$this->privates = array(
53+
'configurator_service' => true,
54+
'configurator_service_simple' => true,
55+
'factory_simple' => true,
56+
'inlined' => true,
57+
'new_factory' => true,
58+
);
5259
$this->aliases = array(
5360
'alias_for_alias' => 'foo',
5461
'alias_for_foo' => 'foo',

0 commit comments

Comments
 (0)