ai_upgrade_assistant-0.2.0-alpha2/src/Service/PhpParserService.php

src/Service/PhpParserService.php
<?php

namespace Drupal\ai_upgrade_assistant\Service;

use PhpParser\Error;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\Node;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\NodeFinder;
use PhpParser\PrettyPrinter;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\ai_upgrade_assistant\Service\NodeVisitor\DeprecatedFunctionVisitor;
use Drupal\ai_upgrade_assistant\Service\NodeVisitor\HookVisitor;
use Drupal\ai_upgrade_assistant\Service\NodeVisitor\ClassUsageVisitor;
use Drupal\ai_upgrade_assistant\Service\NodeVisitor\DrupalDependencyVisitor;
use Drupal\ai_upgrade_assistant\Service\NodeVisitor\PluginPatternVisitor;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;

/**
 * Service for parsing and analyzing PHP code using PHP Parser.
 */
class PhpParserService {
  use DependencySerializationTrait;

  /**
   * The PHP parser instance.
   *
   * @var \PhpParser\Parser
   */
  protected $parser;

  /**
   * The node traverser.
   *
   * @var \PhpParser\NodeTraverser
   */
  protected $traverser;

  /**
   * The node finder.
   *
   * @var \PhpParser\NodeFinder
   */
  protected $nodeFinder;

  /**
   * The pretty printer.
   *
   * @var \PhpParser\PrettyPrinter\Standard
   */
  protected $prettyPrinter;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * The file system service.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The deprecated function visitor.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\NodeVisitor\DeprecatedFunctionVisitor
   */
  protected $deprecatedFunctionVisitor;

  /**
   * The hook visitor.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\NodeVisitor\HookVisitor
   */
  protected $hookVisitor;

  /**
   * The class usage visitor.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\NodeVisitor\ClassUsageVisitor
   */
  protected $classUsageVisitor;

  /**
   * The Drupal dependency visitor.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\NodeVisitor\DrupalDependencyVisitor
   */
  protected $dependencyVisitor;

  /**
   * The plugin pattern visitor.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\NodeVisitor\PluginPatternVisitor
   */
  protected $pluginPatternVisitor;

  /**
   * Constructs a new PhpParserService.
   *
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory service.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system service.
   */
  public function __construct(
    LoggerChannelFactoryInterface $logger_factory,
    FileSystemInterface $file_system
  ) {
    $this->loggerFactory = $logger_factory;
    $this->fileSystem = $file_system;
    
    // Initialize PHP Parser components
    $this->parser = (new ParserFactory())->createForHostVersion();
    
    // Initialize traverser with name resolver
    $this->traverser = new NodeTraverser();
    $this->traverser->addVisitor(new NameResolver());
    
    // Initialize visitors
    $this->deprecatedFunctionVisitor = new DeprecatedFunctionVisitor();
    $this->classUsageVisitor = new ClassUsageVisitor();
    $this->dependencyVisitor = new DrupalDependencyVisitor();
    $this->pluginPatternVisitor = new PluginPatternVisitor();
    
    $this->nodeFinder = new NodeFinder();
    $this->prettyPrinter = new PrettyPrinter\Standard();
  }

  /**
   * Parses a PHP file and returns its AST.
   *
   * @param string $file_path
   *   Path to the PHP file.
   *
   * @return \PhpParser\Node\Stmt[]|null
   *   Array of statements or null on error.
   */
  public function parseFile(string $file_path) {
    try {
      // Ensure we have an absolute path
      if (!$this->fileSystem->realpath($file_path)) {
        // Try prepending DRUPAL_ROOT
        $drupal_root = \Drupal::root();
        $full_path = $drupal_root . '/' . $file_path;
        
        if (!$this->fileSystem->realpath($full_path)) {
          $this->loggerFactory->get('ai_upgrade_assistant')->error(
            'File not found: @file',
            ['@file' => $file_path]
          );
          return NULL;
        }
        
        $file_path = $full_path;
      }

      if (!file_exists($file_path)) {
        $this->loggerFactory->get('ai_upgrade_assistant')->error(
          'File does not exist: @file',
          ['@file' => $file_path]
        );
        return NULL;
      }

      $code = file_get_contents($file_path);
      if ($code === FALSE) {
        $this->loggerFactory->get('ai_upgrade_assistant')->error(
          'Failed to read file: @file',
          ['@file' => $file_path]
        );
        return NULL;
      }
      return $this->parser->parse($code);
    }
    catch (Error $error) {
      $this->loggerFactory->get('ai_upgrade_assistant')->error(
        'Parse error in @file: @message',
        [
          '@file' => $file_path,
          '@message' => $error->getMessage(),
        ]
      );
      return NULL;
    }
  }

  /**
   * Analyzes a PHP file for deprecated code and compatibility issues.
   *
   * @param string $file_path
   *   Path to the PHP file.
   * @param string $module_name
   *   The module name.
   *
   * @return array
   *   Analysis results containing deprecated functions, hooks, and class usage.
   */
  public function analyzeFile(string $file_path, string $module_name) {
    $ast = $this->parseFile($file_path);
    if (!$ast) {
      return [
        'status' => 'error',
        'message' => 'Failed to parse file',
      ];
    }

    // Reset all visitors
    $this->deprecatedFunctionVisitor->reset();
    $this->classUsageVisitor->reset();
    $this->dependencyVisitor->reset();
    $this->pluginPatternVisitor->reset();

    // Create a new hook visitor for this module
    $this->hookVisitor = new HookVisitor($module_name);

    // Add visitors to traverser
    $traverser = new NodeTraverser();
    $traverser->addVisitor(new NameResolver());
    $traverser->addVisitor($this->deprecatedFunctionVisitor);
    $traverser->addVisitor($this->hookVisitor);
    $traverser->addVisitor($this->classUsageVisitor);
    $traverser->addVisitor($this->dependencyVisitor);
    $traverser->addVisitor($this->pluginPatternVisitor);

    // Traverse the AST
    $traverser->traverse($ast);

    // Get findings from all visitors
    $findings = [
      'status' => 'success',
      'file' => $file_path,
      'deprecated_functions' => $this->deprecatedFunctionVisitor->getFindings(),
      'hooks' => $this->hookVisitor->getFindings(),
      'class_usage' => $this->classUsageVisitor->getFindings(),
      'dependencies' => $this->dependencyVisitor->getFindings(),
      'plugin_patterns' => $this->pluginPatternVisitor->getFindings(),
    ];

    // Add analysis metadata
    $findings['analysis_metadata'] = [
      'timestamp' => time(),
      'module' => $module_name,
      'php_version' => PHP_VERSION,
      'patterns_found' => [
        'deprecated' => count($findings['deprecated_functions']),
        'hooks' => count($findings['hooks']),
        'classes' => count($findings['class_usage']),
        'dependencies' => count($findings['dependencies']['service_dependencies'] ?? []),
        'plugins' => count($findings['plugin_patterns']['plugins'] ?? []),
      ],
    ];

    return $findings;
  }

  /**
   * Gets all deprecated items from a file.
   *
   * @param string $file_path
   *   Path to the PHP file.
   * @param string $module_name
   *   The module name.
   *
   * @return array
   *   Array of deprecated items.
   */
  public function getDeprecatedItems(string $file_path, string $module_name) {
    $analysis = $this->analyzeFile($file_path, $module_name);
    if ($analysis['status'] === 'error') {
      return [];
    }

    return [
      'functions' => $analysis['deprecated_functions'],
      'methods' => $analysis['plugin_patterns']['deprecated_methods'] ?? [],
      'classes' => array_filter(
        $analysis['class_usage'],
        function ($usage) {
          return isset($usage['deprecated']) && $usage['deprecated'];
        }
      ),
    ];
  }

  /**
   * Gets all Drupal-specific patterns from a file.
   *
   * @param string $file_path
   *   Path to the PHP file.
   * @param string $module_name
   *   The module name.
   *
   * @return array
   *   Array of Drupal patterns.
   */
  public function getDrupalPatterns(string $file_path, string $module_name) {
    $analysis = $this->analyzeFile($file_path, $module_name);
    if ($analysis['status'] === 'error') {
      return [];
    }

    return [
      'hooks' => $analysis['hooks'],
      'plugins' => $analysis['plugin_patterns'],
      'services' => [
        'dependencies' => $analysis['dependencies']['service_dependencies'] ?? [],
        'static_calls' => $analysis['dependencies']['static_service_calls'] ?? [],
      ],
      'interfaces' => $analysis['plugin_patterns']['interfaces'] ?? [],
      'extends' => $analysis['plugin_patterns']['extends'] ?? [],
    ];
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc