Skip to content

Commit 8455445

Browse files
Resolve services defined by string & BaseObject configurations (proget-hq#38)
1 parent 68b7603 commit 8455445

File tree

5 files changed

+77
-9
lines changed

5 files changed

+77
-9
lines changed

src/ServiceMap.php

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Proget\PHPStan\Yii2;
66

77
use PhpParser\Node;
8+
use yii\base\BaseObject;
89

910
final class ServiceMap
1011
{
@@ -33,18 +34,19 @@ public function __construct(string $configPath)
3334
foreach ($config['container']['singletons'] ?? [] as $id => $service) {
3435
$this->addServiceDefinition($id, $service);
3536
}
37+
3638
foreach ($config['container']['definitions'] ?? [] as $id => $service) {
3739
$this->addServiceDefinition($id, $service);
3840
}
3941

4042
foreach ($config['components'] ?? [] as $id => $component) {
41-
if (is_object($component)) {
43+
if (\is_object($component)) {
4244
$this->components[$id] = \get_class($component);
4345
continue;
4446
}
4547

46-
if (!is_array($component)) {
47-
throw new \RuntimeException(sprintf('Invalid value for component with id %s. Expected object or array.', $id));
48+
if (!\is_array($component)) {
49+
throw new \RuntimeException(\sprintf('Invalid value for component with id %s. Expected object or array.', $id));
4850
}
4951

5052
if (null !== $class = $component['class'] ?? null) {
@@ -70,19 +72,49 @@ public function getComponentClassById(string $id): ?string
7072
/**
7173
* @param string|\Closure|array<mixed> $service
7274
*
73-
* @throws \ReflectionException
75+
* @throws \RuntimeException|\ReflectionException
7476
*/
7577
private function addServiceDefinition(string $id, $service): void
7678
{
79+
$this->services[$id] = $this->guessServiceDefinition($id, $service);
80+
}
81+
82+
/**
83+
* @param string|\Closure|array<mixed> $service
84+
*
85+
* @throws \RuntimeException|\ReflectionException
86+
*/
87+
private function guessServiceDefinition(string $id, $service): string
88+
{
89+
if (\is_string($service) && \class_exists($service)) {
90+
return $service;
91+
}
92+
7793
if ($service instanceof \Closure || \is_string($service)) {
7894
$returnType = (new \ReflectionFunction($service))->getReturnType();
7995
if (!$returnType instanceof \ReflectionNamedType) {
80-
throw new \RuntimeException(sprintf('Please provide return type for %s service closure', $id));
96+
throw new \RuntimeException(\sprintf('Please provide return type for %s service closure', $id));
8197
}
8298

83-
$this->services[$id] = $returnType->getName();
84-
} else {
85-
$this->services[$id] = $service['class'] ?? $service[0]['class'];
99+
return $returnType->getName();
86100
}
101+
102+
if (!\is_array($service)) {
103+
throw new \RuntimeException(\sprintf('Unsupported service definition for %s', $id));
104+
}
105+
106+
if (isset($service['class'])) {
107+
return $service['class'];
108+
}
109+
110+
if (isset($service[0]['class'])) {
111+
return $service[0]['class'];
112+
}
113+
114+
if (\is_subclass_of($id, BaseObject::class)) {
115+
return $id;
116+
}
117+
118+
throw new \RuntimeException(\sprintf('Cannot guess service definition for %s', $id));
87119
}
88120
}

tests/ServiceMapTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ public function testThrowExceptionWhenClosureServiceHasMissingReturnType(): void
2727
new ServiceMap(__DIR__.DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'yii-config-invalid.php');
2828
}
2929

30+
public function testThrowExceptionWhenServiceHasUnsupportedType(): void
31+
{
32+
$this->expectException(\RuntimeException::class);
33+
$this->expectExceptionMessage('Unsupported service definition for unsupported-type');
34+
35+
new ServiceMap(__DIR__.DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'yii-config-invalid-unsupported-type.php');
36+
}
37+
38+
public function testThrowExceptionWhenServiceHasUnsupportedArray(): void
39+
{
40+
$this->expectException(\RuntimeException::class);
41+
$this->expectExceptionMessage('Cannot guess service definition for unsupported-array');
42+
43+
new ServiceMap(__DIR__.DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'yii-config-invalid-unsupported-array.php');
44+
}
45+
3046
public function testThrowExceptionWhenComponentHasInvalidValue(): void
3147
{
3248
$this->expectException(\RuntimeException::class);
@@ -39,6 +55,8 @@ public function testItLoadsServicesAndComponents(): void
3955
{
4056
$serviceMap = new ServiceMap(__DIR__.DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'yii-config-valid.php');
4157

58+
self::assertSame(MyActiveRecord::class, $serviceMap->getServiceClassFromNode(new String_('singleton-string')));
59+
self::assertSame(MyActiveRecord::class, $serviceMap->getServiceClassFromNode(new String_(MyActiveRecord::class)));
4260
self::assertSame(\SplStack::class, $serviceMap->getServiceClassFromNode(new String_('singleton-closure')));
4361
self::assertSame(\SplObjectStorage::class, $serviceMap->getServiceClassFromNode(new String_('singleton-service')));
4462
self::assertSame(\SplFileInfo::class, $serviceMap->getServiceClassFromNode(new String_('singleton-nested-service-class')));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
return [
4+
'container' => ['singletons' => [
5+
'unsupported-array' => [],
6+
]]
7+
];
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
return [
4+
'container' => ['singletons' => [
5+
'unsupported-type' => 1,
6+
]]
7+
];

tests/assets/yii-config-valid.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
],
1212
'container' => [
1313
'singletons' => [
14+
'singleton-string' => MyActiveRecord::class,
1415
'singleton-closure' => function(): \SplStack {
1516
return new \SplStack();
1617
},
@@ -26,7 +27,10 @@
2627
'service' => ['class' => \SplObjectStorage::class],
2728
'nested-service-class' => [
2829
['class' => \SplFileInfo::class]
29-
]
30+
],
31+
MyActiveRecord::class => [
32+
'flag' => 'foo',
33+
],
3034
]
3135
]
3236
];

0 commit comments

Comments
 (0)