Skip to content

Commit c2b348c

Browse files
committed
More cleanup of tag creation
TagWithType need to be created via a factory now.
1 parent 02f9ed7 commit c2b348c

20 files changed

+263
-375
lines changed

docs/upgrade-to-v6.rst

Whitespace-only changes.

src/DocBlock/StandardTagFactory.php

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,34 @@
1717
use phpDocumentor\Reflection\DocBlock\Tags\Author;
1818
use phpDocumentor\Reflection\DocBlock\Tags\Covers;
1919
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
20+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory;
21+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory;
2022
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
23+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ImplementsFactory;
24+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory;
25+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory;
26+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory;
27+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory;
28+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory;
29+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory;
30+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateExtendsFactory;
31+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateFactory;
32+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateImplementsFactory;
33+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ThrowsFactory;
34+
use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory;
2135
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
2236
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
2337
use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag;
2438
use phpDocumentor\Reflection\DocBlock\Tags\Method;
25-
use phpDocumentor\Reflection\DocBlock\Tags\Mixin;
26-
use phpDocumentor\Reflection\DocBlock\Tags\Param;
27-
use phpDocumentor\Reflection\DocBlock\Tags\Property;
28-
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
29-
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
30-
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
3139
use phpDocumentor\Reflection\DocBlock\Tags\See as SeeTag;
3240
use phpDocumentor\Reflection\DocBlock\Tags\Since;
3341
use phpDocumentor\Reflection\DocBlock\Tags\Source;
3442
use phpDocumentor\Reflection\DocBlock\Tags\TemplateCovariant;
3543
use phpDocumentor\Reflection\DocBlock\Tags\Throws;
3644
use phpDocumentor\Reflection\DocBlock\Tags\Uses;
37-
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
3845
use phpDocumentor\Reflection\DocBlock\Tags\Version;
3946
use phpDocumentor\Reflection\FqsenResolver;
47+
use phpDocumentor\Reflection\TypeResolver;
4048
use phpDocumentor\Reflection\Types\Context as TypeContext;
4149
use ReflectionMethod;
4250
use ReflectionNamedType;
@@ -77,7 +85,7 @@ final class StandardTagFactory implements TagFactory
7785
public const REGEX_TAGNAME = '[\w\-\_\\\\:]+';
7886

7987
/**
80-
* @var array<class-string<Tag>|Factory> An array with a tag as a key, and an
88+
* @var array<string, class-string<Tag>|Tag|Factory> An array with a tag as a key, and an
8189
* FQCN to a class that handles it as an array value.
8290
*/
8391
private array $tagHandlerMappings = [
@@ -86,21 +94,13 @@ final class StandardTagFactory implements TagFactory
8694
'deprecated' => Deprecated::class,
8795
// 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example',
8896
'link' => LinkTag::class,
89-
'mixin' => Mixin::class,
9097
'method' => Method::class,
91-
'param' => Param::class,
92-
'property-read' => PropertyRead::class,
93-
'property' => Property::class,
94-
'property-write' => PropertyWrite::class,
95-
'return' => Return_::class,
9698
'see' => SeeTag::class,
9799
'since' => Since::class,
98100
'source' => Source::class,
99101
'template-covariant' => TemplateCovariant::class,
100102
'throw' => Throws::class,
101-
'throws' => Throws::class,
102103
'uses' => Uses::class,
103-
'var' => Var_::class,
104104
'version' => Version::class,
105105
];
106106

@@ -124,24 +124,58 @@ final class StandardTagFactory implements TagFactory
124124
*/
125125
private array $serviceLocator = [];
126126

127+
private function __construct(FqsenResolver $fqsenResolver)
128+
{
129+
$this->fqsenResolver = $fqsenResolver;
130+
131+
$this->addService($fqsenResolver, FqsenResolver::class);
132+
}
133+
127134
/**
128-
* Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers.
129-
*
130-
* If no tag handlers are provided than the default list in the {@see self::$tagHandlerMappings} property
131-
* is used.
135+
* Initialize this tag factory with the means to resolve an FQSEN.
132136
*
133137
* @see self::registerTagHandler() to add a new tag handler to the existing default list.
134-
*
135-
* @param array<class-string<Tag>> $tagHandlers
136138
*/
137-
public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null)
139+
public static function createInstance(FqsenResolver $fqsenResolver): self
138140
{
139-
$this->fqsenResolver = $fqsenResolver;
140-
if ($tagHandlers !== null) {
141-
$this->tagHandlerMappings = $tagHandlers;
142-
}
141+
$tagFactory = new self($fqsenResolver);
142+
$descriptionFactory = new DescriptionFactory($tagFactory);
143+
144+
$typeResolver = new TypeResolver($fqsenResolver);
145+
146+
$phpstanTagFactory = new AbstractPHPStanFactory(
147+
new ParamFactory($typeResolver, $descriptionFactory),
148+
new VarFactory($typeResolver, $descriptionFactory),
149+
new ReturnFactory($typeResolver, $descriptionFactory),
150+
new PropertyFactory($typeResolver, $descriptionFactory),
151+
new PropertyReadFactory($typeResolver, $descriptionFactory),
152+
new PropertyWriteFactory($typeResolver, $descriptionFactory),
153+
new MethodFactory($typeResolver, $descriptionFactory),
154+
new ImplementsFactory($typeResolver, $descriptionFactory),
155+
new ExtendsFactory($typeResolver, $descriptionFactory),
156+
new TemplateFactory($typeResolver, $descriptionFactory),
157+
new TemplateImplementsFactory($typeResolver, $descriptionFactory),
158+
new TemplateExtendsFactory($typeResolver, $descriptionFactory),
159+
new ThrowsFactory($typeResolver, $descriptionFactory),
160+
);
143161

144-
$this->addService($fqsenResolver, FqsenResolver::class);
162+
$tagFactory->addService($descriptionFactory);
163+
$tagFactory->addService($typeResolver);
164+
$tagFactory->registerTagHandler('param', $phpstanTagFactory);
165+
$tagFactory->registerTagHandler('var', $phpstanTagFactory);
166+
$tagFactory->registerTagHandler('return', $phpstanTagFactory);
167+
$tagFactory->registerTagHandler('property', $phpstanTagFactory);
168+
$tagFactory->registerTagHandler('property-read', $phpstanTagFactory);
169+
$tagFactory->registerTagHandler('property-write', $phpstanTagFactory);
170+
$tagFactory->registerTagHandler('method', $phpstanTagFactory);
171+
$tagFactory->registerTagHandler('extends', $phpstanTagFactory);
172+
$tagFactory->registerTagHandler('implements', $phpstanTagFactory);
173+
$tagFactory->registerTagHandler('template', $phpstanTagFactory);
174+
$tagFactory->registerTagHandler('template-extends', $phpstanTagFactory);
175+
$tagFactory->registerTagHandler('template-implements', $phpstanTagFactory);
176+
$tagFactory->registerTagHandler('throws', $phpstanTagFactory);
177+
178+
return $tagFactory;
145179
}
146180

147181
public function create(string $tagLine, ?TypeContext $context = null): Tag
@@ -238,7 +272,7 @@ private function createTag(string $body, string $name, TypeContext $context): Ta
238272
/**
239273
* Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`).
240274
*
241-
* @return class-string<Tag>|Factory
275+
* @return class-string<Tag>|Tag|Factory
242276
*/
243277
private function findHandlerClassName(string $tagName, TypeContext $context)
244278
{
@@ -302,7 +336,7 @@ private function getArgumentsForParametersFromWiring(array $parameters, array $l
302336
* Retrieves a series of ReflectionParameter objects for the static 'create' method of the given
303337
* tag handler class name.
304338
*
305-
* @param class-string|Factory $handler
339+
* @param class-string<Tag>|Tag|Factory $handler
306340
*
307341
* @return ReflectionParameter[]
308342
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
6+
7+
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
8+
use phpDocumentor\Reflection\DocBlock\Tag;
9+
use phpDocumentor\Reflection\DocBlock\Tags\Mixin;
10+
use phpDocumentor\Reflection\TypeResolver;
11+
use phpDocumentor\Reflection\Types\Context;
12+
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
13+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
14+
use Webmozart\Assert\Assert;
15+
16+
use function is_string;
17+
18+
/**
19+
* @internal This class is not part of the BC promise of this library.
20+
*/
21+
final class MixinFactory implements PHPStanFactory
22+
{
23+
private DescriptionFactory $descriptionFactory;
24+
private TypeResolver $typeResolver;
25+
26+
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
27+
{
28+
$this->descriptionFactory = $descriptionFactory;
29+
$this->typeResolver = $typeResolver;
30+
}
31+
32+
public function create(PhpDocTagNode $node, Context $context): Tag
33+
{
34+
$tagValue = $node->value;
35+
Assert::isInstanceOf($tagValue, MixinTagValueNode::class);
36+
37+
$description = $tagValue->getAttribute('description');
38+
if (is_string($description) === false) {
39+
$description = $tagValue->description;
40+
}
41+
42+
return new Mixin(
43+
$this->typeResolver->createType($tagValue->type, $context),
44+
$this->descriptionFactory->create($description, $context)
45+
);
46+
}
47+
48+
public function supports(PhpDocTagNode $node, Context $context): bool
49+
{
50+
return $node->value instanceof MixinTagValueNode;
51+
}
52+
}

src/DocBlock/Tags/Factory/ParamFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use phpDocumentor\Reflection\DocBlock\Tag;
99
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
1010
use phpDocumentor\Reflection\DocBlock\Tags\Param;
11+
use phpDocumentor\Reflection\Exception\ParserException;
1112
use phpDocumentor\Reflection\TypeResolver;
1213
use phpDocumentor\Reflection\Types\Context;
1314
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
@@ -40,7 +41,7 @@ public function create(PhpDocTagNode $node, Context $context): Tag
4041
$tagValue = $node->value;
4142

4243
if ($tagValue instanceof InvalidTagValueNode) {
43-
return InvalidTag::create($tagValue->value, 'param')->withError($tagValue->exception);
44+
return InvalidTag::create($tagValue->value, 'param')->withError(ParserException::from($tagValue->exception));
4445
}
4546

4647
Assert::isInstanceOfAny(
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
6+
7+
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
8+
use phpDocumentor\Reflection\DocBlock\Tag;
9+
use phpDocumentor\Reflection\DocBlock\Tags\Throws;
10+
use phpDocumentor\Reflection\TypeResolver;
11+
use phpDocumentor\Reflection\Types\Context;
12+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
13+
use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
14+
use Webmozart\Assert\Assert;
15+
16+
use function is_string;
17+
18+
/**
19+
* @internal This class is not part of the BC promise of this library.
20+
*/
21+
final class ThrowsFactory implements PHPStanFactory
22+
{
23+
private DescriptionFactory $descriptionFactory;
24+
private TypeResolver $typeResolver;
25+
26+
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
27+
{
28+
$this->descriptionFactory = $descriptionFactory;
29+
$this->typeResolver = $typeResolver;
30+
}
31+
32+
public function create(PhpDocTagNode $node, Context $context): Tag
33+
{
34+
$tagValue = $node->value;
35+
Assert::isInstanceOf($tagValue, ThrowsTagValueNode::class);
36+
37+
$description = $tagValue->getAttribute('description');
38+
if (is_string($description) === false) {
39+
$description = $tagValue->description;
40+
}
41+
42+
return new Throws(
43+
$this->typeResolver->createType($tagValue->type, $context),
44+
$this->descriptionFactory->create($description, $context)
45+
);
46+
}
47+
48+
public function supports(PhpDocTagNode $node, Context $context): bool
49+
{
50+
return $node->value instanceof ThrowsTagValueNode;
51+
}
52+
}

src/DocBlock/Tags/Mixin.php

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
namespace phpDocumentor\Reflection\DocBlock\Tags;
1515

1616
use phpDocumentor\Reflection\DocBlock\Description;
17-
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
1817
use phpDocumentor\Reflection\Type;
19-
use phpDocumentor\Reflection\TypeResolver;
20-
use phpDocumentor\Reflection\Types\Context as TypeContext;
21-
use Webmozart\Assert\Assert;
2218

2319
/**
2420
* Reflection class for a {@}mixin tag in a Docblock.
@@ -31,21 +27,4 @@ public function __construct(Type $type, ?Description $description = null)
3127
$this->type = $type;
3228
$this->description = $description;
3329
}
34-
35-
public static function create(
36-
string $body,
37-
?TypeResolver $typeResolver = null,
38-
?DescriptionFactory $descriptionFactory = null,
39-
?TypeContext $context = null
40-
): self {
41-
Assert::notNull($typeResolver);
42-
Assert::notNull($descriptionFactory);
43-
44-
[$type, $description] = self::extractTypeFromBody($body);
45-
46-
$type = $typeResolver->resolve($type, $context);
47-
$description = $descriptionFactory->create($description, $context);
48-
49-
return new static($type, $description);
50-
}
5130
}

src/DocBlock/Tags/Param.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
use phpDocumentor\Reflection\DocBlock\Description;
1717
use phpDocumentor\Reflection\Type;
1818

19-
use function strpos;
20-
2119
/**
2220
* Reflection class for the {@}param tag in a Docblock.
2321
*/

src/DocBlock/Tags/TagWithType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function getType(): ?Type
3737
return $this->type;
3838
}
3939

40-
public static function create(string $body): Tag
40+
final public static function create(string $body): Tag
4141
{
4242
throw new CannotCreateTag('Typed tag cannot be created');
4343
}

src/DocBlock/Tags/TemplateCovariant.php

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
namespace phpDocumentor\Reflection\DocBlock\Tags;
1515

1616
use phpDocumentor\Reflection\DocBlock\Description;
17-
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
1817
use phpDocumentor\Reflection\Type;
19-
use phpDocumentor\Reflection\TypeResolver;
20-
use phpDocumentor\Reflection\Types\Context as TypeContext;
21-
use Webmozart\Assert\Assert;
2218

2319
/**
2420
* Reflection class for a {@}template-covariant tag in a Docblock.
@@ -31,21 +27,4 @@ public function __construct(Type $type, ?Description $description = null)
3127
$this->type = $type;
3228
$this->description = $description;
3329
}
34-
35-
public static function create(
36-
string $body,
37-
?TypeResolver $typeResolver = null,
38-
?DescriptionFactory $descriptionFactory = null,
39-
?TypeContext $context = null
40-
): self {
41-
Assert::notNull($typeResolver);
42-
Assert::notNull($descriptionFactory);
43-
44-
[$type, $description] = self::extractTypeFromBody($body);
45-
46-
$type = $typeResolver->resolve($type, $context);
47-
$description = $descriptionFactory->create($description, $context);
48-
49-
return new static($type, $description);
50-
}
5130
}

0 commit comments

Comments
 (0)