ai_upgrade_assistant-0.2.0-alpha2/src/Service/NodeVisitor/EventSubscriberVisitor.php
src/Service/NodeVisitor/EventSubscriberVisitor.php
<?php
namespace Drupal\ai_upgrade_assistant\Service\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
/**
* Node visitor that analyzes event subscriber usage and deprecated events.
*/
class EventSubscriberVisitor extends NodeVisitorAbstract {
/**
* List of findings.
*
* @var array
*/
protected $findings = [];
/**
* List of deprecated events and their replacements.
*
* @var array
*/
protected $deprecatedEvents = [
'kernel.request' => [
'replacement' => 'kernel.request',
'version' => '9.0.0',
'critical' => false,
'note' => 'Consider using route subscribers or middleware instead',
],
'kernel.response' => [
'replacement' => 'kernel.response',
'version' => '9.0.0',
'critical' => false,
'note' => 'Consider using response event subscribers',
],
'config.save' => [
'replacement' => 'Drupal\Core\Config\ConfigEvents::SAVE',
'version' => '8.0.0',
'critical' => true,
],
'config.delete' => [
'replacement' => 'Drupal\Core\Config\ConfigEvents::DELETE',
'version' => '8.0.0',
'critical' => true,
],
];
/**
* List of events requiring special attention in Drupal 11.
*
* @var array
*/
protected $drupal11Events = [
'kernel.view' => [
'changes' => [
'Enhanced response handling',
'New view event arguments',
],
'example' => 'Use getControllerResult() for structured data',
],
'kernel.response' => [
'changes' => [
'Response manipulation improvements',
'Cache metadata handling',
],
'example' => 'Use response event for cache tags',
],
];
/**
* {@inheritdoc}
*/
public function enterNode(Node $node) {
// Check for EventSubscriberInterface implementation
if ($node instanceof Node\Stmt\Class_) {
$implements_subscriber = false;
foreach ($node->implements as $interface) {
if ($interface->toString() === 'EventSubscriberInterface') {
$implements_subscriber = true;
break;
}
}
if ($implements_subscriber) {
$finding = [
'type' => 'event_subscriber',
'class' => $node->name->toString(),
'line' => $node->getLine(),
'file' => $node->getAttribute('file'),
];
// Find getSubscribedEvents method
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Node\Stmt\ClassMethod && $stmt->name->toString() === 'getSubscribedEvents') {
$events = $this->extractSubscribedEvents($stmt);
if (!empty($events)) {
$finding['subscribed_events'] = $events;
// Check for deprecated events
foreach ($events as $event_name) {
if (isset($this->deprecatedEvents[$event_name])) {
if (!isset($finding['deprecated_events'])) {
$finding['deprecated_events'] = [];
}
$finding['deprecated_events'][] = [
'event' => $event_name,
'replacement' => $this->deprecatedEvents[$event_name]['replacement'],
'version' => $this->deprecatedEvents[$event_name]['version'],
'critical' => $this->deprecatedEvents[$event_name]['critical'],
'note' => isset($this->deprecatedEvents[$event_name]['note']) ? $this->deprecatedEvents[$event_name]['note'] : null,
];
}
// Check for D11 event changes
if (isset($this->drupal11Events[$event_name])) {
if (!isset($finding['drupal11_events'])) {
$finding['drupal11_events'] = [];
}
$finding['drupal11_events'][] = [
'event' => $event_name,
'changes' => $this->drupal11Events[$event_name],
];
}
}
}
}
}
$this->findings[] = $finding;
}
}
}
/**
* Extracts subscribed events from getSubscribedEvents method.
*
* @param \PhpParser\Node\Stmt\ClassMethod $method
* The getSubscribedEvents method node.
*
* @return array
* Array of event names.
*/
protected function extractSubscribedEvents(Node\Stmt\ClassMethod $method) {
$events = [];
if (!empty($method->stmts)) {
foreach ($method->stmts as $stmt) {
if ($stmt instanceof Node\Stmt\Return_) {
if ($stmt->expr instanceof Node\Expr\Array_) {
foreach ($stmt->expr->items as $item) {
if ($item->key instanceof Node\Scalar\String_) {
$events[] = $item->key->value;
}
}
}
}
}
}
return $events;
}
/**
* Gets the findings.
*
* @return array
* Array of findings.
*/
public function getFindings() {
return $this->findings;
}
/**
* Resets the findings.
*/
public function reset() {
$this->findings = [];
}
}
