++ Primo Caricamento
This commit is contained in:
16
app/Http/Controllers/Controller.php
Normal file
16
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Controller base — tutti i controller del progetto estendono questa classe
|
||||
//
|
||||
// In Laravel 11 il controller base è praticamente vuoto: serve solo come
|
||||
// punto di estensione comune, nel caso in cui in futuro tu voglia aggiungere
|
||||
// metodi o middleware condivisi tra tutti i controller.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
146
app/Http/Controllers/CustomerController.php
Normal file
146
app/Http/Controllers/CustomerController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// CustomerController — CRUD completo per la gestione clienti
|
||||
//
|
||||
// CRUD = Create, Read, Update, Delete
|
||||
//
|
||||
// Laravel usa la convenzione "Resource Controller": 7 metodi standard
|
||||
// che corrispondono alle operazioni CRUD via HTTP:
|
||||
//
|
||||
// index() → GET /customers → lista clienti
|
||||
// create() → GET /customers/create → form nuovo cliente
|
||||
// store() → POST /customers → salva nuovo cliente
|
||||
// show() → GET /customers/{id} → dettaglio cliente
|
||||
// edit() → GET /customers/{id}/edit → form modifica
|
||||
// update() → PUT /customers/{id} → aggiorna cliente
|
||||
// destroy() → DELETE /customers/{id} → elimina cliente
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use App\Models\Customer;
|
||||
use App\Services\SettingService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private SettingService $settings
|
||||
) {}
|
||||
|
||||
// ─── Lista clienti ─────────────────────────────────────────────────────
|
||||
public function index(Request $request)
|
||||
{
|
||||
// Recupera il numero di elementi per pagina dalle impostazioni dinamiche
|
||||
$perPage = $this->settings->get('items_per_page', 15);
|
||||
|
||||
// Costruisce la query con filtri opzionali dalla URL
|
||||
// Es: /customers?search=mario&type=privato&status=attivo
|
||||
$query = Customer::query();
|
||||
|
||||
if ($search = $request->input('search')) {
|
||||
$query->search($search); // Usa lo scope definito nel Model
|
||||
}
|
||||
|
||||
if ($type = $request->input('type')) {
|
||||
$query->byType($type);
|
||||
}
|
||||
|
||||
if ($status = $request->input('status')) {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
// paginate() divide i risultati in pagine e genera automaticamente
|
||||
// i link prev/next, passati alla view come $customers->links()
|
||||
$customers = $query->latest()->paginate($perPage)->withQueryString();
|
||||
|
||||
return view('customers.index', compact('customers'));
|
||||
}
|
||||
|
||||
// ─── Form nuovo cliente ────────────────────────────────────────────────
|
||||
public function create()
|
||||
{
|
||||
return view('customers.create');
|
||||
}
|
||||
|
||||
// ─── Salva nuovo cliente ───────────────────────────────────────────────
|
||||
public function store(Request $request)
|
||||
{
|
||||
// Validazione: se fallisce, Laravel reindirizza automaticamente
|
||||
// al form precedente con gli errori e i valori inseriti.
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:customers,email',
|
||||
'phone' => 'nullable|string|max:50',
|
||||
'city' => 'nullable|string|max:100',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'vat_number' => 'nullable|string|max:20',
|
||||
'fiscal_code' => 'nullable|string|max:20',
|
||||
'type' => 'required|in:privato,azienda',
|
||||
'status' => 'required|in:attivo,inattivo,prospect',
|
||||
'notes' => 'nullable|string',
|
||||
'contract_value' => 'nullable|numeric|min:0',
|
||||
]);
|
||||
|
||||
$customer = Customer::create($validated);
|
||||
|
||||
// redirect() rimanda il browser a un'altra pagina
|
||||
// with('success', ...) aggiunge un messaggio flash (mostrato una volta)
|
||||
return redirect()
|
||||
->route('customers.show', $customer)
|
||||
->with('success', "Cliente \"{$customer->name}\" creato con successo.");
|
||||
}
|
||||
|
||||
// ─── Dettaglio cliente ─────────────────────────────────────────────────
|
||||
// Route Model Binding: Laravel trova automaticamente il Customer dall'URL
|
||||
// Non serve scrivere: $customer = Customer::findOrFail($id);
|
||||
public function show(Customer $customer)
|
||||
{
|
||||
return view('customers.show', compact('customer'));
|
||||
}
|
||||
|
||||
// ─── Form modifica cliente ─────────────────────────────────────────────
|
||||
public function edit(Customer $customer)
|
||||
{
|
||||
return view('customers.edit', compact('customer'));
|
||||
}
|
||||
|
||||
// ─── Aggiorna cliente ─────────────────────────────────────────────────
|
||||
public function update(Request $request, Customer $customer)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
// unique: ignora il record corrente (altrimenti failerebbe sempre)
|
||||
'email' => "required|email|unique:customers,email,{$customer->id}",
|
||||
'phone' => 'nullable|string|max:50',
|
||||
'city' => 'nullable|string|max:100',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'vat_number' => 'nullable|string|max:20',
|
||||
'fiscal_code' => 'nullable|string|max:20',
|
||||
'type' => 'required|in:privato,azienda',
|
||||
'status' => 'required|in:attivo,inattivo,prospect',
|
||||
'notes' => 'nullable|string',
|
||||
'contract_value' => 'nullable|numeric|min:0',
|
||||
]);
|
||||
|
||||
$customer->update($validated);
|
||||
|
||||
return redirect()
|
||||
->route('customers.show', $customer)
|
||||
->with('success', "Cliente \"{$customer->name}\" aggiornato.");
|
||||
}
|
||||
|
||||
// ─── Elimina cliente (soft delete) ────────────────────────────────────
|
||||
// Grazie a SoftDeletes nel Model, il record non viene cancellato:
|
||||
// viene impostato `deleted_at` e non compare più nelle query normali.
|
||||
public function destroy(Customer $customer)
|
||||
{
|
||||
$name = $customer->name;
|
||||
$customer->delete();
|
||||
|
||||
return redirect()
|
||||
->route('customers.index')
|
||||
->with('success', "Cliente \"{$name}\" eliminato.");
|
||||
}
|
||||
}
|
||||
61
app/Http/Controllers/DashboardController.php
Normal file
61
app/Http/Controllers/DashboardController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// DashboardController — gestisce la pagina principale del portale
|
||||
//
|
||||
// Un Controller riceve la richiesta HTTP, recupera i dati necessari
|
||||
// e li passa alla View (template Blade) per la visualizzazione.
|
||||
//
|
||||
// Flusso di una richiesta:
|
||||
// Browser → routes/web.php → Controller → View → risposta HTML
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use App\Models\Customer;
|
||||
use App\Services\SettingService;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
// Dependency Injection: Laravel istanzia SettingService automaticamente
|
||||
public function __construct(
|
||||
private SettingService $settings
|
||||
) {}
|
||||
|
||||
// Corrisponde alla route: GET /
|
||||
public function index()
|
||||
{
|
||||
// Statistiche aggregate sui clienti
|
||||
$stats = [
|
||||
'total' => Customer::count(),
|
||||
'active' => Customer::active()->count(),
|
||||
'prospect' => Customer::where('status', 'prospect')->count(),
|
||||
'inactive' => Customer::where('status', 'inattivo')->count(),
|
||||
// Somma contratti clienti attivi
|
||||
'total_contract_value' => Customer::active()->sum('contract_value'),
|
||||
];
|
||||
|
||||
// Ultimi 5 clienti aggiunti (per "Attività recente")
|
||||
$recentCustomers = Customer::latest()->take(5)->get();
|
||||
|
||||
// Clienti per città (top 5 - per widget grafico)
|
||||
$byCity = Customer::selectRaw('city, count(*) as total')
|
||||
->groupBy('city')
|
||||
->orderByDesc('total')
|
||||
->take(5)
|
||||
->pluck('total', 'city')
|
||||
->toArray();
|
||||
|
||||
// Messaggio di benvenuto dinamico (da impostazioni)
|
||||
$welcomeMessage = $this->settings->get('welcome_message');
|
||||
|
||||
// compact() è una shorthand PHP per creare un array associativo
|
||||
// equivalente a: ['stats' => $stats, 'recentCustomers' => $recentCustomers, ...]
|
||||
return view('dashboard', compact(
|
||||
'stats',
|
||||
'recentCustomers',
|
||||
'byCity',
|
||||
'welcomeMessage'
|
||||
));
|
||||
}
|
||||
}
|
||||
68
app/Http/Controllers/SettingController.php
Normal file
68
app/Http/Controllers/SettingController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// SettingController — pannello impostazioni dinamiche
|
||||
//
|
||||
// Permette all'admin di modificare le impostazioni dell'applicazione
|
||||
// senza toccare il codice o riavviare i container.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use App\Services\SettingService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private SettingService $settings
|
||||
) {}
|
||||
|
||||
// ─── Mostra il pannello impostazioni ──────────────────────────────────
|
||||
public function index()
|
||||
{
|
||||
// Tutte le impostazioni correnti dal servizio
|
||||
$current = $this->settings->all();
|
||||
|
||||
// Configurazione per la UI (label, gruppi, tipi)
|
||||
$config = config('settings');
|
||||
|
||||
return view('settings.index', compact('current', 'config'));
|
||||
}
|
||||
|
||||
// ─── Salva le modifiche ────────────────────────────────────────────────
|
||||
public function update(Request $request)
|
||||
{
|
||||
$types = config('settings.types', []);
|
||||
$defaults = config('settings.defaults', []);
|
||||
|
||||
// Costruisce le regole di validazione dinamicamente
|
||||
// in base ai tipi definiti in config/settings.php
|
||||
$rules = [];
|
||||
foreach ($defaults as $key => $default) {
|
||||
$type = $types[$key] ?? 'string';
|
||||
$rules[$key] = match ($type) {
|
||||
'integer' => 'nullable|integer|min:1',
|
||||
'boolean' => 'nullable|boolean',
|
||||
'string' => 'nullable|string|max:255',
|
||||
'text' => 'nullable|string',
|
||||
default => 'nullable|string',
|
||||
};
|
||||
}
|
||||
|
||||
$validated = $request->validate($rules);
|
||||
|
||||
// I checkbox non inviati dal form hanno valore null → false per i boolean
|
||||
foreach ($types as $key => $type) {
|
||||
if ($type === 'boolean' && ! array_key_exists($key, $validated)) {
|
||||
$validated[$key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->settings->setMany($validated);
|
||||
|
||||
return redirect()
|
||||
->route('settings.index')
|
||||
->with('success', 'Impostazioni salvate con successo. La cache è stata aggiornata.');
|
||||
}
|
||||
}
|
||||
107
app/Models/Customer.php
Normal file
107
app/Models/Customer.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Model Customer — rappresenta un cliente nel database
|
||||
//
|
||||
// In Laravel, un Model è una classe PHP che:
|
||||
// 1. Mappa una tabella del DB (per default: nome classe pluralizzato → "customers")
|
||||
// 2. Permette di leggere, creare, aggiornare e cancellare record (CRUD)
|
||||
// 3. Definisce le relazioni con altri Model
|
||||
//
|
||||
// Usa Eloquent ORM: invece di scrivere SQL raw, usi metodi PHP come:
|
||||
// Customer::all() → SELECT * FROM customers
|
||||
// Customer::find(1) → SELECT * FROM customers WHERE id=1
|
||||
// Customer::where('city', 'Roma') → SELECT * FROM customers WHERE city='Roma'
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Customer extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes; // Soft delete: non cancella davvero dal DB, imposta deleted_at
|
||||
|
||||
// ─── Tabella del database ──────────────────────────────────────────────
|
||||
// Non è necessario specificarlo se il nome è il plurale della classe
|
||||
// (Customer → customers). Lo specifichiamo esplicitamente per chiarezza.
|
||||
protected $table = 'customers';
|
||||
|
||||
// ─── Campi modificabili (mass assignment) ─────────────────────────────
|
||||
// Per sicurezza, Laravel blocca l'aggiornamento di massa di tutti i campi.
|
||||
// Solo i campi elencati qui possono essere modificati con create() o fill().
|
||||
// Alternativa: usa $guarded = [] per permettere tutto (meno sicuro).
|
||||
protected $fillable = [
|
||||
'name', // Ragione sociale o nome completo
|
||||
'email', // Email principale di contatto
|
||||
'phone', // Telefono
|
||||
'city', // Città
|
||||
'address', // Indirizzo completo
|
||||
'vat_number', // Partita IVA
|
||||
'fiscal_code', // Codice fiscale
|
||||
'type', // 'privato' o 'azienda'
|
||||
'status', // 'attivo', 'inattivo', 'prospect'
|
||||
'notes', // Note libere
|
||||
'contract_value', // Valore contratto annuo
|
||||
];
|
||||
|
||||
// ─── Cast automatici ──────────────────────────────────────────────────
|
||||
// Eloquent converte automaticamente il tipo quando leggi/scrivi il campo.
|
||||
// 'decimal:2' → restituisce un float con 2 decimali
|
||||
// 'boolean' → converte 0/1 del DB in true/false PHP
|
||||
protected $casts = [
|
||||
'contract_value' => 'decimal:2',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
// ─── Scope: filtri riutilizzabili ─────────────────────────────────────
|
||||
// Un "scope" è un metodo che aggiunge condizioni alla query.
|
||||
// Uso: Customer::active()->get()
|
||||
// invece di: Customer::where('status', 'attivo')->get()
|
||||
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 'attivo');
|
||||
}
|
||||
|
||||
public function scopeByType($query, string $type)
|
||||
{
|
||||
return $query->where('type', $type);
|
||||
}
|
||||
|
||||
public function scopeSearch($query, string $term)
|
||||
{
|
||||
return $query->where(function ($q) use ($term) {
|
||||
$q->where('name', 'like', "%{$term}%")
|
||||
->orWhere('email', 'like', "%{$term}%")
|
||||
->orWhere('city', 'like', "%{$term}%")
|
||||
->orWhere('vat_number', 'like', "%{$term}%");
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Accessor: trasforma il valore quando lo leggi ───────────────────
|
||||
// Uso: $customer->badge_color → restituisce il colore Bootstrap
|
||||
public function getBadgeColorAttribute(): string
|
||||
{
|
||||
return match ($this->status) {
|
||||
'attivo' => 'success',
|
||||
'inattivo' => 'secondary',
|
||||
'prospect' => 'warning',
|
||||
default => 'light',
|
||||
};
|
||||
}
|
||||
|
||||
public function getTypeLabelAttribute(): string
|
||||
{
|
||||
return match ($this->type) {
|
||||
'privato' => 'Privato',
|
||||
'azienda' => 'Azienda',
|
||||
default => 'N/D',
|
||||
};
|
||||
}
|
||||
}
|
||||
44
app/Models/Setting.php
Normal file
44
app/Models/Setting.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Model Setting — gestisce le impostazioni dinamiche dell'applicazione
|
||||
//
|
||||
// Ogni riga della tabella `settings` è una coppia chiave-valore.
|
||||
// Esempio:
|
||||
// key: "items_per_page" value: "15"
|
||||
// key: "currency_symbol" value: "€"
|
||||
//
|
||||
// I valori sono sempre stringhe nel DB. SettingService gestisce il cast
|
||||
// al tipo corretto (int, bool, string, ecc.) basandosi su config/settings.php
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
protected $table = 'settings';
|
||||
|
||||
protected $fillable = [
|
||||
'key',
|
||||
'value',
|
||||
'label', // Nome leggibile mostrato nel pannello admin
|
||||
'group', // Gruppo di appartenenza (es. "Azienda", "Visualizzazione")
|
||||
'type', // Tipo dato: string, integer, boolean, text
|
||||
];
|
||||
|
||||
// Non usiamo timestamps per le impostazioni (semplifica la tabella)
|
||||
public $timestamps = true;
|
||||
|
||||
// ─── Scope: cerca per chiave ──────────────────────────────────────────
|
||||
public function scopeForKey($query, string $key)
|
||||
{
|
||||
return $query->where('key', $key);
|
||||
}
|
||||
|
||||
public function scopeInGroup($query, string $group)
|
||||
{
|
||||
return $query->where('group', $group);
|
||||
}
|
||||
}
|
||||
49
app/Providers/AppServiceProvider.php
Normal file
49
app/Providers/AppServiceProvider.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// AppServiceProvider — Service Provider principale dell'applicazione
|
||||
//
|
||||
// Cos'è un Service Provider?
|
||||
// È una classe che viene caricata all'avvio di Laravel. Serve per:
|
||||
// - Registrare binding nel Service Container (IoC container)
|
||||
// - Eseguire codice di inizializzazione
|
||||
// - Condividere dati con tutte le view
|
||||
//
|
||||
// register(): invocato PRIMA del boot. Registra binding nel container.
|
||||
// boot(): invocato DOPO tutti i register. Qui tutto è disponibile.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use App\Services\SettingService;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
// Registra SettingService come Singleton:
|
||||
// una sola istanza per tutta la durata della richiesta.
|
||||
// Questo evita di creare più istanze (e più connessioni Redis)
|
||||
$this->app->singleton(SettingService::class, fn () => new SettingService());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
// Condivide le impostazioni di base con TUTTE le view Blade.
|
||||
// Così nelle view puoi usare $appSettings senza doverta passare
|
||||
// esplicitamente da ogni controller.
|
||||
View::composer('*', function ($view) {
|
||||
/** @var SettingService $settings */
|
||||
$settings = app(SettingService::class);
|
||||
|
||||
$view->with('appSettings', [
|
||||
'company_name' => $settings->get('company_name'),
|
||||
'currency_symbol' => $settings->get('currency_symbol'),
|
||||
'theme_color' => $settings->get('theme_color'),
|
||||
'support_email' => $settings->get('support_email'),
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
135
app/Services/SettingService.php
Normal file
135
app/Services/SettingService.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// SettingService — Servizio per le impostazioni dinamiche
|
||||
//
|
||||
// Questo service è il punto unico di accesso alle impostazioni.
|
||||
// Gestisce:
|
||||
// 1. Lettura con fallback ai default di config/settings.php
|
||||
// 2. Cache Redis per performance (evita query ad ogni richiesta)
|
||||
// 3. Cast dei valori al tipo corretto (string → int, "1" → true, ecc.)
|
||||
// 4. Scrittura e invalidazione cache
|
||||
//
|
||||
// DEPENDENCY INJECTION:
|
||||
// Laravel inietta automaticamente questo service quando lo dichiari
|
||||
// nel costruttore di un Controller:
|
||||
//
|
||||
// public function __construct(private SettingService $settings) {}
|
||||
//
|
||||
// Poi lo usi con: $this->settings->get('items_per_page')
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class SettingService
|
||||
{
|
||||
private const CACHE_KEY = 'app_settings_all';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
// ─── Leggi un'impostazione ─────────────────────────────────────────────
|
||||
// $key → chiave dell'impostazione (es. 'items_per_page')
|
||||
// $default → valore di ritorno se la chiave non esiste
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$all = $this->all();
|
||||
|
||||
if (isset($all[$key])) {
|
||||
return $all[$key];
|
||||
}
|
||||
|
||||
// Prova i default di config/settings.php
|
||||
$configDefault = config("settings.defaults.{$key}");
|
||||
|
||||
return $configDefault ?? $default;
|
||||
}
|
||||
|
||||
// ─── Leggi tutte le impostazioni (con cache) ─────────────────────────
|
||||
public function all(): array
|
||||
{
|
||||
$ttl = config('settings.cache_ttl_minutes', 60) * 60;
|
||||
|
||||
// Cache::remember: se la chiave è in cache, la restituisce;
|
||||
// altrimenti esegue la closure, salva il risultato e lo restituisce.
|
||||
return Cache::remember(self::CACHE_KEY, $ttl, function () {
|
||||
return $this->loadFromDatabase();
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Scrivi un'impostazione ───────────────────────────────────────────
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $this->serialize($value)]
|
||||
);
|
||||
|
||||
// Invalida la cache: al prossimo accesso verrà riletta dal DB
|
||||
$this->clearCache();
|
||||
}
|
||||
|
||||
// ─── Scrivi più impostazioni in una volta ─────────────────────────────
|
||||
public function setMany(array $settings): void
|
||||
{
|
||||
foreach ($settings as $key => $value) {
|
||||
Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $this->serialize($value)]
|
||||
);
|
||||
}
|
||||
|
||||
$this->clearCache();
|
||||
}
|
||||
|
||||
// ─── Svuota la cache delle impostazioni ───────────────────────────────
|
||||
public function clearCache(): void
|
||||
{
|
||||
Cache::forget(self::CACHE_KEY);
|
||||
}
|
||||
|
||||
// ─── Leggi dal database e applica i cast ──────────────────────────────
|
||||
private function loadFromDatabase(): array
|
||||
{
|
||||
$types = config('settings.types', []);
|
||||
$result = [];
|
||||
|
||||
foreach (Setting::all() as $setting) {
|
||||
$type = $types[$setting->key] ?? 'string';
|
||||
$result[$setting->key] = $this->cast($setting->value, $type);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// ─── Converti il valore al tipo corretto ──────────────────────────────
|
||||
// Necessario perché nel DB tutto è stringa VARCHAR.
|
||||
private function cast(mixed $value, string $type): mixed
|
||||
{
|
||||
return match ($type) {
|
||||
'integer' => (int) $value,
|
||||
'boolean' => filter_var($value, FILTER_VALIDATE_BOOLEAN),
|
||||
'float' => (float) $value,
|
||||
'json' => json_decode($value, true),
|
||||
default => (string) $value, // 'string', 'text'
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Serializza per il salvataggio in DB ──────────────────────────────
|
||||
private function serialize(mixed $value): string
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return $value ? '1' : '0';
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return json_encode($value);
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user