ai_upgrade_assistant-0.2.0-alpha2/src/Controller/AnalysisController.php

src/Controller/AnalysisController.php
<?php

namespace Drupal\ai_upgrade_assistant\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Batch\BatchBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\ai_upgrade_assistant\Service\BatchAnalyzer;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;

/**
 * Controller for handling analysis operations.
 */
class AnalysisController extends ControllerBase {
  use DependencySerializationTrait;

  /**
   * The batch analyzer service.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\BatchAnalyzer
   */
  protected $batchAnalyzer;

  /**
   * The state service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * Constructs a new AnalysisController object.
   *
   * @param \Drupal\ai_upgrade_assistant\Service\BatchAnalyzer $batch_analyzer
   *   The batch analyzer service.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   */
  public function __construct(
    BatchAnalyzer $batch_analyzer,
    StateInterface $state,
    RendererInterface $renderer,
    DateFormatterInterface $date_formatter
  ) {
    $this->batchAnalyzer = $batch_analyzer;
    $this->state = $state;
    $this->renderer = $renderer;
    $this->dateFormatter = $date_formatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('ai_upgrade_assistant.batch_analyzer'),
      $container->get('state'),
      $container->get('renderer'),
      $container->get('date.formatter')
    );
  }

  /**
   * Starts the analysis process.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
   *   JSON response with batch token or redirect to batch processing.
   */
  public function startAnalysis() {
    // Clear any existing analysis data
    $this->state->delete('ai_upgrade_assistant.analysis_results');
    
    // Get list of enabled modules
    $modules = array_keys($this->moduleHandler()->getModuleList());
    
    // Create and set the batch
    $batch = $this->batchAnalyzer->createBatch($modules);
    
    // Set the batch
    batch_set($batch);
    
    // Process the batch
    if ($this->isAjax()) {
      $batch =& batch_get();
      $batch['progressive'] = TRUE;
      $response = [
        'status' => 'success',
        'message' => $this->t('Analysis started'),
        'batch_token' => $batch['token'],
      ];
      return new JsonResponse($response);
    }
    
    return batch_process('/admin/reports/ai-upgrade-assistant/analysis');
  }

  /**
   * Checks if the current request is an AJAX request.
   *
   * @return bool
   *   TRUE if the request is an AJAX request, FALSE otherwise.
   */
  protected function isAjax() {
    return \Drupal::request()->isXmlHttpRequest();
  }

  /**
   * Batch finished callback.
   */
  public function analysisFinished($success, $results, $operations) {
    if ($success) {
      $this->messenger()->addStatus($this->t('Module analysis completed successfully.'));
    }
    else {
      $this->messenger()->addError($this->t('There was an error during the analysis process.'));
    }
  }

  /**
   * Gets the current analysis progress.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with progress information.
   */
  public function getProgress() {
    $batch = batch_get();
    $results = $this->state->get('ai_upgrade_assistant.analysis_results', []);
    
    if (!$batch) {
      return new JsonResponse([
        'status' => 'complete',
        'current' => 100,
        'total' => 100,
        'message' => $this->t('Analysis complete'),
      ]);
    }

    $current = $batch['sets'][$batch['current_set']]['current'];
    $total = $batch['sets'][$batch['current_set']]['total'];
    
    return new JsonResponse([
      'status' => 'in_progress',
      'current' => $current,
      'total' => $total,
      'message' => $batch['sets'][$batch['current_set']]['message'],
      'terminal_output' => $this->getLatestTerminalOutput(),
    ]);
  }

  /**
   * Gets the latest recommendations.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with rendered recommendations.
   */
  public function getRecommendations() {
    $results = $this->state->get('ai_upgrade_assistant.analysis_results', []);
    
    $build = [
      '#theme' => 'upgrade_recommendations',
      '#recommendations' => $this->processResults($results),
    ];

    return new JsonResponse([
      'content' => $this->renderer->render($build),
    ]);
  }

  /**
   * Gets the code diff view.
   *
   * @return array
   *   Render array for the diff view.
   */
  public function getDiffView($file_path) {
    $results = $this->state->get('ai_upgrade_assistant.analysis_results', []);
    $file_results = $results['files'][$file_path] ?? [];
    
    return [
      '#theme' => 'code_diff_view',
      '#file_path' => $file_path,
      '#analysis' => $file_results,
      '#attached' => [
        'library' => ['ai_upgrade_assistant/diff_view'],
      ],
    ];
  }

  /**
   * Gets the latest terminal output.
   *
   * @return string
   *   The latest terminal output.
   */
  protected function getLatestTerminalOutput() {
    return $this->state->get('ai_upgrade_assistant.terminal_output', '');
  }

  /**
   * Processes analysis results into recommendations.
   *
   * @param array $results
   *   Raw analysis results.
   *
   * @return array
   *   Processed recommendations.
   */
  protected function processResults(array $results) {
    $recommendations = [];

    // Process core analysis
    if (!empty($results['core'])) {
      if (!$results['core']['compatible']) {
        $recommendations[] = [
          'type' => 'core_upgrade',
          'priority' => 'high',
          'message' => $this->t('Upgrade to Drupal 10 required. Current version: @version', 
            ['@version' => $results['core']['version']]),
        ];
      }
    }

    // Process module analysis
    if (!empty($results['modules'])) {
      foreach ($results['modules'] as $name => $module) {
        if (!$module['compatible']) {
          $recommendations[] = [
            'type' => 'module_compatibility',
            'priority' => 'medium',
            'message' => $this->t('Module @name needs to be updated for Drupal 10 compatibility',
              ['@name' => $name]),
            'details' => $module['issues'],
          ];
        }
      }
    }

    // Process file analysis
    if (!empty($results['files'])) {
      foreach ($results['files'] as $file_path => $analysis) {
        if (!empty($analysis['issues'])) {
          foreach ($analysis['issues'] as $issue) {
            $recommendations[] = [
              'type' => $issue['type'],
              'priority' => $issue['priority'],
              'message' => $issue['description'],
              'actions' => [
                [
                  'label' => $this->t('View changes'),
                  'url' => "admin/reports/upgrade-assistant/diff/" . urlencode($file_path),
                ],
              ],
              'code_example' => $issue['code_example'] ?? NULL,
            ];
          }
        }
      }
    }

    return $recommendations;
  }

  /**
   * Analyzes a specific module.
   *
   * @param string $module
   *   The machine name of the module to analyze.
   *
   * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
   *   A render array or redirect response.
   */
  public function analyzeModule($module) {
    // Create batch with single module
    $batch = $this->batchAnalyzer->createBatch([$module]);
    batch_set($batch);

    if (PHP_SAPI === 'cli') {
      drush_backend_batch_process();
      return [
        '#markup' => $this->t('Module analysis complete.'),
      ];
    }

    return batch_process("/admin/reports/upgrade-assistant/module/$module");
  }

  /**
   * Displays detailed analysis results for a module.
   *
   * @param string $module
   *   The machine name of the module.
   *
   * @return array
   *   A render array for the module details page.
   */
  public function moduleDetails($module) {
    $analysis_results = $this->state->get("ai_upgrade_assistant.analysis_results.$module", []);
    
    return [
      '#theme' => 'analysis_report',
      '#module' => $module,
      '#results' => $analysis_results,
      '#attached' => [
        'library' => ['ai_upgrade_assistant/analysis_report'],
      ],
    ];
  }

  /**
   * Displays analysis results for a specific module.
   *
   * @param string $module
   *   The machine name of the module.
   *
   * @return array
   *   A render array for the analysis results page.
   */
  public function displayAnalysisResults($module) {
    $results = $this->state->get('ai_upgrade_assistant.analysis_results', []);
    
    // If no results, try to analyze the module first
    if (empty($results[$module])) {
      try {
        $project_analyzer = \Drupal::service('ai_upgrade_assistant.project_analyzer');
        $analysis = $project_analyzer->analyzeModule($module);
        
        // Store results in state
        $results[$module] = $analysis;
        $this->state->set('ai_upgrade_assistant.analysis_results', $results);
        
        // Log success
        $this->getLogger('ai_upgrade_assistant')->info('Successfully analyzed module @module', ['@module' => $module]);
      }
      catch (\Exception $e) {
        // Log error
        $this->getLogger('ai_upgrade_assistant')->error('Error analyzing module @module: @error', [
          '@module' => $module,
          '@error' => $e->getMessage(),
        ]);
        
        // Show error message to user
        $this->messenger()->addError($this->t('Error analyzing module: @error', ['@error' => $e->getMessage()]));
        
        // Return empty analysis with error state
        return [
          '#theme' => 'ai_upgrade_assistant_analysis',
          '#analysis' => [
            'generated_on' => date('Y-m-d H:i:s'),
            'drupal_version' => \Drupal::VERSION,
            'status' => 'error',
            'error_message' => $e->getMessage(),
          ],
          '#attached' => [
            'library' => ['ai_upgrade_assistant/analysis_report'],
          ],
        ];
      }
    }

    $module_results = $results[$module] ?? [];
    
    // Add debug output
    $this->getLogger('ai_upgrade_assistant')->debug('Analysis results for @module: @results', [
      '@module' => $module,
      '@results' => print_r($module_results, TRUE),
    ]);

    // Format the analysis results for the template while preserving all AI details
    $formatted_results = [
      'generated_on' => date('Y-m-d H:i:s'),
      'drupal_version' => \Drupal::VERSION,
      'status' => 'success',
      'total_modules' => 1,
      'issues_found' => count($module_results['issues'] ?? []),
      'critical_issues' => count(array_filter($module_results['issues'] ?? [], function($issue) {
        return isset($issue['severity']) && $issue['severity'] === 'critical';
      })),
      'compatibility' => $module_results['compatibility_score'] ?? 0,
      'compatibility_factors' => $module_results['compatibility_factors'] ?? [],
      'modules' => [
        [
          'name' => $module,
          'version' => $module_results['version'] ?? 'unknown',
          'status' => $module_results['status'] ?? 'unknown',
          'description' => $module_results['description'] ?? '',
          'project_url' => $module_results['project_url'] ?? '',
          'issues' => array_map(function($issue) {
            return [
              'severity' => $issue['severity'] ?? 'notice',
              'severity_icon' => $this->getSeverityIcon($issue['severity'] ?? 'notice'),
              'title' => $issue['title'] ?? $issue['message'] ?? '',
              'message' => $issue['message'] ?? '',
              'file' => $issue['file'] ?? '',
              'solution' => $issue['solution'] ?? '',
            ];
          }, $module_results['issues'] ?? []),
          'code_quality' => [
            'coding_standards' => array_map(function($issue) {
              return [
                'message' => $issue['message'] ?? '',
                'file' => $issue['file'] ?? '',
                'line' => $issue['line'] ?? '',
                'solution' => $issue['solution'] ?? '',
              ];
            }, $module_results['code_quality']['coding_standards'] ?? []),
            'deprecated_code' => array_map(function($issue) {
              return [
                'message' => $issue['message'] ?? '',
                'file' => $issue['file'] ?? '',
                'line' => $issue['line'] ?? '',
                'replacement' => $issue['replacement'] ?? '',
              ];
            }, $module_results['code_quality']['deprecated_code'] ?? []),
          ],
        ],
      ],
      'ai_recommendation' => [
        'greeting' => $module_results['ai_recommendation']['greeting'] ?? '',
        'message' => $module_results['ai_recommendation']['message'] ?? '',
        'next_steps' => $module_results['ai_recommendation']['next_steps'] ?? [],
        'time_estimate' => [
          'min' => $module_results['ai_recommendation']['time_estimate']['min'] ?? 0,
          'max' => $module_results['ai_recommendation']['time_estimate']['max'] ?? 0,
        ],
        'confidence' => $module_results['ai_recommendation']['confidence'] ?? 'medium',
      ],
    ];

    return [
      '#theme' => 'ai_upgrade_assistant_analysis',
      '#analysis' => $formatted_results,
      '#attached' => [
        'library' => ['ai_upgrade_assistant/analysis_report'],
      ],
    ];
  }

  /**
   * Gets the icon for a severity level.
   *
   * @param string $severity
   *   The severity level.
   *
   * @return string
   *   The material icon name.
   */
  protected function getSeverityIcon($severity) {
    switch ($severity) {
      case 'critical':
        return 'error';
      case 'error':
        return 'warning';
      case 'warning':
        return 'info';
      default:
        return 'check_circle';
    }
  }

  /**
   * Displays the analysis report.
   *
   * @return array
   *   A render array representing the analysis report.
   */
  public function displayReport() {
    $results = $this->state->get('ai_upgrade_assistant.analysis_results', []);
    
    // Process the results
    $summary = $this->calculateSummary($results);
    $moduleAnalysis = $this->processModuleAnalysis($results);
    $securityIssues = $this->processSecurityIssues($results);

    // Structure the analysis data
    $analysis = [
      'generated_on' => [
        '#markup' => $this->dateFormatter->format(time(), 'custom', 'Y-m-d H:i:s T'),
      ],
      'drupal_version' => [
        '#markup' => \Drupal::VERSION,
      ],
      'total_modules' => [
        '#markup' => $summary['total_files'] ?? 0,
      ],
      'issues_found' => [
        '#markup' => $summary['total_issues'] ?? 0,
      ],
      'critical_issues' => [
        '#markup' => $summary['critical_issues'] ?? 0,
      ],
      'compatibility' => [
        '#markup' => isset($summary['total_files']) && $summary['total_files'] > 0 
          ? round(100 - (($summary['total_issues'] / $summary['total_files']) * 100))
          : 0,
      ],
      'modules' => array_map(function($module) {
        return [
          'name' => ['#markup' => $module['name']],
          'version' => ['#markup' => $module['version']],
          'status' => ['#markup' => $module['status']],
          'issues' => array_map(function($issue) {
            return [
              'type' => ['#markup' => $issue['type'] ?? 'unknown'],
              'message' => ['#markup' => $issue['message'] ?? ''],
              'severity' => ['#markup' => $issue['severity'] ?? 'info'],
            ];
          }, $module['issues'] ?? []),
        ];
      }, $moduleAnalysis),
      'security_issues' => array_map(function($issue) {
        return [
          'module' => ['#markup' => $issue['module']],
          'title' => ['#markup' => $issue['title']],
          'severity' => ['#markup' => $issue['severity']],
          'description' => ['#markup' => $issue['description']],
          'solution' => ['#markup' => $issue['solution'] ?? ''],
        ];
      }, $securityIssues),
    ];

    return [
      '#theme' => 'ai_upgrade_assistant_analysis',
      '#analysis' => $analysis,
      '#attached' => [
        'library' => ['ai_upgrade_assistant/analysis_report'],
      ],
    ];
  }

  /**
   * Calculates summary statistics from analysis results.
   */
  protected function calculateSummary($results) {
    $summary = [
      'total_files' => 0,
      'total_issues' => 0,
      'critical_issues' => 0,
      'warnings' => 0,
      'suggestions' => 0,
    ];

    if (!empty($results['files'])) {
      $summary['total_files'] = count($results['files']);
      
      foreach ($results['files'] as $file) {
        if (!empty($file['issues'])) {
          foreach ($file['issues'] as $issue) {
            $summary['total_issues']++;
            switch ($issue['severity']) {
              case 'critical':
                $summary['critical_issues']++;
                break;
              case 'warning':
                $summary['warnings']++;
                break;
              case 'suggestion':
                $summary['suggestions']++;
                break;
            }
          }
        }
      }
    }

    return $summary;
  }

  /**
   * Processes module analysis results.
   */
  protected function processModuleAnalysis($results) {
    $moduleAnalysis = [];

    if (!empty($results['modules'])) {
      foreach ($results['modules'] as $name => $module) {
        $moduleAnalysis[$name] = [
          'name' => $name,
          'version' => $module['version'] ?? 'Unknown',
          'status' => $module['compatible'] ? 'Compatible' : 'Needs Update',
          'issues' => $module['issues'] ?? [],
          'dependencies' => $module['dependencies'] ?? [],
          'security_issues' => $module['security_issues'] ?? [],
          'available_updates' => $module['available_updates'] ?? [],
        ];
      }
    }

    return $moduleAnalysis;
  }

  /**
   * Processes security issues from results.
   */
  protected function processSecurityIssues($results) {
    $securityIssues = [];

    if (!empty($results['security'])) {
      foreach ($results['security'] as $module => $issues) {
        foreach ($issues as $issue) {
          $securityIssues[] = [
            'module' => $module,
            'title' => $issue['title'],
            'severity' => $issue['severity'],
            'description' => $issue['description'],
            'solution' => $issue['solution'] ?? '',
            'advisory_link' => $issue['link'] ?? '',
          ];
        }
      }
    }

    return $securityIssues;
  }
}

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

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