From 55628e3c87aec138f1434e0d09ffb7545c19ec8f Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 14 Jun 2022 19:32:44 +0200 Subject: [PATCH 1/2] add support for class string service ids --- ...rupalServiceDynamicReturnTypeExtension.php | 24 +++++++++++++++---- .../service_map/service_map.services.yml | 2 ++ tests/src/Type/data/drupal-service-static.php | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Type/DrupalServiceDynamicReturnTypeExtension.php b/src/Type/DrupalServiceDynamicReturnTypeExtension.php index ddfe8383..920f3638 100644 --- a/src/Type/DrupalServiceDynamicReturnTypeExtension.php +++ b/src/Type/DrupalServiceDynamicReturnTypeExtension.php @@ -5,7 +5,9 @@ use Drupal; use mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition; use mglaman\PHPStanDrupal\Drupal\ServiceMap; +use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Scalar\String_; use PhpParser\Node\VariadicPlaceholder; use PHPStan\Analyser\Scope; @@ -51,17 +53,29 @@ public function getTypeFromStaticMethodCall( if ($arg1 instanceof VariadicPlaceholder) { throw new ShouldNotHappenException(); } + $arg1 = $arg1->value; - if (!$arg1 instanceof String_) { - // @todo determine what these types are. - return $returnType; + + if ($arg1 instanceof String_) { + $serviceId = $arg1->value; + return $this->getServiceType($serviceId) ?? $returnType; } - $serviceId = $arg1->value; + if ($arg1 instanceof ClassConstFetch && $arg1->class instanceof FullyQualified) { + $serviceId = (string) $arg1->class; + return $this->getServiceType($serviceId) ?? $returnType; + } + + return $returnType; + } + + protected function getServiceType(string $serviceId): ?Type + { $service = $this->serviceMap->getService($serviceId); if ($service instanceof DrupalServiceDefinition) { return $service->getType(); } - return $returnType; + + return null; } } diff --git a/tests/fixtures/drupal/modules/service_map/service_map.services.yml b/tests/fixtures/drupal/modules/service_map/service_map.services.yml index c55dd459..71921a77 100644 --- a/tests/fixtures/drupal/modules/service_map/service_map.services.yml +++ b/tests/fixtures/drupal/modules/service_map/service_map.services.yml @@ -1,6 +1,8 @@ services: service_map.my_service: class: Drupal\service_map\MyService + Drupal\service_map\MyService: + class: Drupal\service_map\MyService GuzzleHttp\Client: '@http_client' Drupal\Core\Config\ConfigFactoryInterface: '@config.factory' Drupal\Core\Messenger\MessengerInterface: '@messenger' diff --git a/tests/src/Type/data/drupal-service-static.php b/tests/src/Type/data/drupal-service-static.php index 600512aa..2e60543d 100644 --- a/tests/src/Type/data/drupal-service-static.php +++ b/tests/src/Type/data/drupal-service-static.php @@ -7,4 +7,5 @@ function test(): void { assertType(MyService::class, \Drupal::service('service_map.my_service')); + assertType(MyService::class, \Drupal::service(MyService::class)); } From 2385494dafc8f9e52cdfb04bd2a7ff5e104660df Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 14 Jun 2022 21:11:54 +0200 Subject: [PATCH 2/2] extend class-string service id support --- .../ContainerDynamicReturnTypeExtension.php | 24 +++++++++++++++---- tests/src/Type/data/container.php | 1 + tests/src/Type/data/drupal-class-resolver.php | 5 ++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Type/ContainerDynamicReturnTypeExtension.php b/src/Type/ContainerDynamicReturnTypeExtension.php index 72839b4d..e559a469 100644 --- a/src/Type/ContainerDynamicReturnTypeExtension.php +++ b/src/Type/ContainerDynamicReturnTypeExtension.php @@ -4,7 +4,10 @@ use mglaman\PHPStanDrupal\Drupal\DrupalServiceDefinition; use mglaman\PHPStanDrupal\Drupal\ServiceMap; +use PhpParser\Node; +use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Scalar\String_; use PhpParser\Node\VariadicPlaceholder; use PHPStan\Analyser\Scope; @@ -52,13 +55,12 @@ public function getTypeFromMethodCall( throw new ShouldNotHappenException(); } $arg1 = $arg1->value; - if (!$arg1 instanceof String_) { - // @todo determine what these types are. + + $serviceId = $this->getServiceId($arg1); + if ($serviceId === null) { return $returnType; } - $serviceId = $arg1->value; - if ($methodReflection->getName() === 'get') { $service = $this->serviceMap->getService($serviceId); if ($service instanceof DrupalServiceDefinition) { @@ -73,4 +75,18 @@ public function getTypeFromMethodCall( throw new ShouldNotHappenException(); } + + protected function getServiceId(Node $arg1): ?string + { + if ($arg1 instanceof String_) { + // @todo determine what these types are. + return $arg1->value; + } + + if ($arg1 instanceof ClassConstFetch && $arg1->class instanceof FullyQualified) { + return (string) $arg1->class; + } + + return null; + } } diff --git a/tests/src/Type/data/container.php b/tests/src/Type/data/container.php index cddf5fbb..9b4e052d 100644 --- a/tests/src/Type/data/container.php +++ b/tests/src/Type/data/container.php @@ -18,4 +18,5 @@ function test(): void { assertType(MyService::class, $container->get('service_map.concrete_service_with_a_parent_which_has_a_parent')); assertType(Override::class, $container->get('service_map.concrete_service_overriding_definition_of_its_parent')); assertType(Concrete::class, $container->get('service_map.concrete_overriding_its_parent_which_has_a_parent')); + assertType(MyService::class, $container->get(MyService::class)); } diff --git a/tests/src/Type/data/drupal-class-resolver.php b/tests/src/Type/data/drupal-class-resolver.php index 32ec54d0..a85ba2f2 100644 --- a/tests/src/Type/data/drupal-class-resolver.php +++ b/tests/src/Type/data/drupal-class-resolver.php @@ -17,4 +17,9 @@ function test(): void { assertType(MyService::class, \Drupal::service('class_resolver')->getInstanceFromDefinition('service_map.my_service')); assertType(MyService::class, \Drupal::classResolver()->getInstanceFromDefinition('service_map.my_service')); assertType(MyService::class, \Drupal::classResolver('service_map.my_service')); + + assertType(MyService::class, (new ClassResolver())->getInstanceFromDefinition(MyService::class)); + assertType(MyService::class, \Drupal::service('class_resolver')->getInstanceFromDefinition(MyService::class)); + assertType(MyService::class, \Drupal::classResolver()->getInstanceFromDefinition(MyService::class)); + assertType(MyService::class, \Drupal::classResolver(MyService::class)); }