netgescon-day0/app/Debug/Services/SystemAnalyzer.php

392 lines
13 KiB
PHP
Executable File

<?php
namespace App\Debug\Services;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Route;
class SystemAnalyzer
{
protected array $duplicates = [];
protected array $missingViews = [];
protected array $brokenRelationships = [];
protected array $systemStats = [];
public function __construct()
{
$this->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';
}
}