Skip to content

Commit 8f57480

Browse files
authored
Add decorator support to ServiceMap. (#615)
* Add decorator support to ServiceMap. * PHPCS Cleanup. * PHPStan cleanup.
1 parent 48a390e commit 8f57480

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/Drupal/DrupalServiceDefinition.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPStan\Type\ObjectType;
66
use PHPStan\Type\StringType;
77
use PHPStan\Type\Type;
8+
use PHPStan\Type\UnionType;
89

910
class DrupalServiceDefinition
1011
{
@@ -44,6 +45,11 @@ class DrupalServiceDefinition
4445
*/
4546
private $alias;
4647

48+
/**
49+
* @var array<string, \mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition>
50+
*/
51+
private $decorators = [];
52+
4753
public function __construct(string $id, ?string $class, bool $public = true, ?string $alias = null)
4854
{
4955
$this->id = $id;
@@ -109,6 +115,28 @@ public function getType(): Type
109115
return new StringType();
110116
}
111117

118+
$decorating_services = $this->getDecorators();
119+
if (count($decorating_services) !== 0) {
120+
$combined_services = [];
121+
$combined_services[] = new ObjectType($this->getClass() ?? $this->id);
122+
foreach ($decorating_services as $service_id => $service_definition) {
123+
$combined_services[] = $service_definition->getType();
124+
}
125+
return new UnionType($combined_services);
126+
}
112127
return new ObjectType($this->getClass() ?? $this->id);
113128
}
129+
130+
public function addDecorator(DrupalServiceDefinition $definition): void
131+
{
132+
$this->decorators[$definition->getId()] = $definition;
133+
}
134+
135+
/**
136+
* @return array<string, \mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition>
137+
*/
138+
public function getDecorators(): array
139+
{
140+
return $this->decorators;
141+
}
114142
}

src/Drupal/ServiceMap.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function getServices(): array
2323
public function setDrupalServices(array $drupalServices): void
2424
{
2525
self::$services = [];
26+
$decorators = [];
2627

2728
foreach ($drupalServices as $serviceId => $serviceDefinition) {
2829
if (isset($serviceDefinition['alias'], $drupalServices[$serviceDefinition['alias']])) {
@@ -32,6 +33,10 @@ public function setDrupalServices(array $drupalServices): void
3233
$serviceDefinition = $this->resolveParentDefinition($serviceDefinition['parent'], $serviceDefinition, $drupalServices);
3334
}
3435

36+
if (isset($serviceDefinition['decorates'])) {
37+
$decorators[$serviceDefinition['decorates']][] = $serviceId;
38+
}
39+
3540
// @todo support factories
3641
if (!isset($serviceDefinition['class'])) {
3742
if (class_exists($serviceId)) {
@@ -51,6 +56,12 @@ public function setDrupalServices(array $drupalServices): void
5156
self::$services[$serviceId]->setDeprecated(true, $deprecated);
5257
}
5358
}
59+
60+
foreach ($decorators as $decorated_service_id => $services) {
61+
foreach ($services as $dcorating_service_id) {
62+
self::$services[$decorated_service_id]->addDecorator(self::$services[$dcorating_service_id]);
63+
}
64+
}
5465
}
5566

5667
private function resolveParentDefinition(string $parentId, array $serviceDefinition, array $drupalServices): array

tests/src/ServiceMapFactoryTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use Drupal\Core\Logger\LoggerChannel;
66
use mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition;
77
use mglaman\PHPStanDrupal\Drupal\ServiceMap;
8+
use PHPStan\Type\ObjectType;
9+
use PHPStan\Type\UnionType;
810
use PHPUnit\Framework\TestCase;
911

1012
final class ServiceMapFactoryTest extends TestCase
@@ -93,6 +95,14 @@ public function testFactory(string $id, callable $validator): void
9395
],
9496
'Psr\Log\LoggerInterface $loggerWorkspaces' => [
9597
'alias' => 'logger.channel.workspaces'
98+
],
99+
'service_map.base_to_be_decorated' => [
100+
'class' => 'Drupal\service_map\Base',
101+
'abstract' => true,
102+
],
103+
'service_map.deocrating_base' => [
104+
'decorates' => 'service_map.base_to_be_decorated',
105+
'class' => 'Drupal\service_map\SecondBase',
96106
]
97107
]);
98108
$validator($service->getService($id));
@@ -212,6 +222,17 @@ function (DrupalServiceDefinition $service): void {
212222
self::assertEquals(LoggerChannel::class, $service->getClass());
213223
}
214224
];
225+
yield [
226+
'service_map.base_to_be_decorated',
227+
function (DrupalServiceDefinition $service): void {
228+
$combined_class = [
229+
new ObjectType('Drupal\service_map\Base'),
230+
new ObjectType('Drupal\service_map\SecondBase')
231+
];
232+
$expected_class = new UnionType($combined_class);
233+
self::assertEquals($expected_class, $service->getType());
234+
}
235+
];
215236
}
216237

217238
}

0 commit comments

Comments
 (0)