systemStats = $this->collectSystemStats(); } /** * Analizza tutti i duplicati nel sistema */ public function analyzeDuplicates(): array { $directories = [ 'resources/views' => 'active', '_DUPLICATES_MOVED/resources/views' => 'moved', '_BACKUP_OLD_netgescon-laravel_INACTIVE/resources/views' => 'backup_laravel', '_BACKUP_OLD_netgescon_INACTIVE/vendor/laravel/breeze/stubs' => 'backup_breeze' ]; $viewFiles = []; foreach ($directories as $dir => $type) { if (!File::exists(base_path($dir))) continue; $files = File::allFiles(base_path($dir)); foreach ($files as $file) { if ($file->getExtension() === 'php') { $filename = $file->getFilename(); if (!isset($viewFiles[$filename])) { $viewFiles[$filename] = []; } $viewFiles[$filename][] = [ 'path' => $file->getPathname(), 'directory' => $dir, 'type' => $type, 'size' => $file->getSize(), 'modified' => $file->getMTime(), 'readable_date' => date('d/m/Y H:i:s', $file->getMTime()) ]; } } } foreach ($viewFiles as $filename => $files) { if (count($files) > 1) { $this->duplicates[$filename] = [ 'count' => count($files), 'files' => $files, 'active_file' => $this->findActiveFile($files), 'risk_level' => $this->calculateRiskLevel($files) ]; } } return $this->duplicates; } /** * Verifica route e view mancanti */ public function verifyRoutesAndViews(): array { $routes = Route::getRoutes(); $missingViews = []; foreach ($routes as $route) { $action = $route->getAction(); if (isset($action['controller'])) { $controller = $action['controller']; $controllerClass = explode('@', $controller)[0]; $controllerPath = $this->getControllerPath($controllerClass); if (File::exists($controllerPath)) { $content = File::get($controllerPath); $viewReferences = $this->extractViewReferences($content); foreach ($viewReferences as $viewName) { if (!$this->viewExists($viewName)) { $missingViews[] = [ 'view' => $viewName, 'controller' => $controller, 'route_uri' => $route->uri(), 'route_name' => $route->getName(), 'methods' => $route->methods() ]; } } } } } $this->missingViews = $missingViews; return $missingViews; } /** * Controlla relationship dei model */ public function checkModelRelationships(): array { $modelPath = app_path('Models'); if (!File::exists($modelPath)) { return []; } $models = File::allFiles($modelPath); $brokenRelationships = []; foreach ($models as $model) { $className = 'App\\Models\\' . $model->getFilenameWithoutExtension(); if (class_exists($className)) { $content = File::get($model->getPathname()); $relationships = $this->extractRelationships($content); foreach ($relationships as $relationship) { $issue = $this->validateRelationship($relationship); if ($issue) { $brokenRelationships[] = array_merge($relationship, [ 'model' => $className, 'issue' => $issue ]); } } } } $this->brokenRelationships = $brokenRelationships; return $brokenRelationships; } /** * Genera statistiche complete del sistema */ public function getSystemReport(): array { return [ 'timestamp' => now()->format('Y-m-d H:i:s'), 'system_info' => $this->systemStats, 'analysis' => [ 'duplicates' => [ 'total_files' => count($this->duplicates), 'high_risk' => count(array_filter($this->duplicates, fn($d) => $d['risk_level'] === 'high')), 'medium_risk' => count(array_filter($this->duplicates, fn($d) => $d['risk_level'] === 'medium')), 'low_risk' => count(array_filter($this->duplicates, fn($d) => $d['risk_level'] === 'low')), 'details' => $this->duplicates ], 'missing_views' => [ 'total' => count($this->missingViews), 'details' => $this->missingViews ], 'broken_relationships' => [ 'total' => count($this->brokenRelationships), 'details' => $this->brokenRelationships ] ], 'recommendations' => $this->generateRecommendations() ]; } /** * Trova il file attivo tra i duplicati */ protected function findActiveFile(array $files): ?array { // Priorità: 1. resources/views (attivo), 2. Più recente $activeFiles = array_filter($files, fn($f) => $f['type'] === 'active'); if (!empty($activeFiles)) { return array_reduce($activeFiles, function ($latest, $file) { return $latest === null || $file['modified'] > $latest['modified'] ? $file : $latest; }); } return array_reduce($files, function ($latest, $file) { return $latest === null || $file['modified'] > $latest['modified'] ? $file : $latest; }); } /** * Calcola il livello di rischio dei duplicati */ protected function calculateRiskLevel(array $files): string { $activeFiles = count(array_filter($files, fn($f) => $f['type'] === 'active')); $totalFiles = count($files); if ($activeFiles > 1) return 'high'; if ($totalFiles > 5) return 'medium'; return 'low'; } /** * Ottiene il path del controller */ protected function getControllerPath(string $controllerClass): string { $relativePath = str_replace('App\\Http\\Controllers\\', '', $controllerClass); return app_path('Http/Controllers/' . str_replace('\\', '/', $relativePath) . '.php'); } /** * Estrae i riferimenti alle view dal codice del controller */ protected function extractViewReferences(string $content): array { preg_match_all('/view\([\'"]([^\'"]+)[\'"]\)/', $content, $matches); return $matches[1] ?? []; } /** * Controlla se una view esiste */ protected function viewExists(string $viewName): bool { $viewPath = resource_path('views/' . str_replace('.', '/', $viewName) . '.blade.php'); return File::exists($viewPath); } /** * Estrae i relationship dai model */ protected function extractRelationships(string $content): array { preg_match_all('/public function (\w+)\(\).*?return \$this->(\w+)\(([^)]+)\)/', $content, $matches, PREG_SET_ORDER); $relationships = []; foreach ($matches as $match) { $relationships[] = [ 'method' => $match[1], 'type' => $match[2], 'related' => trim($match[3], '"\'') ]; } return $relationships; } /** * Valida un relationship */ protected function validateRelationship(array $relationship): ?string { $relatedModel = $relationship['related']; if (strpos($relatedModel, '::class') === false) { $relatedClassName = 'App\\Models\\' . $relatedModel; if (!class_exists($relatedClassName)) { return 'Model non trovato: ' . $relatedClassName; } } return null; } /** * Raccoglie statistiche di sistema */ protected function collectSystemStats(): array { return [ 'php_version' => PHP_VERSION, 'laravel_version' => app()->version(), 'environment' => app()->environment(), 'debug_mode' => config('app.debug'), 'storage_writable' => is_writable(storage_path()), 'views_count' => $this->countFiles(resource_path('views'), 'blade.php'), 'controllers_count' => $this->countFiles(app_path('Http/Controllers')), 'models_count' => $this->countFiles(app_path('Models')), 'routes_count' => Route::getRoutes()->count(), 'duplicates_folder_size' => $this->getFolderSize(base_path('_DUPLICATES_MOVED')), 'last_debug_scan' => $this->getLastDebugScan(), ]; } /** * Conta i file in una directory */ protected function countFiles(string $path, string $extension = 'php'): int { if (!File::exists($path)) return 0; $files = File::allFiles($path); if ($extension === 'blade.php') { return count(array_filter($files, fn($file) => str_ends_with($file->getFilename(), '.blade.php'))); } return count(array_filter($files, fn($file) => $file->getExtension() === 'php')); } /** * Calcola la dimensione di una cartella */ protected function getFolderSize(string $path): string { if (!File::exists($path)) return '0 B'; $size = 0; foreach (File::allFiles($path) as $file) { $size += $file->getSize(); } return $this->formatBytes($size); } /** * Formatta i byte in formato leggibile */ protected function formatBytes(int $size, int $precision = 2): string { $units = ['B', 'KB', 'MB', 'GB']; $base = log($size, 1024); return round(pow(1024, $base - floor($base)), $precision) . ' ' . $units[floor($base)]; } /** * Genera raccomandazioni basate sull'analisi */ protected function generateRecommendations(): array { $recommendations = []; if (count($this->duplicates) > 0) { $highRisk = count(array_filter($this->duplicates, fn($d) => $d['risk_level'] === 'high')); if ($highRisk > 0) { $recommendations[] = [ 'type' => 'critical', 'message' => "Trovati {$highRisk} file duplicati ad alto rischio. Pulizia urgente necessaria.", 'action' => 'Esegui pulizia duplicati' ]; } } if (count($this->missingViews) > 0) { $recommendations[] = [ 'type' => 'error', 'message' => count($this->missingViews) . " view mancanti trovate. Il sistema potrebbe generare errori.", 'action' => 'Crea le view mancanti o rimuovi i riferimenti' ]; } if (count($this->brokenRelationships) > 0) { $recommendations[] = [ 'type' => 'warning', 'message' => count($this->brokenRelationships) . " relationship problematici trovati.", 'action' => 'Controlla e correggi i relationship dei model' ]; } if (empty($recommendations)) { $recommendations[] = [ 'type' => 'success', 'message' => 'Sistema pulito e funzionante!', 'action' => 'Continua il monitoraggio regolare' ]; } return $recommendations; } /** * Ottieni l'ultimo timestamp di scansione debug */ protected function getLastDebugScan(): string { $cacheFile = storage_path('framework/cache/last_debug_scan'); if (file_exists($cacheFile)) { $timestamp = file_get_contents($cacheFile); return date('d/m/Y H:i:s', (int)$timestamp); } return 'Mai eseguita'; } }