Skip to content

[BetterPhpDocParser] inject phpdoc node decorators explicitly to keep required order - #8379

Merged
TomasVotruba merged 1 commit into
mainfrom
tv-no-tagged
Aug 25, 2026
Merged

[BetterPhpDocParser] inject phpdoc node decorators explicitly to keep required order#8379
TomasVotruba merged 1 commit into
mainfrom
tv-no-tagged

Conversation

@TomasVotruba

Copy link
Copy Markdown
Member

The PHP doc node decorators had a required run order that autodiscovery does not guarantee.

DoctrineAnnotationDecorator transforms a raw GenericTagValueNode annotation into a DoctrineAnnotationTagValueNode tree, creating the ArrayItemNodes. ArrayItemClassNameDecorator then resolves class names inside those nodes. So Doctrine must run first.

Autodiscovering the NodeDecorator/ directory ordered them by filesystem, dropping DoctrineAnnotationDecorator to last:

autodiscover order: ConstExpr, ArrayItem, PhpDocTagGenericUses, DoctrineAnnotation
required order:      ConstExpr, DoctrineAnnotation, ArrayItem, PhpDocTagGenericUses

With Doctrine last, ArrayItemClassNameDecorator runs on un-transformed text, never marks the annotation class usages, and removeUnusedImports() then strips imports that are actually used inside annotations:

 <?php

-use App\Repository\DemoRepository;
-use Doctrine\DBAL\Types\Types;
 use Doctrine\ORM\Mapping as ORM;

 /**
  * @ORM\Entity(repositoryClass=DemoRepository::class)
  */
 final class SkipUsedInAnnotation
 {
     /**
      * @ORM\Column(type=Types::STRING, length=100, nullable=false)
      */
     protected $status;
 }

Fix

Inject the four decorators as explicit __construct() params, in the required order, instead of autodiscovering them — the order is now encoded in the service and documented with a comment. Container autowires each concrete decorator by type.

…xplicitly in order

Move the four PhpDocNodeDecorator services out of the PhpDocParser
namespace into a dedicated NodeDecorator namespace, and inject them into
BetterPhpDocParser as explicit constructor params instead of a tagged
collection.

The decorators have a required run order: DoctrineAnnotationDecorator
must run before ArrayItemClassNameDecorator, which resolves class names
in the array items the former produces (e.g. inside doctrine
annotations). Explicit ordered injection guarantees this; tagged or
autodiscovered registration would not.
@TomasVotruba
TomasVotruba merged commit a1d9964 into main Aug 25, 2026
44 checks passed
@TomasVotruba
TomasVotruba deleted the tv-no-tagged branch August 25, 2026 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant