72 PDO 2
Rielaboriamo la pagina precedente creando registra_dati_questionario_PDO.php. Effettuiamo la conessione:
try { $conn = new PDO("mysql:host=localhost;dbname={$accessData['dbname']}", $accessData['username'],$accessData['password']); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Connessione al server fallita. Impossibile procedere. Contattare ..."; die(); }
Mentre per la connessione possiamo sfruttare il try e il catch, per gli altri comandi dobbiamo attivare il supporto alle eccezioni. Per far questo sobbiamo attivare il metodo setAttribute sul nostro oggetto PDO ($conn):
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
L’attributo che ci interessa è ERRMODE cioè la modalità di gestione degli errori, una collezione di costanti predefinite all’interno della classe PDO. Il secondo attributo, ERRMODE_EXCEPTION, è la gestione delle eccezioni degli errori. Continuiamo il codice con la query di inserimento dati nella tabella questionario:
$data_oggi = date("Y-m-d"); $comandoSQL = "insert into questionari values (null, " . $conn->quote($_POST['descrizione']) . ", " . "'" . $data_oggi . "', " . "'" . $_SESSION['iduser'] . "')";
L’unica diversità dalla precedente versione è la protezione dei SQL injection con il metodo quote. Siamo pronti per lanciare il comando e lo faremo con un costrutto try / catch:
try { $conn->query($comandoSQL); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Inserimento fallito ..."; die(); }
a questo punto se sbagliassimo, per esempio, il nome di una tabella, l’exception degli errori ci avviserebbe chiaramente sull’errore commesso.
Andiamo ora a recuperare l’ultimo id inserito col metodo PDO:
$idQuestionario = $conn->lastInsertId();
lastInsertId recuera l’ltimo id col metodo PDO. Ora possiamo usare i prepared statments con la classe PDO
$conn->prepare("insert into items values (null, ?, ?)");
La sintassi del binding è simile :
$comando_prepared->bindParam(1, $fkQuestionario, PDO::PARAM_INT); $comando_prepared->bindParam(2, $fkDomanda, PDO::PARAM_INT);
Il metodo di PDO per i prepared statments è bindParam, gli argomenti sono il primo parametro, la variabile collegata ($fkQuestionario), e a differenza del procedurale dove inserivo i per intero, qui bisogna specificare PDO::PARAM_INT , per le stringhe bisogna specificare anche la lunghezza.
Ora recuperiamo le domande scelte sui checkbox della form e generiamo un ciclo for con il codice questionario sempre uguale e il codice della domanda che varia
$domande = $_POST['domande_scelte']; for($i=0; $i<count($domande); $i++) { $fkQuestionario=$idQuestionario; $fkDomanda=$domande[$i];
Eseguimo la query sempre con la gestione delle eccezioni e il comando execute:
try { $comando_prepared->execute(); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Inserimento fallito ...";try { //allora eliminiamo il questionario $conn->query("delete from questionari where idquestionario=$idQuestionario"); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Impossibile eliminare ..."; } die(); }
Dovesse fallire l’inserimento nella tabella items, bisogna provvedere anche all’eliminazione dei dati inseriti nella tabella questionario
$conn->query("delete from questionari where idquestionario=$idQuestionario");
Nel caso fallisse la cancellazione del questionario, riceverò un doppio messaggio di errore (una doppia eccezione), una per il fallimento items e una per il fallimento cancellazione questionario. Da notare l’annidamento doppio delle eccezioni try / catch.
Esiste un secondo metodo per usare i prepared statments coi PDO che è leggermente più facile, perché utilizza il nome del nostro segnaposto::
$comando_prepared = $conn->prepare("insert into items values (null, :fkQuestionario, :fkDomanda)");
e la analoga variante del binding:
$comando_prepared->bindParam(':fkQuestionario', $fkQuestionario , PDO::PARAM_INT); $comando_prepared->bindParam(':fkDomanda', $fkDomanda, PDO::PARAM_INT);
Come si può notare si usano i nomi dei campi da popolare.
Di seguito il codice completo di tutta la pagina:
<?php include($_SERVER['DOCUMENT_ROOT']."/fagtest/my_include/setup_con_DB.php");if ( !isset($_SESSION['iduser']) ) { header("Location: login.php?errore=autenticazione_richiesta"); //user non autenticato exit; } try { //CONNESSIONE $conn = new PDO("mysql:host=localhost;dbname={$accessData['dbname']}", $accessData['username'],$accessData['password']); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Connessione al server fallita. Impossibile procedere. Contattare ..."; die(); } //ATTIVAZIONE ECCEZIONI PER METODO QUERY $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //prima inseriamo la riga del questionario nella tabella questionari $data_oggi = date("Y-m-d"); $comandoSQL = "insert into questionari values (null, " . $conn->quote($_POST['descrizione']) . ", " . "'" . $data_oggi . "', " . "'" . $_SESSION['iduser'] . "')"; try { $conn->query($comandoSQL); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Inserimento fallito ..."; die(); } $idQuestionario = $conn->lastInsertId(); //PREPARED STATEMENTS //$comando_prepared = //$conn->prepare("insert into items values (null, ?, ?)"); $comando_prepared = $conn->prepare("insert into items values (null, :fkQuestionario, :fkDomanda)"); //binding segnaposto ? con rispettive variabili //$comando_prepared->bindParam(1, $fkQuestionario, PDO::PARAM_INT); //$comando_prepared->bindParam(2, $fkDomanda, PDO::PARAM_INT); $comando_prepared->bindParam(':fkQuestionario', $fkQuestionario , PDO::PARAM_INT); $comando_prepared->bindParam(':fkDomanda', $fkDomanda, PDO::PARAM_INT);//recuperiamo le domande scelte sulla form $domande = $_POST['domande_scelte']; for($i=0; $i<count($domande); $i++) { $fkQuestionario=$idQuestionario; $fkDomanda=$domande[$i]; try { $comando_prepared->execute(); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Inserimento fallito ..."; try { //allora eliminiamo il questionario $conn->query("delete from questionari where idquestionario=$idQuestionario"); } catch (PDOException $e) { echo $e->getMessage() . "<br/>"; echo "Impossibile eliminare ..."; } die(); } } //CHIUDIAMO LA CONNESSIONE E LIBERIAMO LE RISORSE OCCUPATE ... $conn=null; /* if ($esito) $idQuestionario = mysqli_insert_id( $conn ); else { mysqli_close($conn); header("Location: login.php?errore=inserimento_fallito"); //inserimento fallito }//per gli N insert into per la tabella degli items conviene usare //i prepared statement $comando_prepared = mysqli_prepare($conn, "insert into items values (null, ?, ?)"); //i=intero, d=double, s=stringa mysqli_stmt_bind_param($comando_prepared, "ii", $fkQuestionario, $fkDomanda); $domande = $_POST['domande_scelte']; for($i=0; $i<count($domande); $i++) { $fkQuestionario=$idQuestionario; $fkDomanda=$domande[$i]; mysqli_stmt_execute($comando_prepared); } mysqli_stmt_close($comando_prepared); mysqli_close($conn); */ ?>