17 KiB
17 KiB
📊 CONTROLLER STANDARD E DATABASE
Pattern controller per moduli NetGescon
🎯 CONTROLLER TEMPLATE BASE
File: app/Http/Controllers/Admin/{Modulo}Controller.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:
// 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:
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:
// 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:
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
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:
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:
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:
// 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:
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