Skip to content

Commit 27888ea

Browse files
authored
Merge pull request #255 from brambaud/feat/url-to-string
Support dynamic return type of Drupal\Core\Url::toString
2 parents 337bc36 + 0f82f46 commit 27888ea

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

extension.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ services:
6767
-
6868
class: mglaman\PHPStanDrupal\Type\EntityQuery\EntityQueryDynamicReturnTypeExtension
6969
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
70+
-
71+
class: mglaman\PHPStanDrupal\Type\UrlToStringDynamicReturnTypeExtension
72+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
7073
-
7174
class: mglaman\PHPStanDrupal\Type\DrupalClassResolverDynamicStaticReturnTypeExtension
7275
tags: [phpstan.broker.dynamicStaticMethodReturnTypeExtension]
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Type;
4+
5+
use Drupal\Core\GeneratedUrl;
6+
use Drupal\Core\Url;
7+
use PhpParser\Node\Expr\MethodCall;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Reflection\MethodReflection;
10+
use PHPStan\Reflection\ParametersAcceptorSelector;
11+
use PHPStan\Type\Constant\ConstantBooleanType;
12+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
13+
use PHPStan\Type\ObjectType;
14+
use PHPStan\Type\StringType;
15+
use PHPStan\Type\Type;
16+
17+
final class UrlToStringDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
18+
{
19+
20+
public function getClass(): string
21+
{
22+
return Url::class;
23+
}
24+
25+
public function isMethodSupported(MethodReflection $methodReflection): bool
26+
{
27+
return $methodReflection->getName() === 'toString';
28+
}
29+
30+
public function getTypeFromMethodCall(
31+
MethodReflection $methodReflection,
32+
MethodCall $methodCall,
33+
Scope $scope
34+
): Type {
35+
if (0 === \count($methodCall->getArgs())) {
36+
return new StringType();
37+
}
38+
39+
$arg1 = $scope->getType($methodCall->getArgs()[0]->value);
40+
if (!$arg1 instanceof ConstantBooleanType) {
41+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
42+
}
43+
44+
if (true === $arg1->getValue()) {
45+
return new ObjectType(GeneratedUrl::class);
46+
}
47+
48+
return new StringType();
49+
}
50+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Tests\Type;
4+
5+
use mglaman\PHPStanDrupal\Tests\AdditionalConfigFilesTrait;
6+
use PHPStan\Testing\TypeInferenceTestCase;
7+
8+
final class UrlDynamicReturnTypeTest extends TypeInferenceTestCase
9+
{
10+
use AdditionalConfigFilesTrait;
11+
12+
public function dataFileAsserts(): iterable
13+
{
14+
yield from $this->gatherAssertTypes(__DIR__ . '/data/url.php');
15+
}
16+
17+
/**
18+
* @dataProvider dataFileAsserts
19+
* @param string $assertType
20+
* @param string $file
21+
* @param mixed ...$args
22+
*/
23+
public function testFileAsserts(
24+
string $assertType,
25+
string $file,
26+
...$args
27+
): void
28+
{
29+
$this->assertFileAsserts($assertType, $file, ...$args);
30+
}
31+
}

tests/src/Type/data/url.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace DrupalUrl;
4+
5+
use Drupal\Core\Url;
6+
use Symfony\Component\HttpFoundation\Request;
7+
use function PHPStan\Testing\assertType;
8+
9+
assertType('string', (new Url('route_name'))->toString());
10+
assertType('string', Url::fromRoute('route_name')->toString());
11+
assertType('string', Url::fromRouteMatch(\Drupal::routeMatch())->toString());
12+
assertType('string', Url::fromUri('the_uri')->toString());
13+
assertType('string', Url::fromUserInput('user_input')->toString());
14+
assertType('string', Url::createFromRequest(new Request())->toString());
15+
assertType('string', (new Url('route_name'))->toString(FALSE));
16+
assertType('string', Url::fromRoute('route_name')->toString(FALSE));
17+
assertType('string', Url::fromRouteMatch(\Drupal::routeMatch())->toString(FALSE));
18+
assertType('string', Url::fromUri('the_uri')->toString(FALSE));
19+
assertType('string', Url::fromUserInput('user_input')->toString(FALSE));
20+
assertType('string', Url::createFromRequest(new Request())->toString(FALSE));
21+
assertType('Drupal\Core\GeneratedUrl', (new Url('route_name'))->toString(TRUE));
22+
assertType('Drupal\Core\GeneratedUrl', Url::fromRoute('route_name')->toString(TRUE));
23+
assertType('Drupal\Core\GeneratedUrl', Url::fromRouteMatch(\Drupal::routeMatch())->toString(TRUE));
24+
assertType('Drupal\Core\GeneratedUrl', Url::fromUri('the_uri')->toString(TRUE));
25+
assertType('Drupal\Core\GeneratedUrl', Url::fromUserInput('user_input')->toString(TRUE));
26+
assertType('Drupal\Core\GeneratedUrl', Url::createFromRequest(new Request())->toString(TRUE));

0 commit comments

Comments
 (0)