Skip to content

Commit

Permalink
Add decorator support to ServiceMap. (#615)
Browse files Browse the repository at this point in the history
* Add decorator support to ServiceMap.

* PHPCS Cleanup.

* PHPStan cleanup.
  • Loading branch information
cmlara authored Nov 3, 2023
1 parent 48a390e commit 8f57480
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/Drupal/DrupalServiceDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;

class DrupalServiceDefinition
{
Expand Down Expand Up @@ -44,6 +45,11 @@ class DrupalServiceDefinition
*/
private $alias;

/**
* @var array<string, \mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition>
*/
private $decorators = [];

public function __construct(string $id, ?string $class, bool $public = true, ?string $alias = null)
{
$this->id = $id;
Expand Down Expand Up @@ -109,6 +115,28 @@ public function getType(): Type
return new StringType();
}

$decorating_services = $this->getDecorators();
if (count($decorating_services) !== 0) {
$combined_services = [];
$combined_services[] = new ObjectType($this->getClass() ?? $this->id);
foreach ($decorating_services as $service_id => $service_definition) {
$combined_services[] = $service_definition->getType();
}
return new UnionType($combined_services);
}
return new ObjectType($this->getClass() ?? $this->id);
}

public function addDecorator(DrupalServiceDefinition $definition): void
{
$this->decorators[$definition->getId()] = $definition;
}

/**
* @return array<string, \mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition>
*/
public function getDecorators(): array
{
return $this->decorators;
}
}
11 changes: 11 additions & 0 deletions src/Drupal/ServiceMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function getServices(): array
public function setDrupalServices(array $drupalServices): void
{
self::$services = [];
$decorators = [];

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

if (isset($serviceDefinition['decorates'])) {
$decorators[$serviceDefinition['decorates']][] = $serviceId;
}

// @todo support factories
if (!isset($serviceDefinition['class'])) {
if (class_exists($serviceId)) {
Expand All @@ -51,6 +56,12 @@ public function setDrupalServices(array $drupalServices): void
self::$services[$serviceId]->setDeprecated(true, $deprecated);
}
}

foreach ($decorators as $decorated_service_id => $services) {
foreach ($services as $dcorating_service_id) {
self::$services[$decorated_service_id]->addDecorator(self::$services[$dcorating_service_id]);
}
}
}

private function resolveParentDefinition(string $parentId, array $serviceDefinition, array $drupalServices): array
Expand Down
21 changes: 21 additions & 0 deletions tests/src/ServiceMapFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Drupal\Core\Logger\LoggerChannel;
use mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition;
use mglaman\PHPStanDrupal\Drupal\ServiceMap;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use PHPUnit\Framework\TestCase;

final class ServiceMapFactoryTest extends TestCase
Expand Down Expand Up @@ -93,6 +95,14 @@ public function testFactory(string $id, callable $validator): void
],
'Psr\Log\LoggerInterface $loggerWorkspaces' => [
'alias' => 'logger.channel.workspaces'
],
'service_map.base_to_be_decorated' => [
'class' => 'Drupal\service_map\Base',
'abstract' => true,
],
'service_map.deocrating_base' => [
'decorates' => 'service_map.base_to_be_decorated',
'class' => 'Drupal\service_map\SecondBase',
]
]);
$validator($service->getService($id));
Expand Down Expand Up @@ -212,6 +222,17 @@ function (DrupalServiceDefinition $service): void {
self::assertEquals(LoggerChannel::class, $service->getClass());
}
];
yield [
'service_map.base_to_be_decorated',
function (DrupalServiceDefinition $service): void {
$combined_class = [
new ObjectType('Drupal\service_map\Base'),
new ObjectType('Drupal\service_map\SecondBase')
];
$expected_class = new UnionType($combined_class);
self::assertEquals($expected_class, $service->getType());
}
];
}

}

0 comments on commit 8f57480

Please sign in to comment.