14 de abril de 2015

Apuntes PDO PHP

PDO proporciona una capa de abstracción de acceso a datos, lo que significa que, independientemente de la base de datos que se esté utilizando, se usan las mismas funciones para realizar consultas y obtener datos. Para cada base de datos existe un manejador (driver) específico, que debe estar habilitado en el archivo de configuración de PHP (el archivo php.ini). Los manejadores se administran mediante extensiones de PHP, las cuales tienen nombres finalizando con dll en Windows y con so en Unix.
extension=php_pdo.dll
extension=php_pdo_firebird.dll
extension=php_pdo_informix.dll
extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
Ejemplo conexiones PDO
<?php
try {
 // Conexión a MS SQL Server 
  $cnn = new PDO("mssql:host=$host;dbname=$dbname, $user, $pass");
  
  // Conexión a Sybase
  $cnn = new PDO("sybase:host=$host;dbname=$dbname, $user, $pass");
 
  // Conexion a MySQL 
  $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
 
  // Conexion a SQLite
  $DBH = new PDO("sqlite:my/database/path/database.db");
}
catch(PDOException $e) {
    echo $e->getMessage();
}
?>
Conexion PDO-MySQL
<?php
try{
        $this->db = new PDO(DB_MOTOR.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $this->db->setAttribute(PDO::ATTR_PERSISTENT,true);
        $this->db->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
   
   }catch(PDOException $e){
         echo 'Ha surgido un error y no se puede conectar a la base de datos' .E_USER_ERROR. PHP_EOL;
         echo "";
         echo "Detalle: ".$e->getMessage();
         exit;
      }
?>
Ejemplo Excepciones PDO
$cnn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$cnn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$cnn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
es mas util la opcion ERRMODE_EXCEPTION, aqui el ejemplo
try {
  $cnn = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
  $cnn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
 
  $cnn->prepare('DELECT name FROM people');
}
catch(PDOException $e) {
    echo "Error en la consulta";
    file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
}
Ejemplo de sentencia SELECT
$sql= "SELECT filmID, filmName, filmDescription, filmImage, filmPrice, filmReview FROM movies WHERE filmID = :filmID"; 
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':filmID', $filmID, PDO::PARAM_INT); 
$stmt->execute();
$obj = $stmt->fetchObject();
echo $obj->filmName;
Ejemplo de Unnamed Placeholders
Es necesario mantener el orden al momento de especificar los valores de la sentencia
<?php
 ini_set('display_errors', '0');
 include_once('connect.php');
 include_once('error_handling.php');

 $team = 'Yamaha';
 $status = 'Factory';

 $sqlQuery = "SELECT * from riders where team = ? AND status = ?";

 $statement = $dbh->prepare($sqlQuery);

 $statement->bindValue('1', $team, PDO::PARAM_STR); 
 $statement->bindValue('2', $status, PDO::PARAM_STR); 

 try{
  $statement->execute();
 }
 catch(PDOException $error){
  echo errorHandling($error);
 }
 while($row = $statement->fetch(PDO::FETCH_ASSOC)) {
  echo $row['name'] . " rides a " . $row['team'] . " " . $row['status'] . " MotoGP bike!
";
 }
?>
Ejemplo de Named Placeholders
No es necesario estar pendiente del orden de los parámetros pero si de especificar adecuadamente el par clave=>valor.
<?php
 ini_set('display_errors', '0');
 include_once('connect.php');
 include_once('error_handling.php');

 $team = 'Yamaha';
 $status = 'Factory';

 $sqlQuery = "SELECT * from riders where team = :team AND status = :status";

 $statement = $dbh->prepare($sqlQuery);

 $statement->bindParam(':team', $team, PDO::PARAM_STR);
 $statement->bindParam(':status', $status, PDO::PARAM_STR);

 try{
  $statement->execute();
 }
 catch(PDOException $error){
  echo errorHandling($error);
 }
 while($row = $statement->fetch(PDO::FETCH_ASSOC)) {
  echo $row['name'] . " rides a " . $row['team'] . " " . $row['status'] . " MotoGP bike!
";
 }
?>
Ejemplo Sentencia INSERT
<?php
$nom = 'Jose';
$ape = 'Hernandez';
 
try
{
  $con = new PDO('mysql:host=localhost;dbname=personal', 'user', 'pass');
  $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
  $stmt = $con->prepare('INSERT INTO personal (nombre, apellidos) VALUES (:nombre, :apellidos)');
  $rows = $stmt->execute( array( ':nombre'   => $nom,
                                    ':apellidos' => $ape));
 
  if( $rows == 1 )
    echo 'Inserción correcta';
}
catch(PDOException $e)
{
  echo 'Error: ' . $e->getMessage();
}
?>
Ejemplo Sentencia UPDATE
<?php
$nom = 'Jose';
$ape = 'Hernandez';
 
try
{
  $con = new PDO('mysql:host=localhost;dbname=personal', 'user', 'pass');
  $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
  $stmt = $con->prepare('UPDATE personal SET apellidos = :apellidos WHERE nombre = :nombre');
  $rows = $stmt->execute( array( ':nombre'   => $nom,
                                    ':apellidos' => $ape));
  if( $rows > 0 )
    echo 'Actualización correcta';
}
catch(PDOException $e)
{
  echo 'Error: ' . $e->getMessage();
}
?>
Ejemplo Sentencia DELETE
<?php
$ape = 'Hernandez';
 
try
{
  $con = new PDO('mysql:host=localhost;dbname=personal', 'user', 'pass');
  $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
  $stmt = $con->prepare('DELETE FROM personal WHERE apellidos = :apellidos');
  $rows = $stmt->execute( array( ':apellidos' => $ape));
 
  if( $rows > 0 )
    echo 'Borrado correcto';
}
catch(PDOException $e)
{
  echo 'Error: ' . $e->getMessage();
}
?>
Mapeo de Objetos
PDO nos permite realizar consultas y mapear los resultados en objetos de nuestro modelo. Para ello primero tenemos que crearnos una clase con nuestro modelo de datos.
<?php
// la clase puede estar en una
// ubicación o folder especifico 

class Usuario{
  private $nombre;
  private $apellidos;
 
  public function nombreApellidos()
  {
    return $this->nombre . ' ' . $this->apellidos;
  }
}
?>
como ejemplo se utilizara una sentencia SELECT, Hay que tener en cuenta que para que funcione correctamente, el nombre de los atributos en nuestra clase tienen que ser iguales que los que tienen las columnas en nuestra tabla de la base de datos. Con esto claro vamos a realizar la consulta.
<?php
try
{
  $con = new PDO('mysql:host=localhost;dbname=personal', 'user', 'pass');
  $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
 $stmt= $con->prepare('SELECT nombre, apellidos FROM personal');
  $stmt->execute();
 
  $stmt->setFetchMode(PDO::FETCH_CLASS, 'Usuario');
 
  while($usuario = $stmt->fetch())
    echo $usuario->nombreApellidos() . '
';
 
}
catch(PDOException $e)
{
  echo 'Error: ' . $e->getMessage();
}
?>
Ejemplo INSERT con Object Mapping
<?php
class person {
    public $name;
    public $addr;
    public $city;
 
    function __construct($n,$a,$c) {
        $this->name = $n;
        $this->addr = $a;
        $this->city = $c;
    }
    # etc ...
}
 
$cathy = new person('Cathy','9 Dark and Twisty','Cardiff');
 
$STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)");
$STH->execute((array)$cathy);
?>
FETCHMODE en consultas SELECT Utilizando query() y PDO::FETCH_NUM
<?php
$sql = 'SELECT name, colour, calories FROM fruit';
try {
  $stmt = $dbh->query($sql);
  $result = $stmt->setFetchMode(PDO::FETCH_NUM);
  while ($row = $stmt->fetch()) {
    print $row[0] . "\t" . $row[1] . "\t" . $row[2] . "\n";
  }
}
catch (PDOException $e) {
  print $e->getMessage();
}
?>
Utilizando query() y PDO::FETCH_ASSOC
<?php
$stmt = $dbh->prepare("SELECT mykey, myvalue FROM mytable");
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$arrValues = $stmt->fetchAll();
foreach ($arrValues as $row){
    print $row["mykey"]." -> ".$row["myvalue"]."
\n";
}
?>
Utilizando query() y PDO::FETCH_OBJ
<?php
$STH = $DBH->query('SELECT name, addr, city from folks'); 

$STH->setFetchMode(PDO::FETCH_OBJ);
 
while($row = $STH->fetch()) {
    echo $row->name . "\n";
    echo $row->addr . "\n";
    echo $row->city . "\n";
}
?>
Utilizando Unnamed Placeholders, execute() y PDO::FETCH_ASSOC
<?php
try {
    $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
 
    $sql = 'SELECT lastname, firstname, jobtitle 
            FROM employees
            WHERE lastname LIKE ?';
 
    $q = $conn->prepare($sql);
    $q->execute(array('%son'));
    $q->setFetchMode(PDO::FETCH_ASSOC);
 
    while ($r = $q->fetch()) {
        echo sprintf('%s 
', $r['lastname']);
    }
} catch (PDOException $pe) {
    die("Could not connect to the database $dbname :" . $pe->getMessage());
}
?>
Utilizando Named Placeholders, execute() y PDO::FETCH_ASSOC
<?php
try {
    $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
 
    $sql = 'SELECT lastname, firstname, jobtitle 
            FROM employees
            WHERE lastname  LIKE :lname OR
                  firstname LIKE :fname';
 
    $q = $conn->prepare($sql);
    $q->execute(array(':fname' => 'Le%',
                      ':lname' => '%son'));
    $q->setFetchMode(PDO::FETCH_ASSOC);
 
    while ($r = $q->fetch()) {
        echo sprintf('%s 
', $r['lastname']);
    }
} catch (PDOException $pe) {
    die("Could not connect to the database $dbname :" . $pe->getMessage());
}
?>
Transacciones en PDO
Debido a que no todas las bases de datos soportan transacciones, PHP corre en el modo de auto-commit que ejecuta cada instrucción individual en forma implícita. Si se desea usar transacciones, y no se desea utilizar el modo de auto-commit, es necesario invocar el método PDO::beginTransaction()al inicio de la transacción. Si el manejador de la base de datos no permite el uso de transacciones se producirá una excepción (PDOException). Cuando se acabe de especificar la transacción se pueden utilizar los métodos PDO::Commit para aplicar dichas instrucciones, o bien, PDO::rollBack para abortar dicha transacción.

<?php
try {
  $stmt = $dbh->prepare("INSERT INTO countries (name, area, population, density)
                                VALUES (:name, :area, :population, :density)");
  $stmt->bindParam(':name', $name);
  $stmt->bindParam(':area', $area);
  $stmt->bindParam(':population', $population);
  $stmt->bindParam(':density', $density);

  $dbh->beginTransaction();
  $name = 'Nicaragua'; $area = 129494; $population = 602800; $density = 46.55;
  $stmt->execute();
  $name = 'Panama'; $area = 78200; $population = 3652000; $density = 46.70;
  $stmt->execute();
  $dbh->commit();

} catch (Exception $e) {
  $dbh->rollBack();
  echo "Failed: " . $e->getMessage();
}
?>
o bien este ejemplo en que se utiliza un array para especificar los valores de la consulta
<?php
try {
  $stmt = $dbh->prepare("INSERT INTO countries (name, area, population, density)
                                VALUES (?, ?, ?, ?)");

  $dbh->beginTransaction();
  $stmt->execute(array('Nicaragua', 129494, 602800, 46.55));
  $stmt->execute(array('Panama', 78200, 3652000, 46.70));
  $dbh->commit();

} catch (Exception $e) {
  $dbh->rollBack();
  echo "Failed: " . $e->getMessage();
}
?>