Salta el contingut

Altres: Bases de Dades

Tractarem com accedir a informació a bases de dades i realitzar funcions bàsiques o necessàries sobre informació en un projecte.

Com a base podeu accedir a la informació oficial o bé w3schools

Normalment usarem una BdD MySQL, tot i que usant PDO ens podem conectar a qualsevol BdD que hi tinguem drivers de conexió.

El llenguatge PHP disposa de dues opcions:

  • mysqli: que pot ser procedimental o objectes i es connecta a una BdD MySQL
  • PDO: que està basada en objectes i ens permet connectar a qualsevol BdD

El SGBDR ens permet treballar com a interfície per a la nostra aplicació PHP i ens permet accedir a la informació guardada a la BdD

Tenim dos conceptes:

  • QUÈ: serà la manera que direm com accedim a la informació. Usant SQL.
  • COM: é sel SGDDR que realitzarà internament l'accés a la informació.

El SQL es divideix en tres blocs:

  • DML: Llenguatge de Manipulació de Dades. Per exemple: SELECT, INSERT, UPDATE, DELETE, ...
  • DDL: Llenguatge de Definició de Dades. Per exemple: CREATE, ALTER, DROP, ...
  • DCL: Llenguatge de Control de Dades. Per exemple: GRANT, REVOKE, ...

Lògica d'accés a la informació d'una BdD

De manera bàsica farem:

- Conexió a una BdD, indicant servidor, usuari, contrasenya i BdD
- Preparar sentència SQL
- Executar sentència SQL
- Si hem fet SQL SELECT
    - Recollim informació
    - Acció amb la informació
- Tancar conexió

Si usem PDO, tindrem 3 classes definides:

  • PDO: Conexió entre PHP i la BdD
  • PDOException: Control de les excepcions ocorregudes
  • PDOStatement: Consulta preparada, executem i resultat obtingut.

Conexió a una BdD

Usant MySQLi

<?php
    $servername = "localhost";
    $username = "username";
    $password = "password";

    // Create connection
    $conn = mysqli_connect($servername, $username, $password);

    // Check connection
    if (!$conn) {
      die("Connection failed: " . mysqli_connect_error());
    }
    echo "Connected successfully";
?>

Usant PDO

<?php
    $servername = "localhost";
    $username = "username";
    $password = "password";

    try {
      $conn = new PDO("mysql:host=$servername;dbname=myDB", $username, $password);
      // set the PDO error mode to exception
      $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      echo "Connected successfully";
    } catch(PDOException $e) {
      echo "Connection failed: " . $e->getMessage();
    }
?>

Executar una sentència simple

Podem executar i obtenir els resultats d'una sentència SQL simple de manera ràpida i fàcil amb PDO->query()

$SQL = "SELECT * FROM CLients ORDER BY Nom";
$rst = $conn->query($SQL);

Ens retorna un array de resultats.

* NOTA
L'execució d'una sentència SQL amb query no controla la injectació d'atacs SQL

Si que ho podrem controlar millor amb `prepare()` i `execute()`.

També podem usar PDO->exec(), executa una sentència i ens retorna el número de resgistres.

$SQL = "DELETE FROM CLients WHERE id=3";
$count = $conn->exec($SQL);
echo "$count registres eliminats";

Ens anirà molt bé per executar consultes SQL que no retornin específicament resultats d'una SELECT, per exemple sentències DDL, com CREATE TABLE.

Preparar una sentència SQL

La classe PDOStatement és la que usarem per tractar les sentències SQL.

Una instància de la classe PDOStatement es crea quan es crida a PDO->prepare().

Associem els paràmetres amb bindparam() i tot seguit execute().

Amb això obtenim millora del rendiment i seguretat en la consulta. Per exemple evitar injectació de SQL per part de robots en accés a formularis web.

Preparar -> Associar valors -> Executar

un exemple:

$SQL = "SELECT * FROM Alumnes WHERE DNI=:DNI";
$rst = $conn->prepare($SQL);
$DNI = "40000000-A";
$rst->bindparam(":DNI",$DNI);
$rst->execute();

bindparam() tant ens permet utilitzar ? com :variable

$SQL = "INSERT INTO Alumnes (DNI,Nom) VALUES (?,?)";
$rst = $conn->prepare($SQL);
$DNI = "40000000-A";
$Nom = "Laia Bosch";
$rst->bindparam(1,$DNI);
$rst->bindparam(2,$Nom);
$rst->execute();

També ens permet passar un array de valors:

$SQL = "INSERT INTO Alumnes (DNI,Nom) VALUES (:DNI,:Nom)";
$rst = $conn->prepare($SQL);
$DNI = "40000001-B";
$Nom = "Maria Soler";
$rst->execute(array(':DNI'=>$DNI,':Nom'=>$Nom));

Podem usar tant:

- bindParam(): la variable s'enllaça com una referència i només s'avalua quane s crida execute().
- bindValue(): la variable s'enllaça al valor fins que s'eceuta la sentència amb execute().

Consultar dades

Una vegada s'ha executat la consulta s'obté el resultat de la mateixa.

Per fer-ho usem fetch. Això ens retorna un registre amb les dades obtingudes de la consulta SQL.

Cal indicar com obtenim l'array de dades:

  • PDO::FETCH_ASSOC: torna un array indexat amb les claus dels noms de les columnes de la taula de la bdd.
  • PDO::FETCH_NUM: torna un array indexat on la clau són números de posició.

Tenim més formes d'obtenir els resultats

llavors només cal recorrer l'array obtingut

$SQL = "SELECT * FROM CLients ORDER BY Nom";
$rst = $conn->query($SQL);
while ($row = $rst->fetch())
    echo $row["DNI"] . " - " . $row["Nom"];

Un exemple d'usar retorn d'un objecte

$SQL = "SELECT * FROM CLients ORDER BY Nom";
$rst = $conn->query($SQL);
while ($row = $rst->fetch(PDO::FETCH_OBJ))
    echo $row->DNI . " - " . $row->Nom;

Si volem obtenir tots els registres usarem fetchAll(). Ara obtindrem tots els registres i haurem de recorrer l'array obtingut

$SQL = "SELECT * FROM CLients ORDER BY Nom";
$rst = $conn->query($SQL);
$clients = $rst->fetchAll()
foreach($clients as $client)
    echo $client["DNI"] . " - " . $client["Nom"];

Transaccions

Les transaccions ens permeten controlar l'execució de diverses sentències agrupades de SQL i que ens cal que cap d'elles ens retorni errada. Ens permetrà desfer-les totes en cas d'errada o confirma-les si totes han anat bé.

Una transacció s'inicia amb PDO::beginTransaction()

Validem totes les sentències SQL executades amb PDO::commit()

Desfem totes les sentències SQL executades amb PDO::rollback()

Per tant podem controlar la integritat de les dades segons s'haginpogut executar totes les sentències SQL correctment o no.

Usarem el try - catch per controlar la transacció.

try
{
    $conn->beginTransaction();
    $conn->query($SQL1);
    $conn->query($SQL2);
    $conn->query($SQL3);
    ...
    $conn->commit();
    echo "Sentències SQL correctes";
}
catch (Exception $e)
{
    $conn->rollback();
    echo "Hi ha hagut alguna errada";
}