L'insertion de nouveaux objets se fait en 3 étapes :
Il est également possible d'insérer plusieurs objets provenant d'une requête SELECT, soit
en les récupérant pour les modifier avant, soit
directement.
Création d'un nouvel objet
<?php
$obj = new MonObjet();
$obj->champ1 = ...;
$obj->champ2 = ...;
Il est important de créer un nouvel objet pour chaque ligne que l'on souhaite insérer.
Réutiliser un objet existant ne fonctionnera pas car l'objet aura un état interne incompatible avec une requête d'insertion.
On doit donner une valeur à tout les champs qui ne sont pas
nullable et pour lesquels il n'y a pas d'insertion automatique
comme avec une colonne en AUTO_INCREMENT ou un champ de type TIMESTAMP.
Les valeurs sont celles des objets PHP, c'est la requête qui s'occupera de la conversion :
- Les champs de type BOOLEAN doivent avoir pour valeur TRUE ou FALSE
- Les champs de type DATE doivent avoir pour valeur un timestamp UNIX (type PHP de représentation des dates dans SALT)
- Les champs de type NUMBER ou TEXT peuvent avoir pour valeur des nombres ou des chaînes de caractères, PHP n'étant pas un langage fortement typé
Création d'une requête d'insertion
<?php
$insertQuery = new InsertQuery($obj);
On peut également passer un tableau d'objet au constructeur, dans ce cas là on inserera tout les objets dans la même
requête INSERT, mais ils doivent tous être de la même classe.
Les valeurs de l'objet sont récupérées dans le constructeur de
InsertQuery. Une modification sur l'objet après la construction de
la requête sera donc sans effet :
<?php
$obj->champ1 = 'A';
$insertQuery = new InsertQuery($obj);
$obj->champ1 = 'B'; // ignoré
// La requête générée inserera la valeur 'A' pour champ1
Exécution de la requête
<?php
$resultat = $db->execInsert($insertQuery);
execInsert renvoi la valeur de
PDO::lastInsertId(), c'est à dire la dernière valeur utilisée d'une séquence
lors de l'insertion. Si la table a une colonne en AUTO_INCREMENT, ce sera la valeur insérée. Dans le cas où plusieurs objets ont
été inserés, il s'agit de la dernière valeur uniquement.
Si la requête d'insertion échoue totalement ou partiellement et que le nombre de lignes insérées est différent du nombre d'objets
passés en paramètre, la méthode levera une exception de type
RowCountException qui contient le nombre de ligne
insérées, le nombre de ligne attendues ainsi que le texte de la requête préparée.
Insertion depuis un SELECT
Le paramètre
$bindingObject de
execQuery() permet d'utiliser le résultat d'une requête pour construire de
nouveaux objets, ce qui est un moyen de réaliser l'équivalent d'une requête INSERT...SELECT avec la possibilité de modifier les
objets en PHP avant l'insertion.
L'exemple ci-dessous montre comment ajouter un nouvel objet Person pour chaque City existante :
<?php
// On construit une requête qui va avoir pour résultat une liste de champ compatibles avec l'objet Person
$q = City::query();
$q->select(SqlExpr::_CONCAT('Habitant de ', $q->city_name), 'person_name');
$q->selectField('id', 'city'); // l'ID d'une ville est stocké dans le champ Person->city
echo $q->toSQL().'<br/>'; // affiche SELECT CONCAT('Habitant de ', t1.city_name) as person_name, t1.id as city FROM city t1
$r = $DBtest->execQuery($q, NULL, Person::singleton()); // execution, mais mapping du résultat dans des objets Person
foreach($r->data as $row) {
echo get_class($row).'<br/>'; // affiche 'Person' au lieu de 'City'
echo 'IS NEW ? '.$row->isNew().'<br/>'; // renvoi TRUE pour chaque objet
echo 'Name : '.$row->person_name.'<br/>';
}
$i = new InsertQuery($r->data); // Les objets étant nouveaux, on peut les utiliser dans une requête d'insertion
$DBtest->execInsert($i); // va générer la requête :
// INSERT INTO person (person_name, city) VALUES
// ('Habitant de Bordeaux', 2),
// ('Habitant de Boston', 6),
// ('Habitant de Lyon', 3),
// ('Habitant de New York', 5),
// ('Habitant de Paris', 1),
// ('Habitant de Toulouse', 4)
INSERT ... SELECT
Il est également possible de réaliser directement un INSERT INTO ... SELECT en indiquant la requête dans le 2ème paramètre du constructeur de InsertQuery :
<?php
$q = City::query();
$q->select(SqlExpr::_CONCAT('Habitant de ', $q->city_name), 'person_name');
$q->selectField('id', 'city'); // l'ID d'une ville est stocké dans le champ Person->city
$i = new InsertQuery(Person::singleton(), $q); // Le 1er paramètre donne juste le type d'objet a insérer. Le 2ème paramètre est la requête SELECT.
$DBtest->execInsert($i); // va générer la requête :
// INSERT INTO person (`person_name`, `city`)
// SELECT CONCAT('Habitant de ', t1.city_name) as `person_name`, t1.id as `city`
// FROM city t1