PDO: PHP Data Objects

PDO es una interfaz de acceso a datos orientada a objetos que nos permite, mediante varios drivers, conectarnos a diferentes bases de datos. Esta librería, escrita en C, viene activada por defecto desde PHP 5.1 por lo cual la podemos utilizar en la mayoría de los servidores que actualmente soportan PHP5.

Más información

http://docs.php.net/manual/es/book.pdo.php

Soporta la mayoría de bases de datos (SQL Server, Oracle, MySQL, PostgreSQL,...)

http://docs.php.net/manual/es/pdo.drivers.php

Vamos a ver cada una de las funciones que usaremos para trabajar con PDO.

**Conexión a bases de datos**

En PDO se usa los _data source name_ (nombre de la fuente de datos) para realizar la conexión a la base de datos seleccionada (similar a PEAR::DB)

Seleccionar el driver de la conexión (mysql, sqlite, pgsql)

class PDO {
   __construct( string $dsn [, string $username
      [, string $password [, array $dri- ver_options ]]] )
}

Ejemplo de conexión usando el driver de mysql

<?php
   $db = new PDO (‘mysql:host=localhost;dbname=uazon’, ‘comprador’, ‘proweb2013’);
?>

Como vemos en el ejemplo es muy similar a la creación de conexiones usando MySQLI orientado objetos.

Veamos un ejemplo de conexión incorrecta:

<?php
   $db = new PDO('mysql:host=localhost;dbname=uazon', '', '');
?>

Resultado

PDOException: SQLSTATE[42000] [1044]
   Access denied for user ''@'localhost' to database 'uazon' in
   C:\wamp\www\sesion11\pdo1.php on line 7

Como vemos, el intento de creación de una nueva conexión ha lanzado una excepción de tipo PDOException, por lo que podríamos envolver el intento de conexión en un try-catch y capturar las posibles excepciones que se produzcan.

Como veremos más adelante podemos definir diferentes modos de error, como son el modo advertencia (Warning), modo excepción o modo silencioso. Nosotros trabajaremos con el modo excepción para tener un control más profesional sobre los errores que se produzcan y sobretodo registrarlos para depurar.

Ejemplo de creación de una nueva conexión envuelta en un bloque try-catch

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);
   echo "Conexion realizada correctamente";
}
catch (PDOException $pdoe)
{
   echo($pdoe->getMessage());
}
?>

**Cerrar una conexión**

Para desconectar con la base de datos hay que destruir el objeto PDO. Si no se destruye dicho objeto, PHP lo destruirá al terminar el script. Lo recomendable es eliminar la instancia de conexión de forma implícita cuando hayamos terminado de usarla o si se ha producido algún error.

Veamos un ejemplo:

....
try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);
   echo "Conexion realizada correctamente";
   $db = null;
}
catch (PDOException $pdoe)
{
   echo($pdoe->getMessage());
}

**Consultas: método query()**

Para realizar consultas a la base de datos, disponemos de los métodos **query()** para consultas SELECT y el método **exec()** para consultas de inserción, borrado y actualización.

El método **query()** ejecuta la consulta pasada como parámetro y devuelve un objeto de tipo **PDOStatement**. Esta clase implementa la interfaz **Traversable** (las propiedades de un objeto de esa clase pueden ser mostrados mediante un foreach) y representa una sentencia preparada que después de ejecutarla devuelve un resultado asociado.

Por temas de compatibilidad con otras bases de datos, se recomienda no usar la devolución del número de filas de la clase PDO.

Veamos su definición:

class PDO {
   PDOStatement query ( string $statement )
}

Como hemos comentado anteriormente se usa para consultas de tipo SELECT.

Ejemplo

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';
                 dbname='. $bd, $user, $pwd);

   $result = $db->query('SELECT titulo FROM libros');

   while ($libro = $result->fetch()) {
      echo 'TITULO: ' . $libro['titulo'] . '<br />';
   }
   $db=null;
}
catch (PDOException $pdoe)
{
   echo($pdoe->getMessage());
}
?>

Como vemos en el ejemplo es muy parecido a la interfaz **PEAR::DB** y a la metodología orientada a objetos de la librería de conexión MySQLI.

Cabe destacar que como no tenemos el método para obtener el número de filas usaremos un bucle while para recorrer la tupla de resultados y mostrarlo por pantalla. Por ejemplo:

while ($libro = $result->fetch()) {
   echo 'TITULO: ' . $libro['titulo'] . '<br />';
}

Para obtener más información sobre el método query accede al siguiente enlace: http://docs.php.net/manual/es/pdo.query.php

**Consultas: método exec()**

El método exec() ejecuta la consulta pasada como parámetro y devuelve el número de filas afectadas.

Como hemos comentado anteriormente se usa para consultas de tipo INSERT, UPDATE y DELETE.

class PDO {
   int exec ( string $statement )
}

Veamos un ejemplo de uso:

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';
try
{
   $db = new PDO('mysql:host='.$servidor.';
                  dbname='. $bd, $user, $pwd);

   $isbn = 123456789;
   $titulo = 'Zen to Done';
   $n_pags = 150;
   $precio = 10.99;
   $fk_editoriales = 8; //Editorial Alfaguara

   $consulta =
      "INSERT INTO libros(isbn, titulo, n_pags, precio, fk_editoriales)" .
      " VALUES ($isbn, '$titulo', $n_pags, $precio, $fk_editoriales)";

   $affectedRows = $db->exec($consulta);

   echo "Libros insertados: $affectedRows";
   $db=null;
}
catch (PDOException $pdoe)
{
   echo($pdoe->getMessage());
}
?>

Este ejemplo inserta el libro "Zen to done" en la tabla libros. **Ojo**, la editorial con identificador "8" debe existir en la base de datos si no nos daría un error de integridad referencial (clave ajena no existente). Más adelante veremos el nivel de errores que podemos activar.

**Métodos de obtención de datos (Métodos Fetch) **

Como hemos comentado anteriormente, el método **query()** devuelve un objeto de tipo **PDOStatement**. Dentro de dicha clase tenemos un método genérico para obtener ("_traer_" - fetch) cada una de las filas que contiene la tupla de resultados, muy similar al utilizado por la librería MySQLI.

El método propio fetch de la clase PDOStatemente devolverá la fila actual apuntada por el cursor desplazable y moverá dicho cursor a la siguiente fila. Por ejemplo, podemos obtener un objeto, equivalente al fetch_object() de MySQLI o un array asociativo con fecth_assoc.

Como disponemos de varios tipos de "fetch", la clase **PDOStatement** nos proporciona el método **setFetchMode()** para establecer por defecto el método de obtención de resultados. Más adelante veremos un ejemplo de uso de dicho método.

Veamos a continuación la definición del método **fetch** de la clase **PDOStatement**:

class PDOStatement implements Traversable {
   mixed fetch ([ int $fetch_style = PDO::FETCH_BOTH
      [, int $cursor_orientation = PDO::FETCH_ORI_NEXT
      [, int $cursor_offset = 0 ]]] )
}

El valor devuelto por este método depende del tipo de **fetch** utilizado (arrray, objeto, etcétera). En cualquier caso, devolverá **FALSE** en caso de fallo.

El método **fetch** recibe 3 parámetros opcionales que son:

  • fetch_style tipo de fetch. Por defecto se inicializa a PDO::FETCH_BOTH , devolviendo un array indexado de forma numérica y asociativa. Hay varios tipos de "fetch" aunque nosotros sólo veremos los que son similares a los utilizados por la librería MySQLI: PDO::FETCH_ASSOC , PDO::FETCH_NUM y PDO::FETCH_OBJ PDO::FETCH_BOTH es una constante predefinida de PDO. Para ver todas la constantes visitar el siguiente enlace http://docs.php.net/manual/es/pdo.constants.php

  • cursor_orientation: determina la fila que va devolver el cursor (scrollable cursor

  • cursor desplazable) que recorrerá la tupla de resultados. Por defecto, se inicializa a PDO::FETCH_ORI_NEXT que devuelve la fila siguiente de dicho cursor. Acceder a la siguiente URL http://docs.php.net/manual/es/pdo.constants.php para visualizar las diferentes tipos de constantes a la hora de definir la orientación del cursor.

  • offset: especifica el desplazamiento a la hora de mover el cursor. Por defecto se inicializa a 0.

Para ver más detalles sobre los parámetros que recibe la función fetch() acceder al manual de PHP desde la siguiente URL:http://docs.php.net/manual/es/pdostatement.fetch.php

Si mostramos la información que contiene la variable libro justo después de obtener la fila:

...
while ($libro = $result->fetch()) {
   echo 'TITULO: ' . $libro['titulo'] . '<br />';
   var_dump($libro);
   break;
}
...

Obtenemos:

array
   'titulo' => string 'Anna Karenina' (length=13)
   0 => string 'Anna Karenina' (length=13)

Como vemos en el resultado del ejemplo, tenemos un array indexado de forma numérica y asociativa. Es lo que nos devuelve el método fetch por defecto. Podríamos suponer que internamente realiza un fetch_assoc() y fetch_row(), funciones que ya hemos visto en sesiones anteriores.

Veamos ahora los 3 tipos de fetch similares a los que hemos utilizado con MySQLI.

**Tipo PDO::FETCH_ASSOC**

Se utiliza para obtener un array indexado de forma asociativa. Es el método más utilizado pues equivale al método fetch_assoc() de las librerías MySQL y MySQLI

La forma de utilizarlo es establecer el parámetro **fetch_style** a **PDO::FETCH_ASSOC**. Veamos un ejemplo:

...
$stmt = $db->query('SELECT titulo FROM libros');
while ( $libro = $stmt->fetch (PDO::FETCH_ASSOC) ) {
   echo 'TITULO: ' . $libro['titulo'] . '<br />';
}
...

Si volcamos la información del array $libro con la función var_dump() obtenemos:

array
   'titulo' => string 'Anna Karenina' (length=13)

**Tipo PDO::FETCH NUM**

Para obtener un array indexado de forma numérica utilizaremos **PDO::FETCH_NUM**.

Veamos un ejemplo:

...
$stmt = $db->query('SELECT titulo FROM libros');
while ($libro = $stmt->fetch ( PDO::FETCH_NUM ) ) {
   echo 'TITULO: ' . $libro[0] . '<br />';
}
...

Si volcamos la información del array $libro con la función var_dump() obtenemos:

array
   0 => string 'Anna Karenina' (length=13)

**Tipo PDO::FETCH OBJECT**

Para obtener un objeto utilizaremos PDO::FETCH_OBJ.

Veamos un ejemplo:

...
$stmt = $db->query('SELECT titulo FROM libros');
while ($libro = $stmt->fetch ( PDO::FETCH_OBJ ) ) {
   echo 'TITULO: ' . $libro->titulo . '<br />';
}
...

Si volcamos la información del array $libro con la función var_dump() obtenemos:

object(stdClass)[3]
public 'titulo' => string 'Anna Karenina' (length=13)

**Establecer el método fetch por defecto**

Podemos establecer por defecto el tipo de fecth para el objeto **PDOStatement** mediante el método **setFetchMode().** Ojo, sólo funcionará para ese objeto, no para los creados a posteriori.

Veamos la definición de dicho método:

class PDOStatement implements Traversable {
   bool setFetchMode ( int $mode )
   bool setFetchMode ( int PDO::FETCH_COLUMN , int $colno )
   bool setFetchMode ( int PDO::FETCH_CLASS , string $classname , array $ctorargs )
   bool setFetchMode ( int PDO::FETCH_INTO , object $object )
}

Veamos un ejemplo:

...
$stmt = $db->query ('SELECT titulo FROM libros');
$stmt->setFetchMode ( PDO::FETCH_ASSOC );
while ( $libro = $stmt->fetch () ) {
   echo 'TITULO: ' . $libro['titulo'] . '<br />';
}
...

Para saber más sobre dicho método accede al siguiente enlace: http://docs.php.net/manual/es/pdostatement.setfetchmode.php

**Gestión de errores**

Como hemos comentado anteriormente disponemos de tres tipos de modo de gestión de errores:

  • Modo Silencioso -> PDO::ERRMODE_SILENT(por defecto)

  • Modo Advertencia -> PDO::ERRMODE_WARNING

  • Modo Excepción -> PDO::ERRMODE_EXCEPTION

Antes de ver cada uno de los modos vamos a hablar del método **setAttribute ()** del objeto PDO, que nos permite establecer el valor de cualquiera de los atributos propios de la clase PDO. Nosotros la vamos a utilizar para establecer el modo de error.

Esta es su definición:

class PDO {
   bool setAttribute ( int $attribute , mixed $value )
}

Un ejemplo de cómo establecer la gestión de errores en el modo Excepción (**PDO::ERRMODE_EXCEPTION**) sería:

...
$db = new PDO ('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

//establecemos el modo de errores a Excepciones
$db->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

// Establecemos el formato de los nombres de las columnas devueltas por el cursor
//PDO::ATTR_CASE: Fuerza los nombres de columna a un caso concreto
//PDO::CASE_NATURAL: Deja los nombres de las columnas que devuelve

// el controlador de base de datos
$db->setAttribute ( PDO::ATTR_CASE, PDO::CASE_NATURAL);
...

Más información sobre los atributos y sus posibles valores, en esta dirección

http://docs.php.net/manual/es/pdo.setattribute.php

Vamos a ver continuación cada uno de los modo detenidamente.

**PDO::ERRMODE_SILENT**

Este el modo por defecto. PDO establecerá un código de error que podemos inspeccionar usando los métodos PDO::errorCode() y PDO::errorInfo()

Versión sin controlar el error

<?php
   $servidor = 'localhost';
   $bd = 'uazon';
   $user = 'comprador';
   $pwd = 'proweb2013';
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

   //SQL incorrecto
   $result = $db->query('SELECT titulo FROM libro');
   while ($libro = $result->fetch()) {
      echo 'TITULO: ' . $libro['titulo'] . '<br />';
   }
   $db=null;
?>

Resultado

Fatal error: Call to a member function fetch() on a non-object in
   C:\wamp\www\sesion11\ejemplos\ejemplo_pdo_modo_silencio.php on line 21

Como vemos se produce un error fatal porque tratamos la variable **$result** como un objeto ($result->fetch() ) y realmente es una variable de tipo booleano siendo su valor FALSE. No tiene sentido envolver el código dentro de un try-catch ya que no lanzamos de forma explícita ninguna excepción por lo que lo eliminamos para no añadir más ruido al anterior ejemplo.

Vamos a ver la versión con la captura del error:

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';
try
{
  $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);
  $result = $db->query ('SELECT titulo FROM libro');
  if ($result === false) {
     throw new PDOException( );
  }
  while ($libro = $result->fetch()) {
     echo 'TITULO: ' . $libro['titulo'] . '<br />';
  }
  $db=null;
}
catch (PDOException $pdoe)
{
  echo $pdoe->getMessage().'<br />';
  if (isset($db)) {
     echo 'ErrorCode: ' . $db->errorCode();
     var_dump($db->errorInfo());
     $db=null;
  }
}
?>

Resultado:

SQL INCORRECTO
ErrorCode: 42S02
array
0 => string '42S02' (length=5)
1 => int 1146
2 => string 'Table 'uazon.libro' doesn't exist' (length=37)

En este ejemplo sí que tiene sentido envolver todo el código susceptible a provocar un error en un try-catch, ya que, vamos a lanzar una excepción de forma explícita si la consulta SQL es incorrecta:

...
$result = $db->query ('SELECT titulo FROM libro');
if ($result === false) {
   throw new PDOException("SQL INCORRECTO ");
}
...

Destacar el triple igual ("===") en la instrucción if en el método **query()**. Esto es debido a que dicho método devuelve un variable de tipo _mixto_ (mixed), por lo que si la consulta es incorrecta, en la variable $result se almacenará un booleano con valor FALSE.

**PDO::ERRMODE_WARNING**

En este nivel de error, además de establecer un código de error, PDO emitirá un mensaje E_WARNING. Esta característica es ideal para realizar debug/test si queremos visualizar los problemas que ocurren sin interrumpir la ejecución de la aplicación.

Ejemplo

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
  $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

  /*** establecemos el nivel de errores a ERRMODE_WARNING ***/
  $db->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );

  $result = $db->query('SELECT titulo FROM libro');

  if ($result === false) {
     throw new PDOException("SQL INCORRECTO ");
  }

  while ($libro = $result->fetch()) {
     echo 'TITULO: ' . $libro['titulo'] . '<br />';
  }
}
catch (PDOException $pdoe)
{
  echo $pdoe->getMessage() ;
  echo $db->errorCode();
  var_dump($db->errorInfo());
}
if (isset($db))
  $db=null;
?>

Resultado

Warning: PDO::query() [pdo.query.php]: SQLSTATE[42S02]: Base table
   or view not found: 1146 Table 'uazon.libro' doesn't exist in
   C:\wamp\www\sesion11 \ejemplo_pdo_modo_warning.php on line 13

SQL INCORRECTO
ErrorCode: 42S02
array
0 => string '42S02' (length=5)
1 => int 1146
2 => string 'Table 'uazon.libro' doesn't exist' (length=37)

Vemos que se lanza una advertencia bastante explicativa del error, aunque debemos de comprobar explícitamente que el objeto **$result** sea correcto porque sino obtendríamos un error fatal al tratar una variable de tipo boolean como un objeto.

**PDO::ERRMODE_EXCEPTION**

Además de establecer un código de error, PDO lanzará una **PDOException** estableciendo el código y la información de dicho error. Esta característica es muy útil mientras realizamos debug, ya que, localizamos más rápidamente los puntos que provocan errores potenciales (recordemos que las transacciones serán canceladas si alguna excepción provoca la terminación de un script PHP)

El modo Excepción es muy útil porque tendremos un gestor de errores mucho más potente que el tradicional estilo de advertencias. Además tendremos mucho menos código que en el modo silencioso, ya que, no tendremos que comprobar de forma explícita si la base de datos nos devuelve un error.

Veamos un ejemplo

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
  $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  $result = $db->query('SELECT titulo FROM libro');

  while ($libro = $result->fetch()) {
     echo 'TITULO: ' . $libro['titulo'] . '<br />';
  }
  $db=null;
}
catch (PDOException $pdoe)
{
  echo $pdoe->getMessage() . '<br />';
  if (isset($db))
  {
     echo 'ErrorCode: ' . $db->errorCode();
     var_dump($db->errorInfo());
     $db=null;
  }
}
?>

Como vemos en el código, no tenemos que comprobar la consulta de forma explícita porque la instrucción query() es la que lanza la excepción que nosotros capturamos posteriormente.

Este es resultado obtenido:

SQLSTATE[42S02]: Base table or view not found: 1146 Table
   'uazon.libro' doesn't exist
ErrorCode: 42S02
array
0 => string '42S02' (length=5)
1 => int 1146
2 => string 'Table 'uazon.libro' doesn't exist' (length=37)

Más información de las funciones errorInfo y errorCode:

** Sentencias preparadas **

Para usar sentencias preparadas, disponemos de los métodos **prepare()**, **bindParam()** y **execute()** que tienen un comportamiento muy parecido al que hemos visto en la librería MySQLI.

Veamos un ejemplo completo donde se inserta el libro "Zen to Done" en la tabla libros:

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

   // Definimos la plantilla de la consulta.
   $consulta =
   "INSERT INTO libros(isbn,titulo,n_pags,precio,fk_editoriales)" .
   " VALUES (:isbn, :titulo, :n_pags, :precio, :fk_editoriales)";

   $isbn = 123456789;
   $titulo = 'Zen to Done';
   $n_pags = 150;
   $precio = 10.99;
   $fk_editoriales = 8; //foreig key -> EDITORIALES (Alfaguara)

   $stmt = $db->prepare ($consulta);
   $stmt->bindParam ( ':isbn', $isbn, PDO::PARAM_INT);
   $stmt->bindParam ( ':titulo', $titulo, PDO::PARAM_STR);
   $stmt->bindParam ( ':n_pags', $n_pags, PDO::PARAM_INT);
   $stmt->bindParam ( ':precio', $precio);
   $stmt->bindParam ( ':fk_editoriales', $fk_editoriales, PDO::PARAM_INT);

   if ( $stmt->execute() )
      echo "Libro insertado correctamente";
   $db=null;
}
catch (PDOException $pdoe)
{
   echo $pdoe->getMessage() . '<br />';
   if (isset($db)) {
      echo 'ErrorCode: ' . $db->errorCode();
      var_dump($db->errorInfo());
      $db=null;
   }
}
?>

La función prepare() prepara la consulta como sentencia predefinida. El funcionamiento es muy similar al que hemos visto con mysqli, aunque se pueden utilizar tanto el signo de interrogación (?) como dos puntos seguidos del nombre de la variable de la plantilla (:variable) como marcadores de las plantillas.

Versión marcadores:

$consulta =
   "INSERT INTO libros (isbn, titulo, n_pags, precio, fk_editoriales)" .
   " VALUES (:isbn, :titulo, :n_pags, :precio, :fk_editoriales)";

$stmt = $db->prepare($consulta);

Versión con interrogantes:

// Definimos la plantilla de la consulta.
$consulta =
   "INSERT INTO libros (isbn, titulo, n_pags, precio, fk_editoriales) " .
   "VALUES(?, ?, ?, ?, ?)";

Mediante bindParam() emparejamos la variable con el valor de la plantilla. Es mucho más cómodo porque no tenemos que seguir el orden establecido por los signos de interrogación, como vimos con MySQLI.

...
$stmt->bindParam (':isbn', $isbn, PDO::PARAM_INT);
$stmt->bindParam (':titulo', $titulo, PDO::PARAM_STR);
...

La función **bindParam()** admite otro parámetro para establecer el tipo del dato a insertar. Por defecto se establece a PARAM_STR (STRING)

Más información en el manual:

http://docs.php.net/manual/es/pdostatement.bindparam.php

Por último, el método **execute()** ejecuta la sentencia preparada. Esta función admite un parámetro optativo, más concretamente un array de variables para emparejar con los marcadores.

Veamos un ejemplo:

 ...
//isbn, titulo, n_pags, precio, fk_editoriales
$libro = array ( 987654321, 'Done to Zen', 1, 99.10, 7);

$stmt->execute ($libro);
...

Para ver más ejemplos de dicha función

http://docs.php.net/manual/es/pdostatement.execute.php

Dos ejemplos completos donde se realizan dos inserciones con una sentencia preparada con marcadores distintos ('?' y ':variable'):

<?php
$servidor = 'localhost';
$bd = 'uazon';
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

   // Definimos la plantilla de la consulta.
   $consulta =
   "INSERT INTO libros(isbn, titulo, n_pags, precio, fk_editoriales) " .
    " VALUES(?, ?, ?, ?, ?)";

   $isbn = 123456789;
   $titulo = 'Zen to Done';
   $n_pags = 150;
   $precio = 10.99;
   $fk_editoriales = 8; //foreig key -> EDITORIALES (Alfaguara)

   $stmt = $db->prepare($consulta);
   $stmt->bindParam(1, $isbn, PDO::PARAM_INT);
   $stmt->bindParam(2, $titulo, PDO::PARAM_STR);
   $stmt->bindParam(3, $n_pags, PDO::PARAM_INT);
   $stmt->bindParam(4, $precio);
   $stmt->bindParam(5, $fk_editoriales, PDO::PARAM_INT);

   $stmt->execute();

   $libro = array(987654321, 'Done to Zen', 1, 99.10, 7);

   $stmt->execute($libro);

   $db=null;
}
catch (PDOException $pdoe)
{
  echo $pdoe->getMessage() . '<br />';
  if (isset($db))
  {
      echo 'ErrorCode: ' . $db->errorCode();
      var_dump($db->errorInfo());
      $db=null;
  }
}
?>

Versión usando el formato de marcadores (:_variable_)

<?php
$servidor = 'localhost';
$bd = 'uazon',
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd, $user, $pwd);

   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

   // Definimos la plantilla de la consulta.
   $consulta =
   "INSERT INTO libros(isbn, titulo, n_pags, precio, fk_editoriales) " .
    " VALUES(:isbn, :titulo, :n_pags, :precio, :fk_editoriales)";

    $isbn = 123456789;
   $titulo = 'Zen to Done';
   $n_pags = 150;
   $precio = 10.99;
   $fk_editoriales = 8; //foreig key -> EDITORIALES (Alfaguara)

   $stmt = $db->prepare($consulta);
   $stmt->bindParam(':isbn', $isbn, PDO::PARAM_INT);
   $stmt->bindParam(':titulo', $titulo, PDO::PARAM_STR);
   $stmt->bindParam(':n_pags', $n_pags, PDO::PARAM_INT);
   $stmt->bindParam(':precio', $precio);
   $stmt->bindParam(':fk_editoriales', $fk_editoriales, PDO::PARAM_INT);

   $stmt->execute();

   //array asociativo
   $libro = array(
    "isbn" => 987654321, "titulo" => 'Done to Zen', "n_pags" => 1,
    "precio" => 99.10, "fk_editoriales" => 7);

   $stmt->execute($libro);

   $db=null;
}
catch (PDOException $pdoe)
{
  echo $pdoe->getMessage() . '<br />';
  if (isset($db)) {
   echo 'ErrorCode: ' . $db->errorCode();
   var_dump($db->errorInfo());
   $db=null;
  }
}
?>

**Transacciones**

Las transacciones funcionan igual que con el objeto MySQLI.

Dentro de la clase PDO disponemos de los métodos:

class PDO {
 //inicializa la transaccion
 bool beginTransaction ( void )
 //fuerza que los cambios se almacenen en la base de datos.
 bool commit (void )
 //vuelve atras la transacción
 bool rollback (void )
}

Veamos el código de inserción de un pedido con transacciones mediante PDO:

<?php
$servidor = 'localhost';
$bd = 'uazon',
$user = 'comprador';
$pwd = 'proweb2013';

try
{
   $db = new PDO('mysql:host='.$servidor.';dbname='. $bd,
                  $user, $pwd);

   $db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

   try
   {
      $db->beginTransaction();

      //fk_usuario = 2 - Francisco Rubio Blancas
      $query =
      "INSERT INTO pedidos(total, fecha, fk_usuarios)" .
      " VALUES (?, ?, ?)");

      $stmt = $db->prepare($query);

      $stmt->execute ( array('44.00', '2011-10-17', '2'));

      //Nos guardamos el ultimo id insertado (autoincremento)
      $fk_pedidos = $db->lastInsertId();

      //2 libros de Anna Karenina(id=1) 22.00 x 2 = 44.00
      $query =
      "INSERT INTO libros_pedidos(fk_libros, fk_pedidos, cantidad, precio)" .
      " VALUES (?, ?, ?, ?)");

      $stmt = $db->prepare($query);

      $stmt->execute (array ('1', $fk_pedidos, '2', '44.00') );

      //Forzamos escritura de los datos en la base de datos
      $db->commit(); //Pedido insertado correctamente.';
   }
   catch (PDOException $pdoe) {
      // Si alguno de los insert falla, volvemos hacia atras la
      // transaccion actual antes del ultimo commit.
      $db->rollback();
      throw $pdoe;
   }
}
catch (Exception $e) {
   echo $e;
   if (isset($db))
      $db = null;
}
?>

Como vemos en el ejemplo dentro de la clase PDO disponemos del método lastInserId() que nos devuelve el último identificador insertado:

class PDO {
   string lastInsertId ([ string $name = NULL ] )
}

Para saber más sobre dicho método acceder a la siguiente URL: http://docs.php.net/manual/es/pdo.lastinsertid.php

results matching ""

    No results matching ""