392 lines
13 KiB
PHP
Executable File
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';
|
|
}
|
|
}
|