Skip to content

Commit e0fa7c2

Browse files
committed
Опциональное (по списку) превращение сервисов бандлов из приватных в публичные.
1 parent 4eca1f2 commit e0fa7c2

File tree

3 files changed

+213
-3
lines changed

3 files changed

+213
-3
lines changed

src/Bundles/BundlesLoader.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use InvalidArgumentException;
66
use Prokl\ServiceProvider\CompilePasses\MakePrivateCommandsPublic;
77
use Prokl\ServiceProvider\CompilePasses\MakePrivateEventsPublic;
8+
use Prokl\ServiceProvider\CompilePasses\MakePrivateServicePublic;
89
use Symfony\Component\DependencyInjection\ContainerBuilder;
910
use Symfony\Component\DependencyInjection\ContainerInterface;
1011
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -124,9 +125,10 @@ public function load() : void
124125

125126
// Сделать все приватные команды публичными.
126127
// Без этого они почему-то не подхватываются при загрузке бандлов.
127-
$this->container->addCompilerPass(
128-
new MakePrivateCommandsPublic()
129-
);
128+
$this->container->addCompilerPass(new MakePrivateCommandsPublic());
129+
130+
// Сделать сервисы публичными согласно параметру publicable_services.
131+
$this->container->addCompilerPass(new MakePrivateServicePublic());
130132
}
131133

132134
// Сохраняю инстанцированный бандл в статику.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Prokl\ServiceProvider\CompilePasses;
4+
5+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
6+
use Symfony\Component\DependencyInjection\ContainerBuilder;
7+
8+
/**
9+
* Class MakePrivateServicePublic
10+
* Сделать приватные сервисы публичными по заданному списку.
11+
* @package Prokl\ServiceProvider\CompilePasses
12+
*
13+
* @since 08.07.2021
14+
*/
15+
final class MakePrivateServicePublic implements CompilerPassInterface
16+
{
17+
/**
18+
* @inheritDoc
19+
*/
20+
public function process(ContainerBuilder $container) : void
21+
{
22+
if (!$container->hasParameter('publicable_services')) {
23+
return;
24+
}
25+
26+
$publicableServices = (array)$container->getParameter('publicable_services');
27+
28+
$services = $container->getServiceIds();
29+
30+
foreach ($services as $id => $service) {
31+
if (!$container->hasDefinition($service)
32+
||
33+
!in_array($service, $publicableServices, true)
34+
) {
35+
continue;
36+
}
37+
38+
$def = $container->getDefinition($service);
39+
$def->setPublic(true);
40+
}
41+
}
42+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<?php
2+
3+
namespace Prokl\ServiceProvider\Tests\Cases\CompilerPass;
4+
5+
use Exception;
6+
use Prokl\ServiceProvider\CompilePasses\MakePrivateServicePublic;
7+
use Prokl\TestingTools\Base\BaseTestCase;
8+
use Symfony\Component\DependencyInjection\ContainerBuilder;
9+
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
10+
11+
/**
12+
* Class MakePrivateServicePublicTest
13+
* @package Prokl\ServiceProvider\Tests\Cases\CompilerPass
14+
* @coversDefaultClass MakePrivateServicePublic
15+
*
16+
* @since 08.07.2021.
17+
*/
18+
class MakePrivateServicePublicTest extends BaseTestCase
19+
{
20+
/**
21+
* @var MakePrivateServicePublic $obTestObject Тестируемый объект.
22+
*/
23+
protected $obTestObject;
24+
25+
/**
26+
* @var object $stubService Сервис.
27+
*/
28+
private $stubService;
29+
30+
/**
31+
* @inheritDoc
32+
*/
33+
protected function setUp(): void
34+
{
35+
parent::setUp();
36+
37+
$this->obTestObject = new MakePrivateServicePublic();
38+
$this->stubService = $this->getStubService();
39+
}
40+
41+
/**
42+
* process(). Нормальный ход событий.
43+
*
44+
* @return void
45+
* @throws Exception
46+
*
47+
*/
48+
public function testProcess(): void
49+
{
50+
$service = $this->getStubService();
51+
$testContainerBuilder = $this->getTestContainer(
52+
'test_service',
53+
get_class($service),
54+
['test_service']
55+
);
56+
57+
$this->obTestObject->process($testContainerBuilder);
58+
$testContainerBuilder->compile();
59+
60+
$result = $testContainerBuilder->get('test_service');
61+
62+
$this->assertInstanceOf(get_class($service), $result);
63+
}
64+
65+
/**
66+
* process(). Пустой список сервисов, подлежащих обращению.
67+
*
68+
* @return void
69+
* @throws Exception
70+
*
71+
*/
72+
public function testProcessEmptyParams(): void
73+
{
74+
$service = $this->getStubService();
75+
$testContainerBuilder = $this->getTestContainer(
76+
'test_service',
77+
get_class($service),
78+
[]
79+
);
80+
81+
$this->obTestObject->process($testContainerBuilder);
82+
$testContainerBuilder->compile();
83+
84+
$this->expectException(ServiceNotFoundException::class);
85+
$this->expectExceptionMessage(
86+
'The "test_service" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'
87+
);
88+
89+
$testContainerBuilder->get('test_service');
90+
}
91+
92+
/**
93+
* process(). Сервис не в списке подлежащих обращению в public.
94+
*
95+
* @return void
96+
* @throws Exception
97+
*
98+
*/
99+
public function testProcessNotInPublicableList(): void
100+
{
101+
$service = $this->getStubService();
102+
$testContainerBuilder = $this->getTestContainer(
103+
'test_service',
104+
get_class($service),
105+
['test_service2']
106+
);
107+
108+
$this->obTestObject->process($testContainerBuilder);
109+
$testContainerBuilder->compile();
110+
111+
$this->expectException(ServiceNotFoundException::class);
112+
$this->expectExceptionMessage(
113+
'The "test_service" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'
114+
);
115+
116+
$testContainerBuilder->get('test_service');
117+
}
118+
119+
/**
120+
* Мок сервиса.
121+
*
122+
* @return mixed
123+
*/
124+
private function getStubService()
125+
{
126+
return new class {
127+
/**
128+
* @var boolean $running Признак - запускался ли сервис.
129+
*/
130+
public $running = false;
131+
132+
public function __construct()
133+
{
134+
$this->running = true;
135+
}
136+
137+
public function addEvent(): void
138+
{
139+
}
140+
};
141+
}
142+
143+
/**
144+
* Тестовый контейнер.
145+
*
146+
* @param string $serviceId ID сервиса.
147+
* @param string|null $class Класс сервиса.
148+
* @param array $publicableServices
149+
*
150+
* @return ContainerBuilder
151+
*/
152+
private function getTestContainer(
153+
string $serviceId,
154+
?string $class = null,
155+
array $publicableServices = []
156+
): ContainerBuilder {
157+
$container = new ContainerBuilder();
158+
$container
159+
->register($serviceId, $class ?? get_class($this->stubService))
160+
->setPublic(false);
161+
162+
$container->setParameter('publicable_services', $publicableServices);
163+
164+
return $container;
165+
}
166+
}

0 commit comments

Comments
 (0)