Summary
Extends the Drupal framework resolver to cover the full range of hook and plugin patterns used in Drupal 10.2+ / 11.x projects. The initial PR (#268) added route extraction and procedural hook detection; this issue tracks the missing pieces.
Relates to #268
What is being fixed
1. OOP hooks via #[Hook] attribute (Drupal 10.2+)
Drupal 10.2 introduced class-based hook implementations using PHP 8 attributes. Three placement styles are supported:
Method-level (most common):
#[Hook('entity_presave')]
public function entityPresave(EntityInterface $entity): void { ... }
Class-level with method: parameter (Drupal's recommended style for dedicated src/Hook/ classes):
#[Hook('form_alter', method: 'formAlter')]
class FormHooks {
public function formAlter(array &$form, ...): void { ... }
}
Class-level with __invoke():
#[Hook('cron')]
class CronHandler {
public function __invoke(): void { ... }
}
Stacked attributes (one method implements multiple hooks — previously only the last was detected):
#[Hook('comment_insert')]
#[Hook('comment_update')]
public function commentSave(CommentInterface $comment): void { ... }
2. Plugin declarations — docblock annotations and PHP 8 attributes
Both pre-10.2 annotation style and modern attribute style are detected and linked to a canonical drupal:plugin:{PluginType} reference:
// Annotation style (pre-10.2)
/** @Block(id = "my_block", ...) */
class MyBlock extends BlockBase { ... }
// PHP 8 attribute style (10.2+)
#[Block(id: 'my_block', ...)]
class MyBlock extends BlockBase { ... }
// Views plugins, entity types, REST resources, etc.
#[ViewsField('my_field')]
class MyField extends FieldPluginBase { ... }
#[ContentEntityType(id: 'my_entity', ...)]
class MyEntity extends ContentEntityBase { ... }
DRUPAL_PLUGIN_TYPES expanded from 28 → 55 types, covering all plugin types converted to PHP attributes in Drupal core (#3396165): ContentEntityType, ConfigEntityType, EntityType, RestResource, Layout, SectionStorage, MediaSource, DataType, Archiver, Editor, HelpSection, ImageToolkitOperation, LanguageNegotiation, Mail, MigrateField, MigrateProcessPlugin, PageDisplayVariant, RenderElement, SearchPlugin, WorkflowType, and all remaining Views plugin types.
3. Symfony event subscribers via *.services.yml
Services tagged event_subscriber are extracted as component nodes with a references edge to the PHP class:
services:
mymodule.event_subscriber:
class: Drupal\mymodule\EventSubscriber\MySubscriber
tags:
- { name: event_subscriber }
Verification — real Drupal 11 project (custom + contrib modules)
| Metric |
Before (initial PR) |
After (this PR) |
| Route nodes |
1,397 |
1,397 |
| Procedural hook refs |
1,826 |
1,826 |
OOP hook refs (#[Hook]) |
0 |
1,439 |
Plugin refs (decorates) |
0 |
1,630 |
| Event subscriber nodes |
0 |
75 |
Test coverage
54 unit tests covering all patterns:
- Procedural hooks (Strategy A docblock + Strategy B name pattern)
- OOP hooks: method-level, class-level
method:, class-level __invoke(), stacked attributes
- Plugin annotations:
@Block, @QueueWorker, @Filter, @ViewsField, @Layout, etc.
- Plugin PHP 8 attributes:
#[Block], #[Action], #[ViewsField], #[ContentEntityType], #[RestResource], etc.
- Event subscribers: single, multiple, non-subscriber services ignored
- Route extraction: single/multiple routes, HTTP methods, commented lines
- Resolution: controller FQCN → method, form FQCN → class, plugin → base class, FQCN → subscriber class
Summary
Extends the Drupal framework resolver to cover the full range of hook and plugin patterns used in Drupal 10.2+ / 11.x projects. The initial PR (#268) added route extraction and procedural hook detection; this issue tracks the missing pieces.
Relates to #268
What is being fixed
1. OOP hooks via
#[Hook]attribute (Drupal 10.2+)Drupal 10.2 introduced class-based hook implementations using PHP 8 attributes. Three placement styles are supported:
Method-level (most common):
Class-level with
method:parameter (Drupal's recommended style for dedicatedsrc/Hook/classes):Class-level with
__invoke():Stacked attributes (one method implements multiple hooks — previously only the last was detected):
2. Plugin declarations — docblock annotations and PHP 8 attributes
Both pre-10.2 annotation style and modern attribute style are detected and linked to a canonical
drupal:plugin:{PluginType}reference:DRUPAL_PLUGIN_TYPESexpanded from 28 → 55 types, covering all plugin types converted to PHP attributes in Drupal core (#3396165):ContentEntityType,ConfigEntityType,EntityType,RestResource,Layout,SectionStorage,MediaSource,DataType,Archiver,Editor,HelpSection,ImageToolkitOperation,LanguageNegotiation,Mail,MigrateField,MigrateProcessPlugin,PageDisplayVariant,RenderElement,SearchPlugin,WorkflowType, and all remaining Views plugin types.3. Symfony event subscribers via
*.services.ymlServices tagged
event_subscriberare extracted ascomponentnodes with areferencesedge to the PHP class:Verification — real Drupal 11 project (custom + contrib modules)
#[Hook])decorates)Test coverage
54 unit tests covering all patterns:
method:, class-level__invoke(), stacked attributes@Block,@QueueWorker,@Filter,@ViewsField,@Layout, etc.#[Block],#[Action],#[ViewsField],#[ContentEntityType],#[RestResource], etc.