518 lines
13 KiB
Markdown
518 lines
13 KiB
Markdown
# 🛠️ MANUALE TECNICO NETGESCON - RISOLUZIONE PROBLEMI E BEST PRACTICES
|
||
|
||
**Data Aggiornamento:** 21 Luglio 2025
|
||
**Versione:** 2.1.0
|
||
**Autore:** GitHub Copilot + Team NetGescon
|
||
|
||
## 📋 INDICE RAPIDO
|
||
|
||
1. [Problemi Risolti Oggi](#problemi-risolti-oggi)
|
||
2. [Errori Comuni e Soluzioni](#errori-comuni-e-soluzioni)
|
||
3. [Best Practices Blade Templates](#best-practices-blade-templates)
|
||
4. [Sistema Tab Unificato](#sistema-tab-unificato)
|
||
5. [Gestione Relazioni Database](#gestione-relazioni-database)
|
||
6. [Debug e Testing](#debug-e-testing)
|
||
7. [Checklist Pre-Deploy](#checklist-pre-deploy)
|
||
|
||
---
|
||
|
||
## ❌ PROBLEMI RISOLTI OGGI
|
||
|
||
### 1. **Errore Sintassi PHP - Carattere Unicode**
|
||
```
|
||
ERRORE: syntax error, unexpected identifier "×", expecting ")"
|
||
FILE: resources/views/admin/stabili/show.blade.php :169
|
||
```
|
||
|
||
**CAUSA:** Uso di carattere moltiplicazione Unicode `×` invece dell'operatore PHP `*`
|
||
|
||
**SOLUZIONE:**
|
||
```php
|
||
// ❌ ERRATO
|
||
{{ ($palazzina->numero_scale ?? 1) × ($palazzina->numero_piani ?? 3) }}
|
||
|
||
// ✅ CORRETTO
|
||
{{ ($palazzina->numero_scale ?? 1) * ($palazzina->numero_piani ?? 3) }}
|
||
```
|
||
|
||
**PREVENZIONE:** Usare sempre operatori PHP standard, non caratteri speciali Unicode
|
||
|
||
### 2. **Errore Relazioni Null**
|
||
```
|
||
ERRORE: Call to a member function count() on null
|
||
FILE: resources/views/admin/stabili/show.blade.php :121
|
||
```
|
||
|
||
**CAUSA:** Chiamata metodi su relazioni non caricate o null
|
||
|
||
**SOLUZIONE:**
|
||
```php
|
||
// ❌ ERRATO - Può causare errore se relazione è null
|
||
{{ $stabile->palazzine->count() }}
|
||
|
||
// ✅ CORRETTO - Usa nullsafe operator
|
||
{{ $stabile->palazzine?->count() ?? 0 }}
|
||
|
||
// ✅ ALTERNATIVA - Verifica esistenza
|
||
{{ ($stabile->palazzine && $stabile->palazzine->count()) ? $stabile->palazzine->count() : 0 }}
|
||
```
|
||
|
||
**PREVENZIONE:** Usare sempre `?->` per relazioni che potrebbero essere null
|
||
|
||
### 3. **Rotte Non Definite**
|
||
```
|
||
ERRORE: Route [admin.unita_immobiliari.index] not defined
|
||
FILE: resources/views/admin/stabili/tabs/dati-generali.blade.php :214
|
||
```
|
||
|
||
**CAUSA:** Riferimento a rotte non esistenti nel sistema di routing
|
||
|
||
**SOLUZIONE:**
|
||
```php
|
||
// ✅ Verifica esistenza rotta prima di usarla
|
||
@if(Route::has('admin.unita_immobiliari.index'))
|
||
<a href="{{ route('admin.unita_immobiliari.index') }}">
|
||
@else
|
||
<a href="#" onclick="alert('Funzionalità in sviluppo')">
|
||
@endif
|
||
```
|
||
|
||
### 4. **Metodi Controller Mancanti**
|
||
```
|
||
ERRORE: Method App\Http\Controllers\Admin\StabileController::authorize does not exist
|
||
FILE: app/Http/Controllers/Admin/StabileController.php :76
|
||
```
|
||
|
||
**CAUSA:** Chiamata a metodi non implementati nel controller
|
||
|
||
**SOLUZIONE:** Implementare il metodo o rimuovere la chiamata
|
||
|
||
---
|
||
|
||
## 🔧 ERRORI COMUNI E SOLUZIONI
|
||
|
||
### **A. Errori Blade Template**
|
||
|
||
#### 1. Variabili Non Definite
|
||
```php
|
||
// ❌ ERRATO
|
||
{{ $variabile->proprieta }}
|
||
|
||
// ✅ CORRETTO
|
||
{{ $variabile->proprieta ?? 'Valore Default' }}
|
||
{{ isset($variabile) ? $variabile->proprieta : 'Default' }}
|
||
```
|
||
|
||
#### 2. Include Files Mancanti
|
||
```php
|
||
// ❌ ERRATO
|
||
@include('admin.stabili.tabs.non-esistente')
|
||
|
||
// ✅ CORRETTO - Verifica esistenza
|
||
@if(view()->exists('admin.stabili.tabs.tab-name'))
|
||
@include('admin.stabili.tabs.tab-name')
|
||
@else
|
||
<p>Contenuto in sviluppo</p>
|
||
@endif
|
||
```
|
||
|
||
#### 3. Loop su Collezioni Null
|
||
```php
|
||
// ❌ ERRATO
|
||
@foreach($stabile->palazzine as $palazzina)
|
||
|
||
// ✅ CORRETTO
|
||
@forelse($stabile->palazzine ?? [] as $palazzina)
|
||
// Contenuto
|
||
@empty
|
||
<p>Nessun elemento trovato</p>
|
||
@endforelse
|
||
```
|
||
|
||
### **B. Errori JavaScript**
|
||
|
||
#### 1. Selezione Elementi DOM
|
||
```javascript
|
||
// ❌ ERRATO - Può essere null
|
||
const element = document.getElementById('tab-content');
|
||
element.classList.add('active');
|
||
|
||
// ✅ CORRETTO - Verifica esistenza
|
||
const element = document.getElementById('tab-content');
|
||
if (element) {
|
||
element.classList.add('active');
|
||
}
|
||
```
|
||
|
||
#### 2. Event Listeners
|
||
```javascript
|
||
// ✅ BEST PRACTICE - Usa delegazione eventi
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Inizializzazione sicura
|
||
const buttons = document.querySelectorAll('.netgescon-tab-btn');
|
||
buttons.forEach(button => {
|
||
if (button) {
|
||
button.addEventListener('click', handleTabClick);
|
||
}
|
||
});
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 BEST PRACTICES BLADE TEMPLATES
|
||
|
||
### **1. Struttura Standardizzata Tab**
|
||
|
||
```php
|
||
<!-- Tab Navigation -->
|
||
<nav class="-mb-px flex space-x-8" aria-label="Tabs" role="tablist">
|
||
<button class="netgescon-tab-btn active"
|
||
data-tab="nome-tab"
|
||
type="button"
|
||
role="tab">
|
||
<i class="fas fa-icon mr-2"></i>
|
||
Nome Tab
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- Tab Content -->
|
||
<div id="nome-tab" class="netgescon-tab-content active">
|
||
@include('path.to.tab-content', ['parametri' => $variabili])
|
||
</div>
|
||
```
|
||
|
||
### **2. Gestione Sicura Dati**
|
||
|
||
```php
|
||
<!-- Sempre usare nullsafe e default values -->
|
||
<p>{{ $oggetto?->proprieta ?? 'N/D' }}</p>
|
||
|
||
<!-- Per collezioni -->
|
||
<div>Totale: {{ $oggetto?->collezione?->count() ?? 0 }}</div>
|
||
|
||
<!-- Per date -->
|
||
<time>{{ $oggetto?->created_at?->format('d/m/Y') ?? 'N/D' }}</time>
|
||
```
|
||
|
||
### **3. Classi CSS Standardizzate**
|
||
|
||
```css
|
||
/* Mantenere consistenza classi */
|
||
.netgescon-tab-btn { /* Stili tab button */ }
|
||
.netgescon-tab-content { /* Stili contenuto tab */ }
|
||
.netgescon-btn { /* Stili bottoni */ }
|
||
.netgescon-card { /* Stili card */ }
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 SISTEMA TAB UNIFICATO
|
||
|
||
### **Implementazione JavaScript Standard**
|
||
|
||
```javascript
|
||
// File: resources/js/netgescon-tabs.js
|
||
class NetGesconTabs {
|
||
constructor() {
|
||
this.init();
|
||
}
|
||
|
||
init() {
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
this.bindEvents();
|
||
});
|
||
}
|
||
|
||
bindEvents() {
|
||
const tabButtons = document.querySelectorAll('.netgescon-tab-btn');
|
||
tabButtons.forEach(button => {
|
||
button.addEventListener('click', (e) => this.handleTabClick(e));
|
||
});
|
||
}
|
||
|
||
handleTabClick(event) {
|
||
const button = event.currentTarget;
|
||
const targetTab = button.dataset.tab;
|
||
|
||
if (!targetTab) return;
|
||
|
||
// Reset tutti i tab
|
||
this.resetAllTabs();
|
||
|
||
// Attiva tab selezionato
|
||
this.activateTab(button, targetTab);
|
||
|
||
// Carica contenuto dinamico se necessario
|
||
this.loadDynamicContent(targetTab);
|
||
}
|
||
|
||
resetAllTabs() {
|
||
document.querySelectorAll('.netgescon-tab-btn').forEach(btn => {
|
||
btn.classList.remove('active');
|
||
});
|
||
|
||
document.querySelectorAll('.netgescon-tab-content').forEach(content => {
|
||
content.classList.remove('active');
|
||
content.classList.add('hidden');
|
||
});
|
||
}
|
||
|
||
activateTab(button, targetTab) {
|
||
button.classList.add('active');
|
||
|
||
const targetContent = document.getElementById(targetTab);
|
||
if (targetContent) {
|
||
targetContent.classList.add('active');
|
||
targetContent.classList.remove('hidden');
|
||
}
|
||
}
|
||
|
||
loadDynamicContent(tabName) {
|
||
// Implementazione specifica per tab che richiedono caricamento dinamico
|
||
const dynamicTabs = ['unita-immobiliari', 'documenti-collegati'];
|
||
|
||
if (dynamicTabs.includes(tabName)) {
|
||
const container = document.getElementById(`${tabName}-content`);
|
||
if (container && !container.dataset.loaded) {
|
||
this.fetchTabContent(tabName, container);
|
||
}
|
||
}
|
||
}
|
||
|
||
async fetchTabContent(tabName, container) {
|
||
try {
|
||
const stabileId = window.stabileId || container.dataset.stabileId;
|
||
const response = await fetch(`/admin/stabili/${stabileId}/${tabName}`, {
|
||
headers: {
|
||
'X-Requested-With': 'XMLHttpRequest',
|
||
'Accept': 'application/json',
|
||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||
}
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
container.innerHTML = data.html;
|
||
container.dataset.loaded = 'true';
|
||
} else {
|
||
this.showError(container, 'Errore nel caricamento dei dati');
|
||
}
|
||
} catch (error) {
|
||
console.error('Errore caricamento tab:', error);
|
||
this.showError(container, 'Errore di connessione');
|
||
}
|
||
}
|
||
|
||
showError(container, message) {
|
||
container.innerHTML = `
|
||
<div class="text-center py-8">
|
||
<div class="text-red-600">
|
||
<i class="fas fa-exclamation-triangle text-2xl mb-2"></i>
|
||
<p>${message}</p>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Inizializza sistema tab
|
||
new NetGesconTabs();
|
||
```
|
||
|
||
---
|
||
|
||
## 🗄️ GESTIONE RELAZIONI DATABASE
|
||
|
||
### **Caricamento Sicuro Relazioni**
|
||
|
||
```php
|
||
// Nel Controller
|
||
public function show(Stabile $stabile)
|
||
{
|
||
// Carica relazioni in modo esplicito
|
||
$stabile->load([
|
||
'palazzine' => function($query) {
|
||
$query->orderBy('codice');
|
||
},
|
||
'unitaImmobiliari',
|
||
'datiBancari.contatto',
|
||
'tabelleMillesimali' => function($query) {
|
||
$query->orderBy('tipologia')->orderBy('anno', 'desc');
|
||
},
|
||
'documenti' => function($query) {
|
||
$query->orderBy('created_at', 'desc');
|
||
}
|
||
]);
|
||
|
||
return view('admin.stabili.show', compact('stabile'));
|
||
}
|
||
```
|
||
|
||
### **Validazione Dati Blade**
|
||
|
||
```php
|
||
<!-- Template sicuro per relazioni -->
|
||
@if($stabile && $stabile->relationLoaded('palazzine'))
|
||
@forelse($stabile->palazzine as $palazzina)
|
||
<!-- Contenuto -->
|
||
@empty
|
||
<!-- Messaggio vuoto -->
|
||
@endforelse
|
||
@else
|
||
<!-- Loading o messaggio alternativo -->
|
||
@endif
|
||
```
|
||
|
||
---
|
||
|
||
## 🐛 DEBUG E TESTING
|
||
|
||
### **1. Debug Veloce**
|
||
|
||
```php
|
||
// In Blade template - Solo per sviluppo
|
||
@if(config('app.debug'))
|
||
<div class="bg-yellow-100 p-2 text-xs">
|
||
Debug: {{ json_encode($stabile->palazzine?->count()) }}
|
||
</div>
|
||
@endif
|
||
```
|
||
|
||
### **2. Log Errori**
|
||
|
||
```php
|
||
// Nel Controller
|
||
try {
|
||
$data = $this->processData();
|
||
} catch (\Exception $e) {
|
||
\Log::error('Errore processamento dati: ' . $e->getMessage(), [
|
||
'file' => $e->getFile(),
|
||
'line' => $e->getLine(),
|
||
'stabile_id' => $stabile->id ?? null
|
||
]);
|
||
|
||
return back()->with('error', 'Errore nel caricamento dei dati');
|
||
}
|
||
```
|
||
|
||
### **3. Comandi Artisan Utili**
|
||
|
||
```bash
|
||
# Pulizia cache
|
||
php artisan config:clear
|
||
php artisan view:clear
|
||
php artisan route:clear
|
||
|
||
# Debug rotte
|
||
php artisan route:list | grep stabili
|
||
|
||
# Test sintassi PHP
|
||
php -l resources/views/admin/stabili/show.blade.php
|
||
|
||
# Verifica database
|
||
php artisan migrate:status
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ CHECKLIST PRE-DEPLOY
|
||
|
||
### **File da Controllare Sempre**
|
||
|
||
- [ ] **Sintassi PHP**: `find . -name "*.php" -exec php -l {} \;`
|
||
- [ ] **Blade Templates**: Verificare tutti gli `@include` esistono
|
||
- [ ] **Relazioni Database**: Controllare `?->` per relazioni nullable
|
||
- [ ] **Rotte**: Verificare tutte le `route()` sono definite
|
||
- [ ] **JavaScript**: Controllare selezione DOM e event listener
|
||
- [ ] **CSS**: Verificare classi standardizzate
|
||
- [ ] **Immagini/Asset**: Controllare percorsi file
|
||
|
||
### **Test Funzionalità**
|
||
|
||
- [ ] **Tab Navigation**: Tutti i tab si aprono correttamente
|
||
- [ ] **Form Submission**: Creazione e modifica stabili
|
||
- [ ] **AJAX Loading**: Caricamento dinamico contenuti
|
||
- [ ] **Error Handling**: Gestione errori 404/500
|
||
- [ ] **Mobile Responsive**: Test su dispositivi mobili
|
||
|
||
### **Performance**
|
||
|
||
- [ ] **Query Optimization**: Eager loading relazioni
|
||
- [ ] **Cache**: Configurazione cache attiva
|
||
- [ ] **Assets**: Minificazione CSS/JS
|
||
- [ ] **Database**: Indici su colonne utilizzate
|
||
|
||
---
|
||
|
||
## 📝 TEMPLATE COMMENTI CODICE
|
||
|
||
### **Blade Templates**
|
||
|
||
```php
|
||
{{--
|
||
NETGESCON TAB: [Nome Tab]
|
||
Descrizione: [Descrizione funzionalità]
|
||
Dipendenze: [Liste dipendenze]
|
||
Autore: GitHub Copilot
|
||
Data: 21/07/2025
|
||
--}}
|
||
|
||
{{-- Header Tab con controlli --}}
|
||
<div class="flex justify-between items-center">
|
||
{{-- Titolo e descrizione --}}
|
||
<div>
|
||
<h4 class="text-xl font-semibold text-gray-900">
|
||
<i class="fas fa-icon mr-2 text-color"></i>
|
||
Titolo Tab
|
||
</h4>
|
||
<p class="text-sm text-gray-600 mt-1">
|
||
Descrizione funzionalità tab
|
||
</p>
|
||
</div>
|
||
|
||
{{-- Pulsanti azione --}}
|
||
<div class="space-x-2">
|
||
<!-- Pulsanti azione -->
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
### **JavaScript**
|
||
|
||
```javascript
|
||
/**
|
||
* NETGESCON: [Nome Funzione]
|
||
* Descrizione: [Descrizione funzionalità]
|
||
*
|
||
* @param {type} parametro - Descrizione parametro
|
||
* @returns {type} Descrizione return
|
||
*
|
||
* @author GitHub Copilot
|
||
* @date 21/07/2025
|
||
* @version 1.0.0
|
||
*/
|
||
function nomeFunction(parametro) {
|
||
// Implementazione
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 PROSSIMI PASSI
|
||
|
||
1. **Implementare Sistema Seeder** per dati demo persistenti
|
||
2. **Creare Test Automatici** per prevenire regressioni
|
||
3. **Ottimizzare Performance** con eager loading
|
||
4. **Documentare API** per integrazioni future
|
||
5. **Setup CI/CD** per deploy automatici
|
||
|
||
---
|
||
|
||
**📞 SUPPORTO TECNICO**
|
||
Per problemi urgenti, consultare sempre questo manuale prima di procedere con modifiche al codice.
|
||
|
||
**🔄 AGGIORNAMENTI**
|
||
Questo manuale verrà aggiornato ad ogni sessione di sviluppo con nuovi problemi risolti e best practices.
|