Skip to content

Commit 0bbca8f

Browse files
authored
Fixed generating PHPDoc for methods with class templates (#1647)
* Fixed generating PHPDoc for methods with class templates * Fix style * Use getter for alias template names * Fixed missing class in static analysis
1 parent f838156 commit 0bbca8f

File tree

4 files changed

+88
-15
lines changed

4 files changed

+88
-15
lines changed

src/Alias.php

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Barryvdh\Reflection\DocBlock\ContextFactory;
1717
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
1818
use Barryvdh\Reflection\DocBlock\Tag\MethodTag;
19+
use Barryvdh\Reflection\DocBlock\Tag\TemplateTag;
1920
use Closure;
2021
use Illuminate\Config\Repository as ConfigRepository;
2122
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
@@ -48,6 +49,9 @@ class Alias
4849
/** @var ConfigRepository */
4950
protected $config;
5051

52+
/** @var string[] */
53+
protected $templateNames;
54+
5155
/**
5256
* @param ConfigRepository $config
5357
* @param string $alias
@@ -347,7 +351,8 @@ protected function addMagicMethods()
347351
$magic,
348352
$this->interfaces,
349353
$this->classAliases,
350-
$this->getReturnTypeNormalizers($class)
354+
$this->getReturnTypeNormalizers($class),
355+
$this->getTemplateNames()
351356
);
352357
}
353358
$this->usedMethods[] = $magic;
@@ -379,7 +384,8 @@ protected function detectMethods()
379384
$method->name,
380385
$this->interfaces,
381386
$this->classAliases,
382-
$this->getReturnTypeNormalizers($reflection)
387+
$this->getReturnTypeNormalizers($reflection),
388+
$this->getTemplateNames(),
383389
);
384390
}
385391
$this->usedMethods[] = $method->name;
@@ -477,39 +483,62 @@ public function getDocComment($prefix = "\t\t")
477483
/**
478484
* @param $prefix
479485
* @return string
480-
* @throws \ReflectionException
481486
*/
482487
public function getPhpDocTemplates($prefix = "\t\t")
483488
{
484489
$templateDoc = new DocBlock('');
485490
$serializer = new DocBlockSerializer(1, $prefix);
486491

492+
foreach ($this->getTemplateNames() as $templateName) {
493+
$template = new TemplateTag('template', $templateName);
494+
$template->setBound('static');
495+
$template->setDocBlock($templateDoc);
496+
$templateDoc->appendTag($template);
497+
}
498+
499+
return $serializer->getDocComment($templateDoc);
500+
}
501+
502+
/**
503+
* @return string[]
504+
*/
505+
public function getTemplateNames()
506+
{
507+
if (!isset($this->templateNames)) {
508+
$this->detectTemplateNames();
509+
}
510+
return $this->templateNames;
511+
}
512+
513+
/**
514+
* @return void
515+
* @throws \ReflectionException
516+
*/
517+
protected function detectTemplateNames()
518+
{
519+
$templateNames = [];
487520
foreach ($this->classes as $class) {
488521
$reflection = new ReflectionClass($class);
489522
$traits = collect($reflection->getTraitNames());
490523

491524
$phpdoc = new DocBlock($reflection);
492525
$templates = $phpdoc->getTagsByName('template');
493-
/** @var DocBlock\Tag\TemplateTag $template */
526+
/** @var TemplateTag $template */
494527
foreach ($templates as $template) {
495-
$template->setBound('static');
496-
$template->setDocBlock($templateDoc);
497-
$templateDoc->appendTag($template);
528+
$templateNames[] = $template->getTemplateName();
498529
}
499530

500531
foreach ($traits as $trait) {
501532
$phpdoc = new DocBlock(new ReflectionClass($trait));
502533
$templates = $phpdoc->getTagsByName('template');
503534

504-
/** @var DocBlock\Tag\TemplateTag $template */
535+
/** @var TemplateTag $template */
505536
foreach ($templates as $template) {
506-
$template->setBound('static');
507-
$template->setDocBlock($templateDoc);
508-
$templateDoc->appendTag($template);
537+
$templateNames[] = $template->getTemplateName();
509538
}
510539
}
511540
}
512-
return $serializer->getDocComment($templateDoc);
541+
$this->templateNames = $templateNames;
513542
}
514543

515544
/**

src/Method.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class Method
3939
protected $classAliases;
4040
protected $returnTypeNormalizers;
4141

42+
/** @var string[] */
43+
protected $templateNames = [];
44+
4245
/**
4346
* @param \ReflectionMethod|\ReflectionFunctionAbstract $method
4447
* @param string $alias
@@ -47,15 +50,17 @@ class Method
4750
* @param array $interfaces
4851
* @param array $classAliases
4952
* @param array $returnTypeNormalizers
53+
* @param string[] $templateNames
5054
*/
51-
public function __construct($method, $alias, $class, $methodName = null, $interfaces = [], array $classAliases = [], array $returnTypeNormalizers = [])
55+
public function __construct($method, $alias, $class, $methodName = null, $interfaces = [], array $classAliases = [], array $returnTypeNormalizers = [], array $templateNames = [])
5256
{
5357
$this->method = $method;
5458
$this->interfaces = $interfaces;
5559
$this->classAliases = $classAliases;
5660
$this->returnTypeNormalizers = $returnTypeNormalizers;
5761
$this->name = $methodName ?: $method->name;
5862
$this->real_name = $method->isClosure() ? $this->name : $method->name;
63+
$this->templateNames = $templateNames;
5964
$this->initClassDefinedProperties($method, $class);
6065

6166
//Reference the 'real' function in the declaring class
@@ -84,7 +89,7 @@ public function __construct($method, $alias, $class, $methodName = null, $interf
8489
*/
8590
protected function initPhpDoc($method)
8691
{
87-
$this->phpdoc = new DocBlock($method, new Context($this->namespace, $this->classAliases));
92+
$this->phpdoc = new DocBlock($method, new Context($this->namespace, $this->classAliases, generics: $this->templateNames));
8893
}
8994

9095
/**
@@ -386,7 +391,7 @@ protected function getInheritDoc($reflectionMethod)
386391
}
387392
if ($method) {
388393
$namespace = $method->getDeclaringClass()->getNamespaceName();
389-
$phpdoc = new DocBlock($method, new Context($namespace, $this->classAliases));
394+
$phpdoc = new DocBlock($method, new Context($namespace, $this->classAliases, generics: $this->templateNames));
390395

391396
if (strpos($phpdoc->getText(), '{@inheritdoc}') !== false) {
392397
//Not at the end yet, try another parent/interface..

tests/AliasTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ function () {
6666
$this->assertNotNull($this->getAliasMacro($alias, EloquentBuilder::class, $macro));
6767
}
6868

69+
/**
70+
* @covers ::detectTemplateNames
71+
*/
72+
public function testTemplateNamesAreDetected(): void
73+
{
74+
// Mock
75+
$alias = new AliasMock();
76+
77+
// Prepare
78+
$alias->setClasses([EloquentBuilder::class]);
79+
80+
// Test
81+
$this->assertSame(['TModel', 'TValue'], $alias->getTemplateNames());
82+
}
83+
6984
protected function getAliasMacro(Alias $alias, string $class, string $method): ?Macro
7085
{
7186
return Arr::first(
@@ -82,6 +97,7 @@ function ($macro) use ($class, $method) {
8297
/**
8398
* @internal
8499
* @noinspection PhpMultipleClassesDeclarationsInOneFile
100+
* @template TValue
85101
*/
86102
class AliasMock extends Alias
87103
{

tests/MethodTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,29 @@ public function testClassAliases()
193193
$this->assertSame([], $method->getParamsWithDefault(false));
194194
$this->assertTrue($method->shouldReturn());
195195
}
196+
197+
public function testEloquentBuilderWithTemplates()
198+
{
199+
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
200+
$reflectionMethod = $reflectionClass->getMethod('firstOr');
201+
202+
$method = new Method($reflectionMethod, 'Builder', $reflectionClass, null, [], [], [], ['TModel']);
203+
204+
$output = <<<'DOC'
205+
/**
206+
* Execute the query and get the first result or call a callback.
207+
*
208+
* @template TValue
209+
* @param (\Closure(): TValue)|list<string> $columns
210+
* @param (\Closure(): TValue)|null $callback
211+
* @return TModel|TValue
212+
* @static
213+
*/
214+
DOC;
215+
$this->assertSame($output, $method->getDocComment(''));
216+
$this->assertSame('firstOr', $method->getName());
217+
$this->assertSame('\\' . EloquentBuilder::class, $method->getDeclaringClass());
218+
}
196219
}
197220

198221
class ExampleClass

0 commit comments

Comments
 (0)