Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions src/Type/ContainerDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Comment on lines +81 to +88
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's anyway to leverage PHPStan type system, which may abstract away some of this logic. But it may not be as accessible in these extensions

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly, that you would like to ask phpstan if the argument is of type 'string' or 'class-string' instead of this?

Do you have any idea where to start looking to come up with a solution that does that (because I am not really experienced in phpstan source)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I saw #397 which if I am not wrong, will make this plugin obsolete?

If so, in my opinion, this PR would make for good initial support of the feature. Any further (cleaner) solutions, for example in #397, using the type system would then also be checked against the tests for this feature.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can ignore that other PR, it's experimental. Let's work on this first


return null;
}
}
24 changes: 19 additions & 5 deletions src/Type/DrupalServiceDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
1 change: 1 addition & 0 deletions tests/src/Type/data/container.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
5 changes: 5 additions & 0 deletions tests/src/Type/data/drupal-class-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
1 change: 1 addition & 0 deletions tests/src/Type/data/drupal-service-static.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@

function test(): void {
assertType(MyService::class, \Drupal::service('service_map.my_service'));
assertType(MyService::class, \Drupal::service(MyService::class));
}