ai_upgrade_assistant-0.2.0-alpha2/src/Service/NodeVisitor/DrupalDependencyVisitor.php
src/Service/NodeVisitor/DrupalDependencyVisitor.php
<?php
namespace Drupal\ai_upgrade_assistant\Service\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\MethodCall;
/**
* Analyzes Drupal dependencies and service usage patterns.
*/
class DrupalDependencyVisitor extends NodeVisitorAbstract {
/**
* Collected findings.
*
* @var array
*/
protected $findings = [];
/**
* Service dependencies found in constructor injection.
*
* @var array
*/
protected $serviceDependencies = [];
/**
* Static service calls found.
*
* @var array
*/
protected $staticServiceCalls = [];
/**
* {@inheritdoc}
*/
public function enterNode(Node $node) {
// Check for constructor injection
if ($node instanceof Node\Stmt\ClassMethod && $node->name->toString() === '__construct') {
foreach ($node->params as $param) {
if ($param->type instanceof Node\Name) {
$typeName = $param->type->toString();
if (strpos($typeName, 'Drupal\\') === 0) {
$this->serviceDependencies[] = [
'type' => 'constructor_injection',
'service' => $typeName,
'parameter' => $param->var->name,
'line' => $node->getLine(),
];
}
}
}
}
// Check for \Drupal::service() calls
if ($node instanceof StaticCall) {
if ($node->class instanceof Node\Name && $node->class->toString() === 'Drupal') {
if ($node->name->toString() === 'service') {
$this->staticServiceCalls[] = [
'type' => 'static_service_call',
'service' => $this->getServiceName($node),
'line' => $node->getLine(),
];
}
}
}
// Check for module dependencies in hook_requirements
if ($node instanceof FuncCall && $node->name instanceof Node\Name) {
$funcName = $node->name->toString();
if ($funcName === 'hook_requirements') {
$this->analyzeRequirements($node);
}
}
// Check for service container calls
if ($node instanceof MethodCall) {
if ($node->var instanceof Node\Expr\PropertyFetch) {
$prop = $node->var->name->toString();
if ($prop === 'container' && $node->name->toString() === 'get') {
$this->staticServiceCalls[] = [
'type' => 'container_get',
'service' => $this->getServiceName($node),
'line' => $node->getLine(),
];
}
}
}
}
/**
* Analyzes hook_requirements for module dependencies.
*
* @param \PhpParser\Node\Expr\FuncCall $node
* The function call node.
*/
protected function analyzeRequirements(FuncCall $node) {
// Look for module_exists, module_load_include calls
$visitor = $this;
$this->findings['requirements'] = [];
$nodeTraverser = new \PhpParser\NodeTraverser();
$nodeTraverser->addVisitor(new class($visitor->findings['requirements']) extends NodeVisitorAbstract {
protected $requirements;
public function __construct(&$requirements) {
$this->requirements = &$requirements;
}
public function enterNode(Node $node) {
if ($node instanceof FuncCall && $node->name instanceof Node\Name) {
$name = $node->name->toString();
if (in_array($name, ['module_exists', 'module_load_include'])) {
if (isset($node->args[0])) {
$this->requirements[] = [
'type' => 'module_dependency',
'function' => $name,
'module' => $this->getArgValue($node->args[0]->value),
'line' => $node->getLine(),
];
}
}
}
}
protected function getArgValue($value) {
if ($value instanceof Node\Scalar\String_) {
return $value->value;
}
return null;
}
});
if (isset($node->stmts)) {
$nodeTraverser->traverse($node->stmts);
}
}
/**
* Gets the service name from a service call node.
*
* @param \PhpParser\Node $node
* The node containing the service call.
*
* @return string|null
* The service name or null if not found.
*/
protected function getServiceName(Node $node) {
if (isset($node->args[0])) {
$arg = $node->args[0]->value;
if ($arg instanceof Node\Scalar\String_) {
return $arg->value;
}
}
return null;
}
/**
* Gets all findings.
*
* @return array
* Array of findings.
*/
public function getFindings() {
return [
'service_dependencies' => $this->serviceDependencies,
'static_service_calls' => $this->staticServiceCalls,
'requirements' => $this->findings['requirements'] ?? [],
];
}
/**
* Resets the visitor's state.
*/
public function reset() {
$this->findings = [];
$this->serviceDependencies = [];
$this->staticServiceCalls = [];
}
}
