Prologo
Primi Passi
Architettura
Le Basi
- Routing
- Middleware
- Protezione da CSRF
- Controller
- Richieste
- Risposte
- Views
- Blade
- Vite
- URL
- Sessioni
- Validazione
- Errori
- Logging
Approfondimenti
- Artisan
- Broadcasting
- Cache
- Collezioni
- Concorrenza
- Contesto
- Contratti
- Eventi
- File System
- Helpers
- Client HTTP
- Localizzazione
- Notifiche
- Sviluppo di Package
- Processi
- Code
- Rate-limiting
- Stringhe
- Scheduling di Task
Sicurezza
Database
Eloquent ORM
Testing
Package
Database
- Introduzione
- Eseguire Query SQL
- Transazioni di Database
- Collegarsi alla CLI del Database
- Ispezionare i Tuoi Database
- Monitorare i Tuoi Database
Introduzione
Quasi tutte le applicazioni web moderne interagiscono con un database. Laravel rende estremamente semplice l’interazione con i database supportati utilizzando SQL grezzo, un builder di query fluente e l’Eloquent ORM. Attualmente, Laravel offre supporto ufficiale per cinque database:
- MariaDB 10.3+ (Politica delle Versioni)
- MySQL 5.7+ (Politica delle Versioni)
- PostgreSQL 10.0+ (Politica delle Versioni)
- SQLite 3.26.0+
- SQL Server 2017+ (Politica delle Versioni)
Inoltre, MongoDB è supportato tramite il pacchetto mongodb/laravel-mongodb
, ufficialmente mantenuto da MongoDB. Consulta la documentazione di Laravel MongoDB per maggiori informazioni.
Configurazione
La configurazione dei servizi database di Laravel si trova nel file di configurazione config/database.php
della tua applicazione. In questo file, puoi definire tutte le tue connessioni al database, oltre a specificare quale connessione deve essere utilizzata di default. La maggior parte delle opzioni di configurazione in questo file si basa sui valori delle variabili d’ambiente della tua applicazione. Sono forniti esempi per la maggior parte dei sistemi database supportati da Laravel in questo file.
Di default, la configurazione di esempio environment configuration di Laravel è pronta per l’uso con Laravel Sail, che è una configurazione Docker per sviluppare applicazioni Laravel sulla tua macchina locale. Tuttavia, puoi modificare la configurazione del database secondo le necessità del tuo database locale.
Configurazione di SQLite
I database SQLite sono contenuti in un unico file nel tuo filesystem. Puoi creare un nuovo database SQLite usando il comando touch
nel terminale: touch database/database.sqlite
. Dopo aver creato il database, puoi facilmente configurare le variabili d’ambiente per puntare a questo database inserendo il percorso assoluto nel valore DB_DATABASE
:
DB_CONNECTION=sqlite
DB_DATABASE=/percorso/assoluto/a/database.sqlite
Di default, i vincoli delle chiavi esterne sono abilitati per le connessioni SQLite. Se vuoi disabilitarli, imposta la variabile d’ambiente DB_FOREIGN_KEYS
a false
:
DB_FOREIGN_KEYS=false
Se usi l’installer di Laravel per creare la tua applicazione Laravel e selezioni SQLite come database, Laravel creerà automaticamente un file
database/database.sqlite
ed eseguirà le migrazioni del database predefinite per te.
Configurazione di Microsoft SQL Server
Per utilizzare un database Microsoft SQL Server, assicurati di avere installate le estensioni PHP sqlsrv
e pdo_sqlsrv
, oltre a tutte le dipendenze necessarie come il driver Microsoft SQL ODBC.
Configurazione Tramite URL
Normalmente, le connessioni al database vengono configurate usando diversi valori come host
, database
, username
, password
, ecc. Ciascuno di questi valori ha la propria variabile d’ambiente corrispondente. Questo significa che, quando configuri le informazioni di connessione al database su un server di produzione, devi gestire diverse variabili d’ambiente.
Alcuni provider di database gestiti, come AWS e Heroku, forniscono un unico "URL" del database che contiene tutte le informazioni di connessione in un’unica stringa. Un esempio di URL del database potrebbe essere simile al seguente:
mysql://root:password@127.0.0.1/forge?charset=UTF-8
Questi URL seguono tipicamente una convenzione di schema standard:
driver://username:password@host:port/database?options
Per comodità, Laravel supporta questi URL come alternativa alla configurazione del database con molteplici opzioni. Se l’opzione di configurazione url
(o la corrispondente variabile d’ambiente DB_URL
) è presente, verrà utilizzata per estrarre le informazioni di connessione e le credenziali del database.
Connessioni di Lettura e Scrittura
A volte potresti voler usare una connessione al database per le istruzioni SELECT e un’altra per INSERT, UPDATE e DELETE. Laravel rende questo semplice e utilizzerà sempre le connessioni corrette, sia che tu stia usando query raw, il query builder o l’ORM Eloquent.
Per vedere come configurare le connessioni di lettura/scrittura, guarda questo esempio:
'mysql' => [
'read' => [
'host' => [
'192.168.1.1',
'196.168.1.2',
],
],
'write' => [
'host' => [
'196.168.1.3',
],
],
'sticky' => true,
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
Nota che sono state aggiunte tre chiavi all’array di configurazione: read
, write
e sticky
. Le chiavi read
e write
contengono array con una singola chiave: host
. Le altre opzioni del database per le connessioni read
e write
verranno unite dall’array di configurazione principale mysql
.
Devi inserire elementi negli array read
e write
solo se vuoi sovrascrivere i valori dell’array principale mysql
. In questo caso, 192.168.1.1
sarà usato come host per la connessione "read", mentre 192.168.1.3
sarà usato per la connessione "write". Le credenziali del database, il prefisso, il set di caratteri e tutte le altre opzioni nell’array principale mysql
saranno condivise tra entrambe le connessioni. Quando ci sono più valori nell’array di configurazione host
, verrà scelto casualmente un host del database per ogni richiesta.
L’opzione sticky
L’opzione sticky
è un valore opzionale che può essere utilizzato per permettere la lettura immediata dei record scritti nel database durante il ciclo di richiesta corrente. Se l’opzione sticky
è abilitata e un’operazione di "write" è stata eseguita sul database durante il ciclo di richiesta corrente, qualsiasi ulteriore operazione di "read" utilizzerà la connessione "write". Questo garantisce che i dati scritti durante il ciclo di richiesta possano essere letti immediatamente dal database nella stessa richiesta. Sta a te decidere se questo comportamento è quello desiderato per la tua applicazione.
Eseguire Query SQL
Dopo aver configurato la connessione al database, puoi eseguire query utilizzando il facade DB
. Il facade DB
offre metodi per ogni tipo di query: select
, update
, insert
, delete
e statement
.
Eseguire una Query Select
Per eseguire una query SELECT di base, puoi usare il metodo select
sulla facade DB
:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Mostra una lista di tutti gli utenti dell'applicazione.
*/
public function index(): View
{
$users = DB::select('select * from users where active = ?', [1]);
return view('user.index', ['users' => $users]);
}
}
Il primo argomento passato al metodo select
è la query SQL, mentre il secondo argomento sono i binding dei parametri che devono essere legati alla query. Tipicamente, questi sono i valori delle condizioni della clausola where
. Il binding dei parametri fornisce protezione contro le iniezioni SQL.
Il metodo select
restituirà sempre un array
di risultati. Ogni risultato all’interno dell’array sarà un oggetto stdClass
di PHP che rappresenta un record del database:
use Illuminate\Support\Facades\DB;
$users = DB::select('select * from users');
foreach ($users as $user) {
echo $user->name;
}
Selezione di Valori Scalari
A volte una query al database restituisce un singolo valore scalare. Invece di dover ottenere il risultato scalare della query tramite un oggetto record, Laravel permette di recuperare direttamente questo valore usando il metodo scalar
:
$burgers = DB::scalar(
"select count(case when food = 'burger' then 1 end) as burgers from menu"
);
Selezionare più set di risultati
Se la tua applicazione chiama stored procedures che restituiscono più set di risultati, puoi usare il metodo selectResultSets
per ottenere tutti i set di risultati restituiti dalla stored procedure:
[$options, $notifications] = DB::selectResultSets(
"CALL get_user_options_and_notifications(?)", $request->user()->id
);
Utilizzo dei Named Bindings
Invece di utilizzare ?
per rappresentare i parametri di binding, puoi eseguire una query usando i named bindings:
$results = DB::select('select * from users where id = :id', ['id' => 1]);
Eseguire una insert
Per eseguire una insert
, puoi usare il metodo insert
sulla facade DB
. Come select
, questo metodo accetta la query SQL come primo argomento e i binding come secondo argomento:
use Illuminate\Support\Facades\DB;
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
Eseguire un update
Il metodo update
deve essere utilizzato per aggiornare i record esistenti nel database. Il numero di righe interessate dalla query viene restituito dal metodo:
use Illuminate\Support\Facades\DB;
$affected = DB::update(
'update users set votes = 100 where name = ?',
['Anita']
);
Eseguire un’eliminazione
Il metodo delete
si usa per eliminare i record dal database. Come per update
, il metodo restituisce il numero di righe interessate:
use Illuminate\Support\Facades\DB;
$deleted = DB::delete('delete from users');
Esecuzione di una query generica
Alcune istruzioni del database non restituiscono alcun valore. Per questo tipo di operazioni, puoi utilizzare il metodo statement
sulla facade DB
:
DB::statement('drop table users');
Eseguire un’Unprepared
A volte potresti voler eseguire un’istruzione SQL senza legare alcun valore. Puoi usare il metodo unprepared
della facade DB
per farlo:
DB::unprepared('update users set votes = 100 where name = "Dries"');
Le istruzioni unprepared potrebbero essere vulnerabili a SQL injection. Non dovresti mai permettere valori controllati dagli utenti in un’istruzione non preparata.
Commit Impliciti
Quando utilizzi i metodi statement
e unprepared
della facade DB
all’interno delle transazioni, devi fare attenzione ad evitare istruzioni che causano commit impliciti. Queste istruzioni fanno sì che il motore del database effettui indirettamente il commit dell’intera transazione, lasciando Laravel ignaro del livello di transazione del database. Un esempio di tale istruzione è la creazione di una tabella nel database:
DB::unprepared('create table a (col varchar(1) null)');
Consulta il manuale di MySQL per un elenco di tutte le istruzioni che attivano commit impliciti.
Utilizzare più Connessioni al Database
Se la tua applicazione definisce più connessioni nel file di configurazione config/database.php
, puoi accedere a ciascuna connessione tramite il metodo connection
fornito dal facade DB
. Il nome della connessione passato al metodo connection
deve corrispondere a una delle connessioni elencate nel file config/database.php
o configurato a runtime usando l’helper config
:
use Illuminate\Support\Facades\DB;
$users = DB::connection('sqlite')->select(/* ... */);
Puoi accedere all’istanza PDO sottostante di una connessione usando il metodo getPdo
su un’istanza di connessione:
$pdo = DB::connection()->getPdo();
Ascoltare gli Eventi delle Query
Se desideri specificare una closure che viene invocata per ogni query SQL eseguita dalla tua applicazione, puoi utilizzare il metodo listen
della facade DB
. Questo metodo può essere utile per registrare le query o per il debug. Puoi registrare la tua closure come listener delle query nel metodo boot
di un service provider:
<?php
namespace App\Providers;
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
DB::listen(function (QueryExecuted $query) {
// $query->sql;
// $query->bindings;
// $query->time;
// $query->toRawSql();
});
}
}
Monitoraggio del Tempo Cumulativo delle Query
Un collo di bottiglia comune nelle applicazioni web moderne è il tempo speso per interrogare i database. Fortunatamente, Laravel può eseguire una closure o un callback a tua scelta quando impiega troppo tempo a interrogare il database durante una singola richiesta. Per iniziare, fornisci una soglia di tempo per le query (in millisecondi) e una closure al metodo whenQueryingForLongerThan
. Puoi invocare questo metodo nel metodo boot
di un service provider:
<?php
namespace App\Providers;
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Events\QueryExecuted;
class AppServiceProvider extends ServiceProvider
{
/**
* Registra i servizi dell'applicazione.
*/
public function register(): void
{
// ...
}
/**
* Avvia i servizi dell'applicazione.
*/
public function boot(): void
{
DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
// Notifica il team di sviluppo...
});
}
}
Transazioni di Database
Puoi usare il metodo transaction
fornito dalla facade DB
per eseguire un insieme di operazioni all’interno di una transazione di database. Se viene lanciata un’eccezione all’interno della closure della transazione, la transazione verrà automaticamente annullata e l’eccezione sarà rilanciata. Se la closure viene eseguita con successo, la transazione verrà automaticamente confermata. Non devi preoccuparti di annullare o confermare manualmente quando usi il metodo transaction
:
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
});
Gestione dei Deadlock
Il metodo transaction
accetta un secondo argomento opzionale che definisce il numero di volte che una transazione deve essere ritentata quando si verifica un deadlock. Una volta esauriti questi tentativi, verrà lanciata un’eccezione:
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
}, 5);
Uso Manuale delle Transazioni
Se vuoi iniziare una transazione manualmente e controllare completamente rollback e commit, puoi usare il metodo beginTransaction
fornito dal facade DB
:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();
Puoi fare il rollback della transazione tramite il metodo rollBack
:
DB::rollBack();
Infine, puoi fare il commit della transazione tramite il metodo commit
:
DB::commit();
I metodi per le transazioni del facade
DB
gestiscono le transazioni sia per il query builder sia per l’Eloquent ORM.
Collegarsi alla CLI del Database
Se desideri connetterti alla CLI del tuo database, puoi utilizzare il comando Artisan db
:
php artisan db
Se necessario, puoi specificare il nome di una connessione al database per connetterti a una connessione diversa da quella predefinita:
php artisan db mysql
Ispezionare i Tuoi Database
Usando i comandi Artisan db:show
e db:table
, puoi ottenere informazioni utili sul tuo database e sulle tabelle associate. Per vedere una panoramica del tuo database, inclusi dimensione, tipo, numero di connessioni aperte e un riepilogo delle sue tabelle, puoi utilizzare il comando db:show
:
php artisan db:show
Puoi specificare quale connessione al database deve essere ispezionata fornendo il nome della connessione tramite l’opzione --database
:
php artisan db:show --database=pgsql
Se desideri includere il conteggio delle righe delle tabelle e i dettagli delle viste del database nell’output del comando, puoi usare rispettivamente le opzioni --counts
e --views
. Su database grandi, ottenere il conteggio delle righe e i dettagli delle viste può essere lento:
php artisan db:show --counts --views
Inoltre, puoi usare i seguenti metodi Schema
per ispezionare il tuo database:
use Illuminate\Support\Facades\Schema;
$tables = Schema::getTables();
$views = Schema::getViews();
$columns = Schema::getColumns('users');
$indexes = Schema::getIndexes('users');
$foreignKeys = Schema::getForeignKeys('users');
Se desideri ispezionare una connessione al database che non è la connessione predefinita della tua applicazione, puoi usare il metodo connection
:
$columns = Schema::connection('sqlite')->getColumns('users');
Panoramica della Tabella
Se vuoi ottenere una panoramica di una singola tabella nel tuo database, puoi eseguire il comando Artisan db:table
. Questo comando fornisce una visione generale di una tabella del database, comprese le colonne, i tipi, gli attributi, le chiavi e gli indici:
php artisan db:table users
Monitorare i Tuoi Database
Utilizzando il comando Artisan db:monitor
, puoi istruire Laravel a inviare un evento Illuminate\Database\Events\DatabaseBusy
se il tuo database gestisce più di un numero specificato di connessioni aperte.
Per iniziare, dovresti pianificare il comando db:monitor
per eseguire ogni minuto. Il comando accetta i nomi delle configurazioni di connessione al database che desideri monitorare, così come il numero massimo di connessioni aperte che dovrebbero essere tollerate prima di inviare un evento:
php artisan db:monitor --databases=mysql,pgsql --max=100
Pianificare solo questo comando non è sufficiente per attivare una notifica che ti avvisi del numero di connessioni aperte. Quando il comando rileva un database che ha un conteggio di connessioni aperte superiore alla tua soglia, verrà inviato un evento DatabaseBusy
. Dovresti ascoltare questo evento all’interno del AppServiceProvider
della tua applicazione per inviare una notifica a te o al tuo team di sviluppo:
use App\Notifications\DatabaseApproachingMaxConnections;
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Event::listen(function (DatabaseBusy $event) {
Notification::route('mail', 'dev@example.com')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}