L’accuratezza e la coerenza dei dati possono portare da piccoli inconvenienti a gravi problemi aziendali. È fondamentale creare un codice che memorizzi, modifichi e cancelli i dati nel database in modo sicuro.

Ecco le transazioni del database di Laravel.

Le transazioni di database sono un approccio efficace per garantire l’integrità dei dati. Laravel semplifica queste transazioni su un’ampia gamma di database.

Ma cosa sono esattamente? Come potete risolverle in Laravel?

Alla fine di questa esauriente guida, avrete imparato tutto sulle transazioni di database in Laravel e su come usarle efficacemente nel vostro progetto.

Cosa Sono le Transazioni di Database in Laravel?

Prima di addentrarci nell’aspetto tecnico, cerchiamo di capire cosa sono le transazioni di database in Laravel e come potete trarne vantaggio.

Una transazione di database è un insieme di operazioni che potete eseguire in modo sicuro all’interno della struttura del database della vostra applicazione, per esempio query SQL per modificare i dati (come aggiornamenti, cancellazioni e inserimenti).

In qualsiasi momento, potete decidere di annullare tutte le query della transazione. Inoltre, tutte le query effettuate verranno trattate dal database come un’unica azione.

Vediamo un esempio.

Supponiamo di avere un’applicazione che permette agli utenti di creare degli account. Naturalmente, a ogni account possono essere associati uno o più utenti. Se l’app genera contemporaneamente un account e il primo utente, dovrete occuparvi di cosa succede se l’account viene generato correttamente, ma l’utente no.

Date un’occhiata a questo esempio di codice:

// Create Account
$newAcct = Account::create([
  'accountname' => Input::get('accountname'),
]);

// Create User
$newUser = User::create([
  'username' => Input::get('username'),
  'account_id' => $newAcct->id,
]);

Ci sono due scenari che possono causare problemi spiacevoli:

  1. L’account non viene generato
  2. Impossibile creare un utente

Consideriamo quest’ultima situazione.

Avere un account senza utenti disponibili comporta un’incoerenza dei dati nel database. Per risolvere questo problema, potete affrontare l’arduo compito di creare un codice per ovviare a questa situazione, oppure risparmiare molto codice o semplicemente inserirlo in una transazione per fare le cose in fretta.

Le transazioni sono presenti nella maggior parte dei database SQL, ma variano soprattutto nella loro implementazione ed efficienza. I sistemi più diffusi come MySQL, SQLite, PostgreSQL e Oracle supportano le transazioni, quindi non dovreste avere problemi a implementare il vostro database SQL preferito.

Migrazioni

La migrazione è una funzionalità fondamentale di Laravel che vi permette di creare una tabella nel vostro database, apportare modifiche e condividere lo schema del database dell’applicazione. Potete usare la migrazione di Laravel per modificare le tabelle aggiungendo nuove colonne o rimuovendo quelle esistenti.

Supponiamo che stiate discutendo delle idee con un team e che dobbiate apportare delle modifiche alla tabella. Il file SQL deve essere condiviso e importato da qualcuno del team. È possibile che questa persona si dimentichi di importare il file SQL, causando problemi nel funzionamento dell’applicazione.

È qui che la migrazione di Laravel viene in aiuto. Potete aggiungere una nuova colonna al vostro database o eliminare voci senza influenzare quelle già presenti.

Seeder

Il seeding è uno strumento fornito a chi sviluppa con Laravel per facilitare il test di diversi tipi di dati, risolvere bug e ottimizzare le prestazioni. Potete aggiungere automaticamente più righe di dati fittizi alla tabella del vostro database tramite il seeder del database con un solo comando.

In questo modo potete ricominciare da capo con un nuovo database e dei valori di esempio, invece di doverli inserire manualmente ogni volta che il database viene ripristinato.

Opzioni per le Transazioni del Database Laravel

Laravel offre diversi strumenti per gestire i dati come Adminer. Per quanto riguarda le transazioni del database, ci sono tre metodi per avviare una transazione manualmente e avere il pieno controllo sulla gestione delle transazioni.

Molti utenti trovano queste opzioni più flessibili per definire esattamente quando una transazione deve essere eseguita o annullata:

  • Creare una transazione: Usate il comando DB::beginTransaction(); per avviare una transazione.
  • Annullare una transazione: Usate il comando DB::rollBack(); se volete apportare delle modifiche o annullare delle azioni.
  • Fare commit di una transazione: Se tutto è andato come previsto, usate il comando DB::commit();.

Ricordate sempre di concludere ogni transazione aperta con un’azione di commit o di rollback, in particolare i loop. In caso contrario, questo metodo manuale non sarà sincronizzato e i vostri record non verranno aggiornati.

Come Lavorare con il Database di Laravel

Le migrazioni e i seeders, come già accennato, sono soluzioni sofisticate pensate per chi sviluppa con Laravel per distribuire, eliminare e ripristinare rapidamente il database di un’applicazione riducendo le disparità. Sono utili soprattutto quando più persone lavorano allo sviluppo della stessa applicazione.

Questa sezione vi mostrerà come usare facilmente le migrazioni e i seeders con il vostro database Laravel tramite i comandi di Artisan.

Prerequisiti

Ecco cosa vi serve per iniziare:

  1. Un utente non root con permessi sudo su un computer locale di Ubuntu 18.04 o su un server di sviluppo. È buona norma avere un firewall attivo se state usando un server remoto.
  2. LEMP installato sul vostro computer. Potete scegliere di installare Docker e Docker Compose per eseguire la vostra applicazione se vi sentite più a vostro agio a lavorarci.

Il nostro strumento DevKinsta è alimentato da Docker e utilizzato da più di 55,000+ persone che lavorano nello sviluppo e nel design per creare e sviluppare facilmente siti WordPress singoli o multipli.

Esistono altri strumenti di sviluppo web che potete usare a seconda delle vostre capacità ed esigenze di codifica.

Migrazioni Laravel

Ci sono due metodi in una classe di migrazione: up e down. Il metodo up viene utilizzato per creare nuove tabelle, indici o colonne nel database. Il metodo down annulla gli effetti del metodo up.

Potete usare lo schema builder di Laravel per creare e modificare liberamente le tabelle in ognuno di questi metodi. Per esempio, questa migrazione genera una tabella voli:

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

class CreateFlightsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/

public function up() {
  Schema::create('flights', function (Blueprint $table) {
	$table->bigIncrements('id');
	$table->string('name');
	$table->string('airline');
	$table->timestamps();
  });
}

/**
* Reverse the migrations.
*
* @return void
*/

public function down() {
  Schema::drop('flights');
}

Tenete presente che i comandi make:migration devono chiarire il nome della tabella. Assicuratevi quindi che table_name corrisponda a ciò che desiderate.

Potete usare le opzioni --table e --create per specificare il nome della tabella e se la migrazione deve creare una nuova tabella, come mostrato di seguito:

php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users

La directory database/migrazioni includerà ora la nuova migrazione. Il nome di ogni file di migrazione include un timestamp, che Laravel usa per determinare l’ordine di migrazione.

Avete anche la possibilità di definire un indirizzo --path, che dovrebbe essere collegato alla directory principale della vostra installazione. Usate il seguente comando:

php artisan migrate:make foo --path=app/migrations

Eseguire le Migrazioni

Ci sono alcuni comandi utili che potete usare durante l’esecuzione delle migrazioni. Vediamo di seguito alcuni di essi:

  • php artisan migrate: Questo comando pubblica tutti gli schemi nel database. Genera anche una tabella nel database.
  • php artisan migrate --path=app/foo/migrations: Questo comando esegue tutte le migrazioni in una directory. Se ricevete un messaggio di errore “Niente da migrare”, eseguite il comando php artisan migrate --path=database/migrations/foo senza la directory app.
  • php artisan migrate --package=vendor/package: Usate questo comando se volete eseguire le migrazioni per un pacchetto.

A volte potreste ricevere un errore “Classe non trovata” durante l’esecuzione delle migrazioni. In questo caso, eseguite il comando composer dump-autoload.

Alcune migrazioni possono essere pericolose e causare la perdita dei vostri dati. Per questo motivo, Laravel vi chiederà di confermare l’esecuzione dei comandi per salvaguardare i vostri dati.

Se non volete che vi venga richiesto, usate --force flag per forzare i comandi come segue:

php artisan migrate --force

Rollback delle Migrazioni

Usate il comando di rollback quando dovete annullare l’ultimo batch di migrazione come segue:

php artisan migrate:rollback

Ecco altri comandi di rollback che potete usare:

  • php artisan migrate:reset: Questo comando inverte tutte le migrazioni, non solo l’ultima operazione.
  • php artisan migrate:fresh: Usate questo comando quando volete una nuova installazione del database. Rimuove tutte le tabelle esistenti ed esegue il comando migration.
  • php artisan migrate:refresh: Questo è un comando 2-in-1 che esegue entrambi i comandi :rollback and migrate.
  • php artisan migrate:fresh --seed: Esegue il comando migrate:fresh prima di creare il database. Quando installate l’applicazione su un nuovo host, potete usare questo comando per creare il seed (cioè caricare i dati nel database).

Laravel Seeding

Un seeder è una classe che crea e inserisce campioni di dati (seed) in un database. Laravel offre una tecnica semplice per alimentare il database con dati di prova utilizzando le classi seed nella directory database/seeds.

Avete la libertà di scegliere il nome delle vostre classi seed. Ma vi consigliamo di seguire uno schema di denominazione chiaro, come UsersTableSeeder. In seguito, per impostazione predefinita, verrà creata una classe DatabaseSeeder.

Ecco un esempio di classe seed per database in Laravel:

class DatabaseSeeder extends Seeder {
  public function run() {
	$this->call('UserTableSeeder');
	$this->command->info('User table seeded!');
  }
}
class UserTableSeeder extends Seeder {
  public function run() {
	DB::table('users')->delete();
	User::create(array('email' => '[email protected]'));
  }
}

Creare un Seeder

Generare dei seeders è semplicissimo, potreste farlo a occhi chiusi (ma per favore non fatelo).

Eseguite il comando make:seeder artisan per creare un seeder. Ora la cartella database/seeds includerà tutti i seeders prodotti dal framework:

php artisan make:seeder UsersTableSeeder

Il metodo predefinito di una classe di seeders è l’esecuzione. Il processo avviene quando applicate il comando db:seed artisan. Potete inserire i dati nel vostro database nel modo che preferite utilizzando la funzione run. Inoltre, è possibile utilizzare le fabbriche di modelli di Eloquent o Query Builder per inserire i dati manualmente.

In ogni caso, dovete tenere presente che durante l’inserimento del database, la protezione dell’assegnazione massiva viene disattivata automaticamente.

In questo caso, apporteremo delle modifiche alla classe di base DatabaseSeeder e aggiungeremo un’istruzione di inserimento nel database al metodo run:

<?php
use IlluminateDatabaseSeeder;
use IlluminateSupportFacadesDB;
use IlluminateSupportFacadesHash;
use IlluminateSupportStr;

class DatabaseSeeder extends Seeder {
  /**
  * Run the database seeds.
  *
  * @return void
  */
  public function run() {
	DB::table('users')->insert([
  	'name' => Str::random(10),
  	'email' => Str::random(10).'@gmail.com',
  	'password' => Hash::make('password'),
	]);
  }
}

Se volete indicare eventuali dipendenze all’interno del codice del metodo di esecuzione, il contenitore di servizi Laravel le risolverà automaticamente.

Inoltre, potete usare la funzione call per eseguire diverse classi di seed da questa classe, consentendovi di personalizzare l’ordine di seeding. Potete suddividere il seeding del database in diversi file, assicurandovi che nessuna classe di seeder si espanda eccessivamente.

Inserite il nome della classe di seeder che volete utilizzare come mostrato di seguito:

/**
* Run the database seeds.
*
* @return void
*/
public function run() {
  $this->call([
	UsersTableSeeder::class,
	PostsTableSeeder::class,
	CommentsTableSeeder::class,
  ]);
}

Esecuzione dei Seeder

Dopo aver generato il vostro seeder, potreste aver bisogno di usare il comando dump-autoload per ricreare l’autoloader di Composer:

composer dump-autoload

Successivamente, dovrete eseguire il comando db:seed artisan per fare seeding del vostro database:

php artisan db:seed

Questo comando esegue la classe DatabaseSeeder per procura, che può essere utilizzata per eseguire altre classi di seed. Tuttavia, potete usare il parametro --class per eseguire una particolare classe di seeder separatamente, come segue:

php artisan db:seed --class=UserTableSeeder

E se voleste ricreare il vostro database da zero, rimuovendo tutte le tabelle ed eseguendo nuovamente tutte le migrazioni? In questo caso, usate il comando migrate:fresh per eseguire il seed del database.

php artisan migrate:fresh --seed

Come nel caso delle migrazioni, alcuni processi di seeding possono portare alla perdita di dati o a modifiche indesiderate. Per questo motivo, vi verrà richiesta l’approvazione prima dell’esecuzione dei seeders per evitare di eseguire comandi di seeding sul vostro database primario.

Se siete abbastanza sicuri e non volete essere interrotti da questo passaggio di sicurezza, usate il flag --force qui sotto:

php artisan db:seed --force

Altri 5 Modi per Usare le Query di Database Grezze in Laravel

Anche se Laravel offre strumenti pratici come Eloquent e Query Builder, potete comunque eseguire query grezze utilizzando SQL. Abbiamo raccolto cinque modi diversi per farlo.

Ma prima di iniziare, dovete sapere che le query grezze non sono protette automaticamente, il che le rende un approccio rischioso. Per questo motivo, se inserite dei parametri nella query, assicuratevi che siano nel formato corretto e che abbiano i valori giusti, come ad esempio un numero piuttosto che un testo.

Calcoli con Avg/Sum/Count

Potete usare una query grezza se volete creare GROUP BY () e poi usare le funzioni aggregate di MySQL come Count(), SUM(), AVG(), MIN() o MAX() come mostrato nel seguente esempio:

$users = DB::table('users')
  ->selectRaw('count(*) as user_count, status')
  ->where('status', '<>', 1)
  ->groupBy('status')
  ->get();

È anche possibile eseguire sia count() che avg() nella stessa query SQL:

$salaries = DB::table('salaries')
  ->selectRaw('companies.name as company_name, avg(salary) as avg_salary, count(*) as people_count')
  ->join('companies', 'salaries.company_id', '=', 'companies.id')
  ->groupBy('companies.id')
  ->orderByDesc('avg_salary')
  ->get();

Filtrare gli Anni

Nel caso in cui doveste eseguire dei calcoli SQL all’interno di GROUP BY o ORDER BY, potete usare le query groupByRaw() e orderByRaw(). Dopo il raggruppamento, potete anche usare l’istruzione where xon una query SQL having con havingRaw ().

Pwe esempio, questo comando mostra come raggruppare un campo data/ora per anno:

$results = User::selectRaw('YEAR(birth_date) as year, COUNT(id) as amount')
  ->groupByRaw('YEAR(birth_date)')
  ->havingRaw('YEAR(birth_date) > 2000')
  ->orderByRaw('YEAR(birth_date)')
  ->get();

Calcolo di un Singolo Campo (Sotto-Query)

Supponiamo che vogliate calcolare una colonna da un’altra e restituire il risultato in una query SQL. Come farlo?

Diamo un’occhiata:

$products = Product::select('id', 'name')
  ->selectRaw('price - discount_price AS discount')
  ->get();

Ecco un altro esempio di istruzione SQL CASE:

$users = DB::table('users')
  ->select('name', 'surname')
  ->selectRaw("(CASE WHEN (gender = 1) THEN 'M' ELSE 'F' END) as gender_text")
  ->get();

Convertire un Vecchio SQL

È uno scenario comune avere un’istruzione SQL che deve essere convertita in Eloquent o Query Builder, soprattutto se proviene da un vecchio progetto a cui avete lavorato.

In realtà non è necessario farlo. Potete invece usare l’istruzione DB::select() come mostrato:

$results = DB::select('select * from users where id=?', [1]);

Eseguire una Query Senza Risultati

DB::statement può eseguire una query SQL senza ottenere risultati come INSERT o UPDATE senza variabili.

Questa funzione si usa spesso nelle migrazioni di database quando la struttura di una tabella cambia e i vecchi dati devono essere modificati con quelli nuovi:

DB::statement('UPDATE users SET role_id = 1 WHERE role_id IS NULL AND YEAR(created_at) > 2020');

Inoltre, DB::statement() può eseguire qualsiasi query SQL con schema non limitato a valori o colonne. Ecco un esempio:

DB::statement('DROP TABLE users');
DB::statement('ALTER TABLE projects AUTO_INCREMENT=123');

Riepilogo

A questo punto dovreste avere una conoscenza approfondita delle transazioni di database in Laravel e di come implementarle. Non solo aiutano l’integrità dei dati, ma contribuiscono anche a ottimizzare le prestazioni di Laravel e a semplificare il processo di sviluppo.