Query di inserimento (insert)
Le query di inserimento devono sempre utilizzare l’oggetto query builder. Alcuni database richiedono una gestione speciale per i campi LOB (Large OBject, ad esempio TEXT in MySQL) e BLOB (Binary Large OBject), quindi è necessario un livello di astrazione per consentire ai singoli driver di database di implementare qualsiasi gestione speciale di cui abbiano bisogno.
Le query di inserimento vengono avviate utilizzando il metodo insert() nel modo seguente:
$query = $connection->insert('mytable', $options);
Questo crea un oggetto query di inserimento, che inserirà uno o più record nella tabella mytable. Nota che non sono necessarie le parentesi graffe per il nome della tabella, poiché il query builder lo gestirà automaticamente.
L’oggetto query di inserimento utilizza un’API fluente. Cioè, tutti i metodi (tranne execute()) restituiscono lo stesso oggetto query, consentendo di concatenare le chiamate ai metodi. In molti casi questo significa che non è nemmeno necessario salvare l’oggetto query in una variabile.
L’oggetto query di inserimento supporta diversi modelli di utilizzo per soddisfare varie esigenze. In generale, il flusso di lavoro consiste nello specificare i campi in cui inserire i dati, definire i valori che verranno inseriti per quei campi ed eseguire la query. I modelli di utilizzo più comuni e consigliati sono elencati di seguito.
Forma compatta
La forma preferita per la maggior parte delle query di inserimento è la forma compatta:
$result = $connection->insert('mytable')
->fields([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
->execute();
Questo produrrà l’equivalente della seguente query:
INSERT INTO {mytable} (title, uid, created) VALUES ('Example', 1, 1221717405);
Il frammento sopra unisce le parti principali del processo di inserimento.
$connection->insert('mytable')
Questa riga crea un nuovo oggetto query di inserimento per la tabella mytable.
->fields([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
Il metodo fields() accetta diverse forme di parametri, ma la più usata è un array associativo. Le chiavi dell’array sono le colonne della tabella in cui inserire, e i valori sono i corrispondenti valori da inserire. Questo produrrà una singola query di inserimento nella tabella specificata.
->execute();
Il metodo execute() invia la query per l’esecuzione. Se questo metodo non viene chiamato, la query non verrà eseguita.
A differenza degli altri metodi dell’oggetto query di inserimento, che restituiscono lo stesso oggetto query, execute() restituisce il valore del campo auto-increment (tipo sequence in hook_schema()), che è stato popolato dalla query di inserimento, se presente. Ecco perché il valore restituito viene assegnato a $result nell’esempio sopra. Se il campo auto-increment non esiste, il valore restituito da execute() non è definito e non deve essere usato.
In genere questo è il formato preferito per le query di inserimento.
Forma degenerata
$result = $connection->insert('mytable')
->fields(['title', 'uid', 'created'])
->values([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
->execute();
Questo è un equivalente leggermente più dettagliato della query precedente e produrrà esattamente lo stesso risultato.
->fields(['title', 'uid', 'created'])
Quando fields() viene chiamato con un array indicizzato invece di un array associativo, definisce solo i campi (colonne del database) che verranno utilizzati nella query, senza assegnare valori per essi. Questo è utile per costruire una query multipla più avanti.
->values([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
Questa chiamata di metodo imposta un array associativo di nomi di campi con i valori che devono essere inseriti in quei campi. Il metodo values() può anche accettare un array indicizzato. Se viene usato un array indicizzato, l’ordine dei valori deve corrispondere all’ordine dei campi in fields(). Se viene usato un array associativo, l’ordine non è importante. Generalmente l’array associativo è preferito per leggibilità.
Questa forma è usata raramente, poiché la forma compatta è preferibile. Nella maggior parte dei casi l’unico motivo per separare fields() e values() è per eseguire query multiple.
Forma con inserimenti multipli
L’oggetto query di inserimento può anche accettare più set di valori. Cioè values() può essere chiamato più volte per accodare più operazioni di inserimento. Come ciò avverrà dipende dalle capacità del database in uso. Nella maggior parte dei database, più operazioni di inserimento verranno eseguite all’interno di una transazione per maggiore integrità e velocità. In MySQL verrà usata la sintassi multi-valori di INSERT.
$values = [
[
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
],
[
'title' => 'Example 2',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
],
[
'title' => 'Example 3',
'uid' => 2,
'created' => \Drupal::time()->getRequestTime(),
],
];
$query = $connection->insert('mytable')->fields(['title', 'uid', 'created']);
foreach ($values as $record) {
$query->values($record);
}
$query->execute();
Nell’esempio sopra, tre query di inserimento verranno eseguite insieme come un’unica operazione, utilizzando il metodo più efficiente per il driver del database in uso. Nota che qui abbiamo salvato l’oggetto query in una variabile per poter iterare su $values e chiamare più volte il metodo values().
Nel caso degenerato, l’esempio sopra è equivalente a queste tre query:
INSERT INTO {mytable} (title, uid, created) VALUES ('Example', 1, 1221717405);
INSERT INTO {mytable} (title, uid, created) VALUES ('Example2', 1, 1221717405);
INSERT INTO {mytable} (title, uid, created) VALUES ('Example3', 2, 1221717405);
Nota che nelle query con inserimenti multipli il valore restituito da execute() non è definito e non deve essere usato, poiché può variare a seconda del driver del database.
Inserimento dai risultati di una query select
Se vuoi popolare una tabella con i risultati di altre tabelle, puoi fare un SELECT dalle tabelle di origine, scorrere i dati in PHP e inserirli nella nuova tabella, oppure eseguire una query INSERT INTO ... SELECT FROM in cui ogni record restituito dalla query SELECT viene inserito nella query INSERT.
In questo esempio vogliamo costruire la tabella mytable con nid e nome utente per tutti i nodi nel sistema che hanno il tipo page.
<?php
// Costruire la query SELECT.
$query = $connection->select('node', 'n');
// Join con la tabella users.
$query->join('users', 'u', 'n.uid = u.uid');
// Aggiungere i campi che vogliamo.
$query->addField('n','nid');
$query->addField('u','name');
// Aggiungere una condizione per ottenere solo i nodi di tipo page.
$query->condition('type', 'page');
// Eseguire l’inserimento.
$connection->insert('mytable')
->from($query)
->execute();
?>
Valori predefiniti
Normalmente, se non specifichi un valore per un determinato campo e uno è definito dallo schema della tabella, il database inserirà automaticamente il valore predefinito. Tuttavia, in alcuni casi è necessario specificare esplicitamente al database di usare il valore predefinito. Questo include il caso in cui vuoi usare i valori predefiniti per l’intero record. Per farlo esiste il metodo useDefaults().
$query->useDefaults(['field1', 'field2']);
Questa riga indica alla query di usare i valori predefiniti per i campi field1 e field2. Nota che specificare lo stesso campo sia in useDefaults() che in fields() o values() è un errore, e causerà un’eccezione.
$connection->insert() o $connection->query()
Questa è una domanda frequente. (Vedi i commenti in questa pagina.) Qual è la differenza tra insert() e query()?
Nel metodo insert() ogni colonna è specificata come una voce separata nell’array dei campi, e il codice può validare il valore di ogni colonna. Con query() si ha una stringa SQL senza possibilità di validare le singole colonne. Se usi query() con i placeholder, il codice può validare i valori delle colonne, ma i placeholder sono solo un’opzione e non c’è modo di garantire che la tua query SQL non contenga valori non passati attraverso i placeholder.
insert() fa passare la query attraverso un set di hook per consentire ad altri moduli di controllare e modificare le tue query. Questo è il modo corretto di collaborare con altri moduli. query() è leggermente più veloce, perché non passa la query attraverso gli hook. Puoi risparmiare tempo di elaborazione, ma il tuo codice non permetterà ad altri moduli di interagire con le tue query.
insert() funziona più facilmente con altri database e con le future versioni di Drupal.