Ciao! Oggi parliamo dei trait in Laravel, una feature interessante ma spesso sottovalutata. A partire da Laravel 11, possiamo crearli rapidamente con Artisan:
php artisan make:trait NomeTrait
Cosa sono i trait?
I trait sono "frammenti di codice riutilizzabile" che possiamo inserire in più classi. Sono perfetti quando vogliamo condividere metodi tra diversi modelli senza usare l'ereditarietà classica.
In parole semplici: scrivi il codice una volta, lo usi ovunque serve.
Caso d'uso: sistema di History
Immaginiamo di voler tracciare tutte le modifiche ai nostri modelli in una tabella histories. Ogni volta che un record viene creato, aggiornato o cancellato, salviamo questa informazione.
Senza trait dovremmo riscrivere la stessa logica in ogni modello. Con i trait? Lo scriviamo una volta sola.
Creiamo il trait
php artisan make:trait WithHistory
Laravel crea il file in app/Traits/WithHistory.php. Apriamolo e scriviamo la nostra logica:
<?php
namespace App\Traits;
use App\Models\History;
trait WithHistory
{
protected static function bootWithHistory()
{
// Quando viene creato un record
static::created(function ($model) {
History::create([
'model_type' => get_class($model),
'model_id' => $model->id,
'action' => 'created',
'user_id' => auth()->id(),
'data' => json_encode($model->toArray()),
]);
});
// Quando viene aggiornato
static::updated(function ($model) {
History::create([
'model_type' => get_class($model),
'model_id' => $model->id,
'action' => 'updated',
'user_id' => auth()->id(),
'data' => json_encode($model->getChanges()),
]);
});
// Quando viene cancellato
static::deleted(function ($model) {
History::create([
'model_type' => get_class($model),
'model_id' => $model->id,
'action' => 'deleted',
'user_id' => auth()->id(),
]);
});
}
}
Le funzioni static:: di Laravel sono una sorta di event listener che scattano a specifiche interazioni tra modelli e database e sono perfette per essere "incapsulate" in un trait.
ecco nel dettaglio:
| metodo | desc |
|---|---|
| static::creating() | Sta per essere creato |
| static::created() | È stato appena creato |
| static::updating() | Sta per essere aggiornato |
| static::updated() | È stato appena aggiornato |
| static::deleting() | Sta per essere cancellato |
| static::deleted() | È stato appena cancellato |
| static::saving() | Sta per essere salvato (create o update) |
| static::saved() | È stato appena salvato |
Il modello History
Prima di andare avanti, creiamo il modello e la migration per la tabella histories:
php artisan make:model History -m
Migration:
Schema::create('histories', function (Blueprint $table) {
$table->id();
$table->string('model_type'); // Tipo di modello (es. App\Models\Post)
$table->unsignedBigInteger('model_id'); // ID del record
$table->string('action'); // created, updated, deleted
$table->unsignedBigInteger('user_id')->nullable();
$table->json('data')->nullable(); // Dati del cambiamento
$table->timestamps();
});
Usiamo il trait nei modelli
Ora possiamo aggiungere il nostro trait a qualsiasi modello vogliamo tracciare:
<?php
//Model/Post.php
class Post extends Model
{
use WithHistory;
// ...
}
//Model/News.php
class News extends Model
{
use WithHistory;
// ...
}
Fatto! Ora ogni creazione, modifica o cancellazione di Post e News viene automaticamente tracciata nella tabella histories.
Il vantaggio
La logica di tracking è scritta una sola volta nel trait. Se domani vogliamo aggiungere il tracking anche al modello Product, basta:
//Model/Product.php
class Product extends Model
{
use WithHistory;
// ...
}
Niente codice duplicato, tutto centralizzato e facile da gestire.
Visualizzare la history
Possiamo anche aggiungere una relazione nel trait per recuperare facilmente la storia di un modello:
trait WithHistory
{
// ... metodi boot precedenti ...
public function histories()
{
return $this->morphMany(History::class, 'model', 'model_type', 'model_id');
}
}
E usarla così:
$post = Post::find(1);
$history = $post->histories; // Tutte le modifiche di questo post
// Oppure filtrare
$updates = $post->histories()->where('action', 'updated')->get();
Conclusione
I trait sono perfetti per condividere comportamenti comuni tra modelli diversi senza inquinare la gerarchia di classi. Il sistema di history che abbiamo creato è solo un esempio: potresti usare trait per gestire soft deletes custom, slug automatici, notifiche, e molto altro.
Per oggi è tutto, grazie per aver letto questo post. A presto!

