Laravel è un framework PHP open-source e facile da usare. Una delle sue caratteristiche più potenti è Eloquent, un ORM (object-relational mapper) che semplifica la gestione dei record del database.

Eloquent velocizza le operazioni di creazione, lettura, aggiornamento e cancellazione di un database da un’applicazione. Quando usiamo Eloquent, creiamo dei modelli che rispecchiano le tabelle del database e utilizziamo questi modelli per creare le nostre query.

Questo articolo esamina sei elementi delle funzionalità più potenti di Eloquent: i query scope, le relazioni, i mutator e gli accessor, le collection, la cancellazione dei modelli e le factory. Questo articolo illustra ciascuna funzionalità con esempi pratici. Speriamo che questi esempi vi aiuteranno a sfruttare al meglio Laravel Eloquent.

1. Query scope di Eloquent

Quando si crea un’applicazione, a volte ci si trova in situazioni in cui si usano le condizioni più di una volta. Riscrivere il codice in ogni caso può aumentare la possibilità di errori e rendere il codice poco ordinato. Laravel risolve questo problema avvolgendo tali condizioni in dichiarazioni riutilizzabili chiamate scope.

I query scope sono metodi per aggiungere la logica del database a un modello e riutilizzare la logica della query.

Di seguito è riportato un esempio di query scope. Supponiamo che di voler creare una piattaforma di sviluppo software per il nostro team che tenga traccia delle funzionalità completate e in corso. Possiamo utilizzare questa condizione per recuperare solo le funzionalità in corso:

$onGoing = Project::where('ongoing', 1)->get();

Potremmo aver bisogno di questa condizione in altre pagine dell’applicazione, come ad esempio la pagina delle statistiche. I query scope consentono a una pagina di riutilizzare la condizione precedente, semplificando la query e rendendo il codice più pulito.

Ecco come utilizzare un query scope per questo scenario:

class Features extends Model
{
    public function scopeOngoing($query)
    {
        return $query->where('ongoing', 0);
    }
}

Quindi utilizziamo il codice sottostante per eseguire lo scope:

$onGoing = Feature::ongoing()->get();

Esistono due tipi di scope: globali e locali.

Scope globali

Gli scope globali consentono di aggiungere vincoli a tutte le query di un modello. Ad esempio, possiamo aggiungere una condizione per filtrare le caratteristiche in base al nome del team leader in tutte le query del modello.

Scope locali

Gli scope locali consentono di definire vincoli comuni per la riutilizzabilità. Ad esempio, potremmo volere che l’applicazione restituisca le caratteristiche che presentano bug. Il codice potrebbe implementare uno scope locale come questo:

namespace AppModels;
use IlluminateDatabaseEloquentModel;

class User extends Model
{
    public function scopeBugged($query)
    {
        return $query->where('bugged', '>', 1);
    }
}

Il codice precedente restituisce tutte le funzioni che presentano bug non risolti.

2. Relazioni in Eloquent

Le relazioni in Eloquent permettono di mettere in relazione diverse tabelle in modo semplice. Ad esempio, un prodotto su un sito web di e-commerce può avere inventario, prezzo, visualizzazioni e recensioni. Con Eloquent possiamo gestire facilmente queste relazioni anche se i loro record si trovano in tabelle diverse.

Possiamo definire le relazioni come metodi sulle classi del modello, proprio come faremmo con un modello Eloquent. Alcune relazioni comunemente utilizzate in Eloquent sono quelle uno-a-uno, inverse e polimorfiche.

Uno-a-uno

Ecco un esempio di relazione uno-a-uno che associa un modello di prodotto a un inventario.

public function Inventory()
{
    return $this->hasOne('AppInventory');
}

Nel codice qui sopra, il metodo Inventory() chiama il metodo hasOne() sul modello di prodotto. Questo metodo verifica se il prodotto è attualmente disponibile.

Inversa

Eloquent permette anche di creare una relazione inversa. Ad esempio, quando vogliamo recuperare i prodotti in base al loro numero di visualizzazioni. Le relazioni inverse possono fornire i prodotti che suscitano il maggior interesse da parte dei visitatori di un sito web. Possiamo utilizzare il metodo belongsTo(), che è l’inverso di hasOne(). Il codice sottostante lo illustra.

public function product()
{
    return $this->belongsTo('AppProduct');
}

Nel codice qui sopra, Eloquent abbina il metodo product_id al numero di visualizzazioni passate. Il metodo product_id può aiutare a recuperare altri parametri, come il prezzo e l’inventario.

Polimorfica

Nello sviluppo di un’applicazione, le relazioni non sono sempre semplici. A volte un modello appartiene a più di un tipo di modello. Ad esempio, i modelli di prodotto e di inventario possono avere entrambi relazioni polimorfiche con un modello di immagine.

Le relazioni polimorfiche permettono di utilizzare lo stesso elenco di immagini sia per l’inventario che per i prodotti. Di seguito troviamo un frammento di codice che implementa una relazione polimorfica.

class Image extends Model
{
    /**
     * Getting the shared image.
     */
    public function myimage()
    {
        return $this->morphTo();
    }
}

class Product extends Model
{
    /**
     * Get the image to use on the product's page.
     */
    public function image()
    {
        return $this->morphOne(Image::class, 'myimage');
    }
}

class Inventory extends Model
{
    /**
     * Get the image to use on the inventory page.
     */
    public function image()
    {
        return $this->morphOne(Image::class, 'myimage');
    }
}

Il codice qui sopra utilizza il metodo morphTo() per recuperare il genitore del modello polimorfico.

Questa è solo la punta dell’iceberg di questo argomento. Per saperne di più, consultate la nostra guida avanzata alle relazioni di Laravel Eloquent.

3. Mutator e accessor di Eloquent

I mutator e gli accessor permettono di modificare i dati durante la memorizzazione e il recupero. I mutator modificano i dati prima di salvarli, mentre gli accessor li modificano mentre li recuperano.

Se vogliamo memorizzare i nomi in minuscolo nel database, possiamo creare un mutator per eseguire questa trasformazione. Se vogliamo visualizzare il nome e il cognome dell’utente come un unico nome nelle pagine dell’applicazione, possiamo creare un accessor per farlo.

Ecco un esempio di mutator che rende maiuscoli i nomi prima di salvarli.

class User extends Model
{
    /**
     * Mutators capitalizing first and last name.
     */
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = ucfirst($value);
    }

    public function setLastNameAttribute($value)
    {
        $this->attributes['last_name'] = ucfirst($value);
    }
}

Ecco un esempio di un accessor che combina il nome e il cognome dell’utente.

class User extends Model
{
    /**
     * Accessor combining both names.
     */
    public function getFullNameAttribute()
    {
        return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
    }
}

4. Collection di Eloquent

Le collection di Eloquent gestiscono i metodi che restituiscono i risultati di più modelli. Questa classe si trova in IlluminateDatabaseEloquentCollection.

Come per gli array, è possibile iterare le collection. Di seguito è riportata una semplice iterazione.

use AppModelsProduct;

$products = Product::where('availability', 1)->get();

foreach ($products as $product) {
   echo $product->name;
}

Le collection sono più potenti degli array perché possiamo eseguire operazioni più complesse su di esse. Ad esempio, possiamo visualizzare l’elenco di tutti i prodotti disponibili e saltare quelli che non sono “attivi”.

$names = Product::all()->reject(function ($product) {
   return $product->active === false;
})->map(function ($product) {
   return $product->name;
});

Di seguito sono elencati alcuni dei metodi che la classe collection mette a disposizione.

Contains

Il metodo contains() verifica se il codice contiene una modalità specificata, come mostrato nel codice seguente:

$products->contains(1);
$products->contains(Product::find(1));

All

Il metodo all() restituisce i modelli contenuti nella collection, come mostrato di seguito:

$collection = Product::all();

Molti altri metodi sono supportati dalla classe collections.

5. Cancellare i modelli in Eloquent

In Eloquent creiamo dei modelli che ci aiutano a costruire le query. Tuttavia, a volte è necessario eliminare i modelli per rendere più efficiente un’applicazione. Per farlo, chiamiamo delete sull’istanza del modello.

use AppModelsStock;

$stock = Stock::find(1);
$stock->delete();

Il codice qui sopra rimuove il modello Stock da un’applicazione. Si tratta di una rimozione permanente che non può essere annullata.

Soft delete

Un’altra funzione di Eloquent è il soft delete, la cancellazione “morbida”, del modello. Quando si elimina un modello, non lo si rimuove dal database.

Lo segnaliamo utilizzando deleted_at per indicare l’ora e la data dell’eliminazione. È utile quando vogliamo escludere una parte dei record del database, ad esempio quelli incompleti, senza rimuoverli definitivamente. Aiuta a ripulire i risultati delle query di Eloquent senza aggiungere ulteriori condizioni.

Possiamo attivare il soft delete aggiungendo il tratto softDeletes a un modello e aggiungendo una colonna deleted_at alla tabella del database correlata.

Aggiungere soft delete a un modello

Possiamo attivare soft delete in un modello aggiungendo il tratto IlluminateDatabaseEloquentSoftDeletes, come mostrato di seguito.

namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;

class Flight extends Model
{
   use SoftDeletes;
}

Come aggiungere una colonna delete_at

Prima di poter iniziare a usare soft delete, il database deve avere una colonna delete_at. Possiamo aggiungere questa colonna utilizzando un metodo builder helper di Laravel Schema, come mostrato di seguito:

use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

Schema::table('users', function (Blueprint $table) {
   $table->softDeletes();
});

Schema::table('users', function (Blueprint $table) {
   $table->dropSoftDeletes();
});

In questo modo si aggiunge una colonna delete_at che viene aggiornata con la data e l’ora in caso di successo di un’azione di soft delete.

Come includere i modelli cancellati

Se vogliamo che i risultati delle query includano i modelli eliminati in modo soft, dovremo aggiungere il metodo withTrashed() alla query. Un esempio è mostrato di seguito:

$stocks = Stock::withTrashed()->where('stock_id', 20)->get();

La query di cui sopra includerà anche i modelli con l’attributo deleted_at.

Come recuperare solo i modelli eliminati in modo soft

Eloquent permette anche di recuperare esclusivamente i modelli cancellati in modo soft. Possiamo farlo chiamando il metodo onlyTrashed(), ad esempio:

$Stock = Stock::onlyTrashed()->where('stock_id', 1)->get();

Come ripristinare i modelli eliminati

Possiamo anche ripristinare i modelli eliminati in modo soft chiamando il metodo restore().

$stocks = Stock::withTrashed()->where('stock_id', 20)->restore();

Questo metodo cambia il campo delete_at di un modello eliminato in modo soft in null. Se il modello non è stato cancellato, il campo rimane invariato.

6. Factory di Eloquent

Le factory di modelli in Laravel creano dati fittizi che possamo usare per testare l’applicazione o per alimentare il database. Per farlo, dobbiamo creare un modello in una classe factory, come mostrato nell’esempio seguente. Il frammento di codice crea un modello di factory che può generare fornitori falsi di un prodotto e dei suoi prezzi.

namespace DatabaseFactories;
use IlluminateDatabaseEloquentFactoriesFactory;
use IlluminateSupportStr;

class StockFactory extends Factory
{
    public function definition()
    {
        return [
            'supplier_name' => fake()->name(),
            'price' => fake()->numberBetween($min = 1500, $max = 6000),
        ];
    }
}

Il metodo definition() dell’esempio precedente restituisce un insieme di valori di attributi che Laravel utilizza per la creazione del modello. L’helper fake aiuta il factory ad accedere alla libreria di PHP, Faker.

Riepilogo

Eloquent semplifica le attività di sviluppo delle applicazioni in Laravel. È ugualmente efficace nella creazione di query semplici o complesse, grazie a implementazioni come le relazioni. La semplicità di generare dati fittizi funzionali utilizzando le factory lo rende perfetto per gli sviluppatori che vogliono creare test robusti per le loro applicazioni. Inoltre, gli scope di Eloquent aiutano a semplificare le query complesse in modo da rendere il codice più ordinato.

Sebbene questo articolo abbia trattato solo sei delle sue caratteristiche principali, Eloquent possiede altre potenti funzionalità. L’uso di modelli condivisibili e riutilizzabili ha reso Eloquent una funzione molto apprezzata dagli sviluppatori e la semplicità delle query di Eloquent rende Laravel un framework facile da sviluppare, anche per i principianti.

Qualunque sia il vostro livello di esperienza, la piattaforma di Hosting di Applicazioni web di Kinsta supporta gli sviluppatori come voi. Il nostro template di avvio rapido di Laravel mostra quanto sia facile rendere operativa la vostra applicazione sui nostri server all’interno della rete premium tier di Google Cloud.

Steve Bonisteel Kinsta

Steve Bonisteel è un Technical Editor di Kinsta che ha iniziato la sua carriera di scrittore come giornalista della carta stampata, inseguendo ambulanze e camion dei pompieri. Dalla fine degli anni '90 si occupa di tecnologia legata a Internet.