ai_upgrade_assistant-0.2.0-alpha2/src/Service/BatchAnalyzer.php
src/Service/BatchAnalyzer.php
<?php
namespace Drupal\ai_upgrade_assistant\Service;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Queue\QueueFactory;
/**
* Service for handling batch processing of module analysis.
*/
class BatchAnalyzer {
use StringTranslationTrait;
use DependencySerializationTrait;
/**
* The project analyzer service.
*
* @var \Drupal\ai_upgrade_assistant\Service\ProjectAnalyzer
*/
protected $projectAnalyzer;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The analysis tracker service.
*
* @var \Drupal\ai_upgrade_assistant\Service\AnalysisTracker
*/
protected $analysisTracker;
/**
* The patch searcher service.
*
* @var \Drupal\ai_upgrade_assistant\Service\PatchSearcher
*/
protected $patchSearcher;
/**
* The cache service.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* The queue factory service.
*
* @var \Drupal\Core\Queue\QueueFactory
*/
protected $queueFactory;
/**
* The batch size for processing.
*
* @var int
*/
protected $batchSize = 5;
/**
* Constructs a new BatchAnalyzer object.
*
* @param \Drupal\ai_upgrade_assistant\Service\ProjectAnalyzer $project_analyzer
* The project analyzer service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\ai_upgrade_assistant\Service\AnalysisTracker $analysis_tracker
* The analysis tracker service.
* @param \Drupal\ai_upgrade_assistant\Service\PatchSearcher $patch_searcher
* The patch searcher service.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache service.
* @param \Drupal\Core\Queue\QueueFactory $queue_factory
* The queue factory service.
*/
public function __construct(
ProjectAnalyzer $project_analyzer,
StateInterface $state,
ModuleHandlerInterface $module_handler,
AnalysisTracker $analysis_tracker,
PatchSearcher $patch_searcher,
CacheBackendInterface $cache,
QueueFactory $queue_factory
) {
$this->projectAnalyzer = $project_analyzer;
$this->state = $state;
$this->moduleHandler = $module_handler;
$this->analysisTracker = $analysis_tracker;
$this->patchSearcher = $patch_searcher;
$this->cache = $cache;
$this->queueFactory = $queue_factory;
}
/**
* Creates a batch for analyzing modules.
*
* @param array $modules
* Array of module names to analyze.
*
* @return array
* Batch definition array.
*/
public function createBatch(array $modules) {
// Clear previous analysis results.
$this->state->delete('ai_upgrade_assistant.last_analysis_results');
$this->cache->deleteMultiple(['ai_upgrade_assistant_analysis']);
// Group modules into chunks for better performance
$chunks = array_chunk($modules, $this->batchSize);
$operations = [];
foreach ($chunks as $chunk) {
$operations[] = [
[static::class, 'analyzeBatchChunk'],
[$chunk],
];
}
return [
'title' => $this->t('Analyzing modules'),
'operations' => $operations,
'finished' => [static::class, 'batchFinished'],
'file' => drupal_get_path('module', 'ai_upgrade_assistant') . '/src/Service/BatchAnalyzer.php',
'progressive' => TRUE,
'init_message' => $this->t('Starting module analysis...'),
'progress_message' => $this->t('Analyzed @current out of @total module groups.'),
'error_message' => $this->t('An error occurred during the analysis.'),
];
}
/**
* Process a batch chunk of modules.
*
* This is a static method to avoid serialization issues.
*
* @param array $modules
* Array of module names in this chunk.
* @param array $context
* Batch context array.
*/
public static function analyzeBatchChunk(array $modules, array &$context) {
// Initialize progress if not set
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['current_module'] = 0;
$context['sandbox']['max'] = count($modules);
$context['results']['analyzed'] = [];
$context['results']['errors'] = [];
}
foreach ($modules as $module) {
try {
// Get required services
$module_handler = \Drupal::service('module_handler');
$project_analyzer = \Drupal::service('ai_upgrade_assistant.project_analyzer');
$analysis_tracker = \Drupal::service('ai_upgrade_assistant.analysis_tracker');
$patch_searcher = \Drupal::service('ai_upgrade_assistant.patch_searcher');
$state = \Drupal::service('state');
// Skip if module doesn't exist
if (!$module_handler->moduleExists($module)) {
$context['results']['errors'][$module] = t('Module @name does not exist.', [
'@name' => $module,
]);
continue;
}
// Get module info
$module_info = $project_analyzer->getModuleInfo($module);
$module_path = $module_info['path'];
// Initialize analysis
$analysis_tracker->initializeAnalysis($module);
// Store module info
$context['results']['module_info'][$module] = $module_info;
// Analyze code
$code_analysis = $project_analyzer->analyzeCode($module, $module_path);
$analysis_tracker->updateAnalysis($module, $code_analysis, 'code_analysis');
$context['results']['code_analysis'][$module] = $code_analysis;
// Analyze dependencies
$dependencies = $project_analyzer->analyzeDependencies($module);
$analysis_tracker->updateAnalysis($module, $dependencies, 'dependencies');
$context['results']['dependencies'][$module] = $dependencies;
// Search patches
$patches = $patch_searcher->findPatches($module);
$analysis_tracker->updateAnalysis($module, $patches, 'patches');
$context['results']['patches'][$module] = $patches;
// Analyze security
$security = $project_analyzer->analyzeSecurityIssues($module);
$analysis_tracker->updateAnalysis($module, $security, 'security_analysis');
$context['results']['security_analysis'][$module] = $security;
// Update progress
$context['sandbox']['progress']++;
$context['message'] = t('Analyzed module: @name', [
'@name' => $module,
]);
$context['results']['analyzed'][] = $module;
}
catch (\Exception $e) {
$context['results']['errors'][$module] = $e->getMessage();
\Drupal::logger('ai_upgrade_assistant')->error('Error analyzing module @module: @error', [
'@module' => $module,
'@error' => $e->getMessage(),
]);
}
}
}
/**
* Batch finished callback.
*
* This is a static method to avoid serialization issues.
*
* @param bool $success
* Whether the batch succeeded.
* @param array $results
* The batch results.
* @param array $operations
* The operations that remained unprocessed.
*/
public static function batchFinished($success, array $results, array $operations) {
if ($success) {
if (!empty($results['errors'])) {
foreach ($results['errors'] as $module => $error) {
\Drupal::messenger()->addError(
t('Error analyzing @module: @error', [
'@module' => $module,
'@error' => $error,
])
);
}
}
$count = count($results['analyzed']);
\Drupal::messenger()->addStatus(
t('Successfully analyzed @count modules.', [
'@count' => $count,
])
);
// Cache the combined results
\Drupal::service('cache.default')->set('ai_upgrade_assistant.analysis_results', $results);
}
else {
\Drupal::messenger()->addError(t('An error occurred during module analysis.'));
}
}
/**
* Sets the batch size.
*
* @param int $size
* The batch size.
*/
public function setBatchSize($size) {
$this->batchSize = max(1, (int) $size);
}
/**
* {@inheritdoc}
*/
public function __sleep() {
$vars = get_object_vars($this);
unset($vars['projectAnalyzer'], $vars['analysisTracker'], $vars['patchSearcher'], $vars['state'], $vars['moduleHandler'], $vars['cache'], $vars['queueFactory']);
return array_keys($vars);
}
/**
* {@inheritdoc}
*/
public function __wakeup() {
$this->projectAnalyzer = \Drupal::service('ai_upgrade_assistant.project_analyzer');
$this->analysisTracker = \Drupal::service('ai_upgrade_assistant.analysis_tracker');
$this->patchSearcher = \Drupal::service('ai_upgrade_assistant.patch_searcher');
$this->state = \Drupal::state();
$this->moduleHandler = \Drupal::moduleHandler();
$this->cache = \Drupal::cache();
$this->queueFactory = \Drupal::service('queue');
}
}
