Skip to content

Commit 9098cee

Browse files
mgiraudMarc
andauthored
Remove doctrine annotations (#186)
* Replace doctrine/annotations with phpstan/phpdoc-parser * Remove custom boostrap.php * Remove annotations * Use PhpDocParser from phpstan instead of DocParser from doctrine/annotations * php-cs-fixer pass * Revert "Remove annotations" This reverts commit b09fb37. * Soft deprecate annotations --------- Co-authored-by: Marc <marc@mac.home>
1 parent b8d3314 commit 9098cee

10 files changed

Lines changed: 71 additions & 93 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"nikic/php-parser": "^5.0",
1414
"symfony/finder": "^5.4 || ^6.4 || ^7.0",
1515
"twig/twig": "^2.0 || ^3.0",
16-
"doctrine/annotations": "^1.7 || ^2.0"
16+
"phpstan/phpdoc-parser": "^2.3"
1717
},
1818
"require-dev": {
1919
"symfony/phpunit-bridge": "^5.4 || ^6.4 || ^7.0",

phpunit.xml.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
convertWarningsToExceptions="true"
99
processIsolation="false"
1010
stopOnFailure="false"
11-
bootstrap="./tests/bootstrap.php"
11+
bootstrap="./vendor/autoload.php"
1212
>
1313

1414
<php>

src/Annotation/Desc.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Translation\Extractor\Annotation;
1313

1414
/**
15+
* @deprecated since 2.3, this class is not used anymore. @Desc is now considered as a PHPDoc tag.
16+
*
1517
* @Annotation
1618
*/
1719
final class Desc

src/Annotation/Ignore.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Translation\Extractor\Annotation;
1313

1414
/**
15+
* @deprecated since 2.3, this class is not used anymore. @Ignore is now considered as a PHPDoc tag.
16+
*
1517
* @Annotation
1618
*/
1719
final class Ignore

src/Annotation/Translate.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Translation\Extractor\Annotation;
1313

1414
/**
15+
* @deprecated since 2.3, this class is not used anymore. @Translate is now considered as a PHPDoc tag.
16+
*
1517
* @Annotation
1618
*/
1719
class Translate

src/Visitor/BaseVisitor.php

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111

1212
namespace Translation\Extractor\Visitor;
1313

14-
use Doctrine\Common\Annotations\DocParser;
1514
use PhpParser\Node;
15+
use PHPStan\PhpDocParser\Ast\ConstExpr\DoctrineConstExprStringNode;
16+
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
17+
use PHPStan\PhpDocParser\Lexer\Lexer;
18+
use PHPStan\PhpDocParser\Parser\ConstExprParser;
19+
use PHPStan\PhpDocParser\Parser\PhpDocParser;
20+
use PHPStan\PhpDocParser\Parser\TokenIterator;
21+
use PHPStan\PhpDocParser\Parser\TypeParser;
22+
use PHPStan\PhpDocParser\ParserConfig;
1623
use Symfony\Component\Finder\SplFileInfo;
17-
use Translation\Extractor\Annotation\Desc;
18-
use Translation\Extractor\Annotation\Ignore;
1924
use Translation\Extractor\Model\Error;
2025
use Translation\Extractor\Model\SourceCollection;
2126
use Translation\Extractor\Model\SourceLocation;
@@ -27,7 +32,8 @@
2732
*/
2833
abstract class BaseVisitor implements Visitor
2934
{
30-
private ?DocParser $docParser = null;
35+
protected ?Lexer $lexer = null;
36+
protected ?PhpDocParser $phpDocParser = null;
3137

3238
protected ?SourceCollection $collection = null;
3339
protected SplFileInfo $file;
@@ -54,9 +60,11 @@ protected function addError(Node $node, string $errorMessage): void
5460
$line = $node->getAttribute('startLine');
5561
}
5662
if (null !== $docComment) {
57-
$context = 'file '.$file.' near line '.$line;
58-
foreach ($this->getDocParser()->parse($docComment->getText(), $context) as $annotation) {
59-
if ($annotation instanceof Ignore) {
63+
$phpDocNode = $this->getPhpDocParser()->parse(
64+
new TokenIterator($this->lexer->tokenize($docComment->getText()))
65+
);
66+
foreach ($phpDocNode->getTags() as $tag) {
67+
if ('@Ignore' === $tag->name) {
6068
return;
6169
}
6270
}
@@ -78,36 +86,38 @@ protected function getLocation(string $text, int $line, ?Node $node = null, arra
7886
{
7987
$file = $this->getAbsoluteFilePath();
8088
if (null !== $node && null !== $docComment = $node->getDocComment()) {
81-
$parserContext = 'file '.$file.' near line '.$line;
82-
foreach ($this->getDocParser()->parse($docComment->getText(), $parserContext) as $annotation) {
83-
if ($annotation instanceof Ignore) {
89+
$phpDocNode = $this->getPhpDocParser()->parse(
90+
new TokenIterator($this->lexer->tokenize($docComment->getText()))
91+
);
92+
foreach ($phpDocNode->getTags() as $tag) {
93+
if ('@Ignore' === $tag->name) {
8494
return null;
85-
} elseif ($annotation instanceof Desc) {
86-
$context['desc'] = $annotation->text;
95+
} elseif ('@Desc' === $tag->name && $tag->value instanceof DoctrineTagValueNode) {
96+
if ([] !== $tag->value->annotation->arguments) {
97+
$context['desc'] = DoctrineConstExprStringNode::unescape($tag->value->annotation->arguments[0]->value);
98+
}
8799
}
88100
}
89101
}
90102

91103
return new SourceLocation($text, $file, $line, $context);
92104
}
93105

94-
private function getDocParser(): DocParser
106+
protected function getPhpDocParser(): PhpDocParser
95107
{
96-
if (null === $this->docParser) {
97-
$this->docParser = new DocParser();
98-
99-
$this->docParser->setImports([
100-
'ignore' => Ignore::class,
101-
'desc' => Desc::class,
102-
]);
103-
$this->docParser->setIgnoreNotImportedAnnotations(true);
108+
if (null === $this->phpDocParser) {
109+
$config = new ParserConfig(usedAttributes: []);
110+
$this->lexer = new Lexer($config);
111+
$constExprParser = new ConstExprParser($config);
112+
$typeParser = new TypeParser($config, $constExprParser);
113+
$this->phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
104114
}
105115

106-
return $this->docParser;
116+
return $this->phpDocParser;
107117
}
108118

109-
public function setDocParser(DocParser $docParser): void
119+
public function setPhpDocParser(PhpDocParser $phpDocParser): void
110120
{
111-
$this->docParser = $docParser;
121+
$this->phpDocParser = $phpDocParser;
112122
}
113123
}

src/Visitor/Php/Symfony/FormTypeChoices.php

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
namespace Translation\Extractor\Visitor\Php\Symfony;
1313

14-
use Doctrine\Common\Annotations\DocParser;
1514
use PhpParser\Node;
1615
use PhpParser\NodeVisitor;
17-
use Translation\Extractor\Annotation\Ignore;
16+
use PHPStan\PhpDocParser\Parser\TokenIterator;
1817
use Translation\Extractor\Model\SourceLocation;
1918

2019
/**
@@ -134,20 +133,15 @@ public function enterNode(Node $node): ?Node
134133

135134
protected function isIgnored(Node $node): bool
136135
{
137-
// because of getDocParser method is private, we have to create a new custom instance
138-
$docParser = new DocParser();
139-
$docParser->setImports([
140-
'ignore' => Ignore::class,
141-
]);
142-
$docParser->setIgnoreNotImportedAnnotations(true);
143-
if (null !== $docComment = $node->getDocComment()) {
144-
foreach ($docParser->parse($docComment->getText()) as $annotation) {
145-
if ($annotation instanceof Ignore) {
146-
return true;
147-
}
148-
}
136+
if (null === $node->getDocComment()) {
137+
return false;
149138
}
150139

151-
return false;
140+
$phpDocNode = $this->getPhpDocParser()->parse(
141+
new TokenIterator($this->lexer->tokenize($node->getDocComment()->getText()))
142+
);
143+
$ignoreTags = $phpDocNode->getTagsByName('@Ignore');
144+
145+
return \count($ignoreTags) > 0;
152146
}
153147
}

src/Visitor/Php/Symfony/ValidationAnnotation.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Translation\Extractor\Visitor\Php\Symfony;
1313

14-
use Doctrine\Common\Annotations\AnnotationException;
1514
use PhpParser\Node;
1615
use PhpParser\NodeVisitor;
1716
use Symfony\Component\Validator\Mapping\ClassMetadata;
@@ -60,14 +59,8 @@ public function enterNode(Node $node): ?Node
6059
return null;
6160
}
6261

63-
try {
64-
/** @var ClassMetadata $metadata */
65-
$metadata = $this->metadataFactory->getMetadataFor($name);
66-
} catch (AnnotationException $e) {
67-
$this->addError($node, \sprintf('Could not parse class "%s" for annotations. %s', $this->namespace, $e->getMessage()));
68-
69-
return null;
70-
}
62+
/** @var ClassMetadata $metadata */
63+
$metadata = $this->metadataFactory->getMetadataFor($name);
7164

7265
if (!$metadata->hasConstraints() && !\count($metadata->getConstrainedProperties())) {
7366
return null;

src/Visitor/Php/TranslateAnnotationVisitor.php

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111

1212
namespace Translation\Extractor\Visitor\Php;
1313

14-
use Doctrine\Common\Annotations\DocParser;
1514
use PhpParser\Comment;
1615
use PhpParser\Node;
1716
use PhpParser\NodeVisitor;
17+
use PHPStan\PhpDocParser\Ast\ConstExpr\DoctrineConstExprStringNode;
18+
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
19+
use PHPStan\PhpDocParser\Parser\TokenIterator;
1820
use Translation\Extractor\Annotation\Translate;
1921

2022
/**
@@ -24,22 +26,6 @@
2426
*/
2527
class TranslateAnnotationVisitor extends BasePHPVisitor implements NodeVisitor
2628
{
27-
protected ?DocParser $translateDocParser = null;
28-
29-
private function getTranslateDocParser(): DocParser
30-
{
31-
if (null === $this->translateDocParser) {
32-
$this->translateDocParser = new DocParser();
33-
34-
$this->translateDocParser->setImports([
35-
'translate' => Translate::class,
36-
]);
37-
$this->translateDocParser->setIgnoreNotImportedAnnotations(true);
38-
}
39-
40-
return $this->translateDocParser;
41-
}
42-
4329
public function enterNode(Node $node): ?Node
4430
{
4531
// look for strings
@@ -58,10 +44,21 @@ public function enterNode(Node $node): ?Node
5844
return null;
5945
}
6046

61-
foreach ($this->getTranslateDocParser()->parse($comment->getText()) as $annotation) {
62-
// add phrase to dictionary
63-
$this->addLocation($node->value, $node->getAttribute('startLine'), $node, ['domain' => $annotation->getDomain()]);
64-
47+
$phpDocNode = $this->getPhpDocParser()->parse(
48+
new TokenIterator($this->lexer->tokenize($comment->getText()))
49+
);
50+
51+
$translateTags = $phpDocNode->getTagsByName('@Translate');
52+
if ([] !== $translateTags) {
53+
$domain = 'messages';
54+
if ($translateTags[0]->value instanceof DoctrineTagValueNode) {
55+
foreach ($translateTags[0]->value->annotation->arguments as $argument) {
56+
if ('domain' === $argument->key->name) {
57+
$domain = DoctrineConstExprStringNode::unescape($argument->value);
58+
}
59+
}
60+
}
61+
$this->addLocation($node->value, $node->getAttribute('startLine'), $node, ['domain' => $domain]);
6562
break;
6663
}
6764
}

tests/bootstrap.php

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)