595 lines
17 KiB
Markdown
595 lines
17 KiB
Markdown
# 📊 CONTROLLER STANDARD E DATABASE
|
|
## Pattern controller per moduli NetGescon
|
|
|
|
---
|
|
|
|
## 🎯 **CONTROLLER TEMPLATE BASE**
|
|
|
|
### **File**: `app/Http/Controllers/Admin/{Modulo}Controller.php`
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class ModuloController extends Controller
|
|
{
|
|
/**
|
|
* Display main listing with stats and menu
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
// Calcola statistiche per cards
|
|
$stats = $this->calculateStats();
|
|
|
|
// Dati principale per listing con filtri
|
|
$items = $this->getMainData($request);
|
|
|
|
// Menu configuration
|
|
$menuTabs = $this->getMenuTabs();
|
|
|
|
return view('admin.modulo.index', compact('stats', 'items', 'menuTabs'));
|
|
}
|
|
|
|
/**
|
|
* Show detail with sub-tabs
|
|
*/
|
|
public function show($id)
|
|
{
|
|
$item = $this->findItem($id);
|
|
$detailTabs = $this->getDetailTabs($item);
|
|
$tabContent = $this->getTabContent($item);
|
|
|
|
return view('admin.modulo.show', compact('item', 'detailTabs', 'tabContent'));
|
|
}
|
|
|
|
/**
|
|
* Show create form
|
|
*/
|
|
public function create()
|
|
{
|
|
$formData = $this->getFormData();
|
|
return view('admin.modulo.create', compact('formData'));
|
|
}
|
|
|
|
/**
|
|
* Store new item
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$validatedData = $request->validate($this->getValidationRules());
|
|
|
|
// Add audit fields
|
|
$validatedData['created_by'] = Auth::id();
|
|
$validatedData['amministratore_id'] = Auth::user()->amministratore_id;
|
|
|
|
$item = DB::table('modulo_table')->insertGetId($validatedData);
|
|
|
|
return redirect()->route('admin.modulo.index')
|
|
->with('success', 'Item creato con successo');
|
|
}
|
|
|
|
/**
|
|
* Show edit form
|
|
*/
|
|
public function edit($id)
|
|
{
|
|
$item = $this->findItem($id);
|
|
$formData = $this->getFormData();
|
|
|
|
return view('admin.modulo.edit', compact('item', 'formData'));
|
|
}
|
|
|
|
/**
|
|
* Update item
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
$validatedData = $request->validate($this->getValidationRules());
|
|
|
|
// Add audit fields
|
|
$validatedData['updated_by'] = Auth::id();
|
|
$validatedData['updated_at'] = now();
|
|
|
|
DB::table('modulo_table')
|
|
->where('id', $id)
|
|
->where('amministratore_id', Auth::user()->amministratore_id)
|
|
->update($validatedData);
|
|
|
|
return redirect()->route('admin.modulo.index')
|
|
->with('success', 'Item aggiornato con successo');
|
|
}
|
|
|
|
/**
|
|
* Delete item
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
DB::table('modulo_table')
|
|
->where('id', $id)
|
|
->where('amministratore_id', Auth::user()->amministratore_id)
|
|
->delete();
|
|
|
|
return redirect()->route('admin.modulo.index')
|
|
->with('success', 'Item eliminato con successo');
|
|
}
|
|
|
|
/**
|
|
* Reports page
|
|
*/
|
|
public function reports()
|
|
{
|
|
$reportData = $this->getReportData();
|
|
return view('admin.modulo.reports', compact('reportData'));
|
|
}
|
|
|
|
/**
|
|
* Configuration page
|
|
*/
|
|
public function config()
|
|
{
|
|
$configData = $this->getConfigData();
|
|
return view('admin.modulo.config', compact('configData'));
|
|
}
|
|
|
|
// ============ PRIVATE METHODS ============
|
|
|
|
/**
|
|
* Calculate statistics for cards
|
|
*/
|
|
private function calculateStats()
|
|
{
|
|
$baseQuery = DB::table('modulo_table')
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('amministratore_id', Auth::user()->amministratore_id);
|
|
});
|
|
|
|
return [
|
|
'totale' => (clone $baseQuery)->count(),
|
|
'attivi' => (clone $baseQuery)->where('stato', 'attivo')->count(),
|
|
'pending' => (clone $baseQuery)->where('stato', 'pending')->count(),
|
|
'questo_mese' => (clone $baseQuery)
|
|
->whereMonth('created_at', now()->month)
|
|
->whereYear('created_at', now()->year)
|
|
->count(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get main data with relations and filters
|
|
*/
|
|
private function getMainData(Request $request)
|
|
{
|
|
$query = DB::table('modulo_table')
|
|
->leftJoin('stabili', 'modulo_table.stabile_id', '=', 'stabili.id')
|
|
->leftJoin('gestioni', 'modulo_table.gestione_id', '=', 'gestioni.id_gestione')
|
|
->select([
|
|
'modulo_table.*',
|
|
'stabili.denominazione as stabile_nome',
|
|
'gestioni.anno_gestione',
|
|
'gestioni.tipo_gestione'
|
|
])
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('stabili.amministratore_id', Auth::user()->amministratore_id);
|
|
});
|
|
|
|
// Apply filters
|
|
if ($request->filled('search')) {
|
|
$query->where(function($q) use ($request) {
|
|
$q->where('modulo_table.denominazione', 'like', '%' . $request->search . '%')
|
|
->orWhere('stabili.denominazione', 'like', '%' . $request->search . '%');
|
|
});
|
|
}
|
|
|
|
if ($request->filled('stato')) {
|
|
$query->where('modulo_table.stato', $request->stato);
|
|
}
|
|
|
|
if ($request->filled('stabile_id')) {
|
|
$query->where('modulo_table.stabile_id', $request->stabile_id);
|
|
}
|
|
|
|
return $query->orderBy('modulo_table.created_at', 'desc')->paginate(20);
|
|
}
|
|
|
|
/**
|
|
* Find single item with security check
|
|
*/
|
|
private function findItem($id)
|
|
{
|
|
$item = DB::table('modulo_table')
|
|
->leftJoin('stabili', 'modulo_table.stabile_id', '=', 'stabili.id')
|
|
->select([
|
|
'modulo_table.*',
|
|
'stabili.denominazione as stabile_nome'
|
|
])
|
|
->where('modulo_table.id', $id)
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('stabili.amministratore_id', Auth::user()->amministratore_id);
|
|
})
|
|
->first();
|
|
|
|
if (!$item) {
|
|
abort(404, 'Item non trovato');
|
|
}
|
|
|
|
return $item;
|
|
}
|
|
|
|
/**
|
|
* Get menu tabs configuration
|
|
*/
|
|
private function getMenuTabs()
|
|
{
|
|
return [
|
|
[
|
|
'label' => 'Lista',
|
|
'route' => 'admin.modulo.index',
|
|
'icon' => 'fas fa-list',
|
|
'active' => request()->routeIs('admin.modulo.index')
|
|
],
|
|
[
|
|
'label' => 'Nuovo',
|
|
'route' => 'admin.modulo.create',
|
|
'icon' => 'fas fa-plus',
|
|
'active' => request()->routeIs('admin.modulo.create')
|
|
],
|
|
[
|
|
'label' => 'Reports',
|
|
'route' => 'admin.modulo.reports',
|
|
'icon' => 'fas fa-chart-bar',
|
|
'active' => request()->routeIs('admin.modulo.reports')
|
|
],
|
|
[
|
|
'label' => 'Config',
|
|
'route' => 'admin.modulo.config',
|
|
'icon' => 'fas fa-cog',
|
|
'active' => request()->routeIs('admin.modulo.config')
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get detail tabs for show page
|
|
*/
|
|
private function getDetailTabs($item)
|
|
{
|
|
return [
|
|
[
|
|
'id' => 'dati-generali',
|
|
'label' => 'Dati Generali',
|
|
'icon' => 'fas fa-info-circle',
|
|
'active' => true
|
|
],
|
|
[
|
|
'id' => 'dettagli',
|
|
'label' => 'Dettagli',
|
|
'icon' => 'fas fa-list',
|
|
'active' => false
|
|
],
|
|
[
|
|
'id' => 'documenti',
|
|
'label' => 'Documenti',
|
|
'icon' => 'fas fa-file',
|
|
'active' => false
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get validation rules
|
|
*/
|
|
private function getValidationRules()
|
|
{
|
|
return [
|
|
'denominazione' => 'required|string|max:255',
|
|
'descrizione' => 'nullable|string',
|
|
'stato' => 'required|in:attivo,inattivo,sospeso',
|
|
'stabile_id' => 'nullable|exists:stabili,id',
|
|
'gestione_id' => 'nullable|exists:gestioni,id_gestione',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get form data for create/edit
|
|
*/
|
|
private function getFormData()
|
|
{
|
|
return [
|
|
'stabili' => DB::table('stabili')
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('amministratore_id', Auth::user()->amministratore_id);
|
|
})
|
|
->select('id', 'denominazione')
|
|
->orderBy('denominazione')
|
|
->get(),
|
|
'gestioni' => DB::table('gestioni')
|
|
->join('stabili', 'gestioni.stabile_id', '=', 'stabili.id')
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('stabili.amministratore_id', Auth::user()->amministratore_id);
|
|
})
|
|
->select('gestioni.id_gestione', 'gestioni.anno_gestione', 'stabili.denominazione as stabile_nome')
|
|
->orderBy('gestioni.anno_gestione', 'desc')
|
|
->get(),
|
|
'stati' => [
|
|
'attivo' => 'Attivo',
|
|
'inattivo' => 'Inattivo',
|
|
'sospeso' => 'Sospeso'
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get tab content for show page
|
|
*/
|
|
private function getTabContent($item)
|
|
{
|
|
return [
|
|
'dati_generali' => $item,
|
|
'dettagli' => $this->getDetailData($item->id),
|
|
'documenti' => $this->getDocumenti($item->id),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get additional detail data
|
|
*/
|
|
private function getDetailData($itemId)
|
|
{
|
|
// Get related data for details tab
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Get documents for item
|
|
*/
|
|
private function getDocumenti($itemId)
|
|
{
|
|
// Get documents related to this item
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Get report data
|
|
*/
|
|
private function getReportData()
|
|
{
|
|
// Generate report data
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Get configuration data
|
|
*/
|
|
private function getConfigData()
|
|
{
|
|
// Get configuration settings
|
|
return [];
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 **SECURITY PATTERNS**
|
|
|
|
### **Filtro Amministratore Obbligatorio**:
|
|
```php
|
|
// SEMPRE filtrare per amministratore
|
|
private function getBaseQuery()
|
|
{
|
|
return DB::table('modulo_table')
|
|
->when(Auth::user()->amministratore_id, function($query) {
|
|
return $query->where('amministratore_id', Auth::user()->amministratore_id);
|
|
});
|
|
}
|
|
|
|
// Per super admin senza filtro
|
|
private function isSuperAdmin()
|
|
{
|
|
return Auth::user()->is_super_admin ?? false;
|
|
}
|
|
```
|
|
|
|
### **Validation con Security**:
|
|
```php
|
|
private function getValidationRules($id = null)
|
|
{
|
|
return [
|
|
'denominazione' => 'required|string|max:255',
|
|
'stabile_id' => [
|
|
'nullable',
|
|
'exists:stabili,id',
|
|
// Verifica che lo stabile appartenga all'amministratore
|
|
function ($attribute, $value, $fail) {
|
|
if ($value && Auth::user()->amministratore_id) {
|
|
$exists = DB::table('stabili')
|
|
->where('id', $value)
|
|
->where('amministratore_id', Auth::user()->amministratore_id)
|
|
->exists();
|
|
if (!$exists) {
|
|
$fail('Stabile non autorizzato.');
|
|
}
|
|
}
|
|
},
|
|
],
|
|
];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 **DATABASE QUERY PATTERNS**
|
|
|
|
### **Query con Relazioni Standard**:
|
|
```php
|
|
// Pattern base per listing
|
|
private function getItemsWithRelations()
|
|
{
|
|
return DB::table('modulo_table as m')
|
|
->leftJoin('stabili as s', 'm.stabile_id', '=', 's.id')
|
|
->leftJoin('gestioni as g', 'm.gestione_id', '=', 'g.id_gestione')
|
|
->leftJoin('unita_immobiliari as ui', 'm.unita_id', '=', 'ui.id')
|
|
->select([
|
|
'm.*',
|
|
's.denominazione as stabile_nome',
|
|
's.indirizzo as stabile_indirizzo',
|
|
'g.anno_gestione',
|
|
'g.tipo_gestione',
|
|
'ui.denominazione as unita_nome'
|
|
])
|
|
->where('s.amministratore_id', Auth::user()->amministratore_id);
|
|
}
|
|
```
|
|
|
|
### **Stats Query Ottimizzate**:
|
|
```php
|
|
private function calculateAdvancedStats()
|
|
{
|
|
$amministratore_id = Auth::user()->amministratore_id;
|
|
|
|
// Single query con aggregazione
|
|
$stats = DB::table('modulo_table as m')
|
|
->join('stabili as s', 'm.stabile_id', '=', 's.id')
|
|
->where('s.amministratore_id', $amministratore_id)
|
|
->selectRaw('
|
|
COUNT(*) as totale,
|
|
SUM(CASE WHEN m.stato = "attivo" THEN 1 ELSE 0 END) as attivi,
|
|
SUM(CASE WHEN m.stato = "pending" THEN 1 ELSE 0 END) as pending,
|
|
SUM(CASE WHEN MONTH(m.created_at) = MONTH(NOW())
|
|
AND YEAR(m.created_at) = YEAR(NOW()) THEN 1 ELSE 0 END) as questo_mese,
|
|
AVG(m.importo) as importo_medio,
|
|
SUM(m.importo) as importo_totale
|
|
')
|
|
->first();
|
|
|
|
return (array) $stats;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 **ROUTE CONFIGURATION**
|
|
|
|
### **File**: `routes/admin.php`
|
|
```php
|
|
Route::prefix('admin')->name('admin.')->middleware(['auth'])->group(function () {
|
|
|
|
// Standard RESTful routes
|
|
Route::resource('modulo', 'ModuloController');
|
|
|
|
// Additional custom routes
|
|
Route::get('modulo/{id}/detail', ['ModuloController', 'detail'])->name('modulo.detail');
|
|
Route::get('modulo/reports/index', ['ModuloController', 'reports'])->name('modulo.reports');
|
|
Route::get('modulo/config/index', ['ModuloController', 'config'])->name('modulo.config');
|
|
|
|
// AJAX routes
|
|
Route::post('modulo/{id}/toggle-status', ['ModuloController', 'toggleStatus'])->name('modulo.toggle-status');
|
|
Route::get('modulo/search/autocomplete', ['ModuloController', 'autocomplete'])->name('modulo.autocomplete');
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 **EXAMPLE IMPLEMENTATIONS**
|
|
|
|
### **Fornitori Controller**:
|
|
```php
|
|
class FornitoriController extends Controller
|
|
{
|
|
private function calculateStats()
|
|
{
|
|
return [
|
|
'totale_fornitori' => DB::table('fornitori')->count(),
|
|
'attivi' => DB::table('fornitori')->where('stato', 'attivo')->count(),
|
|
'questo_mese' => DB::table('fornitori')
|
|
->whereMonth('created_at', now()->month)->count(),
|
|
'fatture_pending' => DB::table('fatture_fornitori')
|
|
->where('stato', 'pending')->count(),
|
|
];
|
|
}
|
|
|
|
private function getValidationRules()
|
|
{
|
|
return [
|
|
'denominazione' => 'required|string|max:255',
|
|
'partita_iva' => 'required|string|max:20',
|
|
'codice_fiscale' => 'nullable|string|max:16',
|
|
'email' => 'nullable|email',
|
|
'telefono' => 'nullable|string|max:20',
|
|
'indirizzo' => 'nullable|string',
|
|
'categoria' => 'required|in:manutenzione,pulizie,servizi,altro',
|
|
'stato' => 'required|in:attivo,inattivo,sospeso',
|
|
];
|
|
}
|
|
}
|
|
```
|
|
|
|
### **Gestioni Controller**:
|
|
```php
|
|
class GestioniController extends Controller
|
|
{
|
|
private function calculateStats()
|
|
{
|
|
return [
|
|
'totale_gestioni' => DB::table('gestioni')->count(),
|
|
'aperte' => DB::table('gestioni')->where('stato', 'aperta')->count(),
|
|
'da_chiudere' => DB::table('gestioni')
|
|
->where('data_fine', '<=', now())
|
|
->where('stato', 'aperta')->count(),
|
|
'archiviate' => DB::table('gestioni')->where('stato', 'archiviata')->count(),
|
|
];
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ⚡ **PERFORMANCE TIPS**
|
|
|
|
### **Query Optimization**:
|
|
```php
|
|
// Use indexes
|
|
private function addIndexes()
|
|
{
|
|
// In migration
|
|
$table->index(['amministratore_id', 'stato']);
|
|
$table->index(['stabile_id', 'created_at']);
|
|
$table->index('stato');
|
|
}
|
|
|
|
// Limit data
|
|
private function getMainData($request)
|
|
{
|
|
return $this->getBaseQuery()
|
|
->select([
|
|
'm.id', 'm.denominazione', 'm.stato', 'm.created_at',
|
|
's.denominazione as stabile_nome'
|
|
]) // Solo campi necessari
|
|
->paginate(20); // Limitare risultati
|
|
}
|
|
```
|
|
|
|
### **Caching Stats**:
|
|
```php
|
|
private function calculateStats()
|
|
{
|
|
return Cache::remember(
|
|
'stats_modulo_' . Auth::user()->amministratore_id,
|
|
now()->addMinutes(5),
|
|
function () {
|
|
return $this->getStatsFromDatabase();
|
|
}
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
**📖 Prossimo file: `05-css-javascript.md`**
|