Acceso a Bases de Datos

• • • •

PHP tiene bibliotecas de funciones de acceso a decenas de diferentes DBMS Para cada DBMS las funciones son similares pero no iguales Si se decide cambiar el DBMS se hace necesario cambiar muchas líneas de código Solución: usar una capa de abstracción adicional que permita operar con cualquier DBMS:

• •

PEAR DB (simple, no tiene toda la funcionalidad de Oracle) ADOdb (mas poderoso, funciones sencillas y avanzadas)
similitud a Microsoft ADO lo hace fácil de aprender a quienes ya han sido expuesto a la tecnología de MS

Acceso Directo vs Abstracto (ADOdb)

Un Ejemplo con ADOdb
require 'adodb/adodb.inc.php'; // Connect to the database $conn = &ADONewConnection('oci8'); $conn->connect('localhost','phpgems','phpgems1','phpgems'); // Send a SELECT query to the database $rs = $conn->execute('SELECT flavor, price, calories FROM _ice_cream'); // Check if any rows were returned if ($rs->RecordCount() > 0) {! !!!!!print "<table>";! !!!!!print "<tr><TH>Ice Cream Flavor</TH><TH>Price per Serving</TH> <TH>Calories per Serving</TH></TR>"; !!!! // Retrieve each row !!!! while (! $rs->EOF) { !!!!!!! print "<tr><TD>{$rs->fields[0]}</TD><TD>{$rs>fields[1]}</TD><TD> {$rs->f ields[2]}</TD></TR>\n";! !!!!!!!!! $rs->MoveNext(); !!!! } !!!! print "</table>"; } else { !!!! print "No results"; }

Primitivas Básicas

• • • •

AdoNewConnection(‘Database Type’);

• • • • • • •

devuelve un objeto de conexión

Connect(‘host’, ‘username’, ‘password’, ‘database’);
realiza la conexión, previo a execute query

Execute(‘SQL Query’);
devuelve el conjunto de filas (row set) resultado

Operadores sobre Row Set
RecordCount() número de filas en el set fields[k] k-esimo campo de la fila actual Movenext() avanza a siguiente fila EOF verdadero si estamos al final del set

Ejecución de la consulta
placeholder
$sql = 'SELECT * FROM ice_cream WHERE flavor LIKE ?';

$rs = $conn->execute($sql,array('Chocolate')); $rs = $conn->execute($sql,array('Vanilla'));

<?php include("adodb.inc.php"); $db = NewADOConnection("$database_type"); $db->Connect("localhost", "john", "doe", "db278") or die("Unable to connect!"); $query = $db->Prepare("INSERT INTO library (title, author) VALUES (?, ?)"); $data = file("list.txt"); foreach ($data as $l) { // split on comma $arr = explode(",", $l); // insert values into prepared query $result = $db->Execute($query, array($arr[0], $arr[1])) or die("Error in query: $query. " . $db->ErrorMsg()); } $db->Close; ?>

Prepare

El RecordSet de ADOdb

• • •

la sentencia ADOConnection–>Execute($sql) devuelve un RecordSet RecordSet tiene asociado un cursor virtual existen funciones de apoyo para:

• • • • • • • • •

obtener una tupla: FetchRow FetchInto FetchObject FetchNextObject FetchObj FetchNextObj obtener todas las tuplas: GetArray GetRows GetAssoc scrolling: Move MoveNext MoveFirst MoveLast AbsolutePosition CurrentRow AtFirstPage AtLastPage AbsolutePage generar menus: GetMenu GetMenu2 fechas: UserDate UserTimeStamp UnixDate UnixTimeStamp info del recordset: RecordCount PO_RecordSet NextRecordSet info de los distintos campos de la tupla: FieldCount FetchField MetaType cierre: Close Deprecated: GetRowAssoc Fields

Movimiento del Puntero de Filas
$rs = $conn->execute('SELECT flavor,calories,price FROM ice_cream'); print last row $rs->MoveLast(); print "Flavor {$rs->fields[0]} has {$rs->fields[1]} calories and costs print "\${$rs->fields[2]}.\n"; print first row $rs->MoveFirst(); print "Flavor {$rs->fields[0]} has {$rs->fields[1]} calories and costs print "\${$rs->fields[2]}.\n";

$rs = $conn->execute('SELECT flavor,calories,price FROM ice_cream'); print second row $rs->Move(2); print "Flavor {$rs->fields[0]} has {$rs->fields[1]} calories and costs print "\${$rs->fields[2]}.\n";

Variaciones sobre el tema ...
include("adodb.inc.php"); // include the ADODB library$db = NewADOConnection("$database_type"); $db->Connect("$host", "$user", "$password", "employees"); $sql = "SELECT surname, age FROM employees"; $rs = $db->Execute($sql); if (!$rs) { print $db->ErrorMsg(); // display error if no results could be returned } else { while (!$rs->EOF) { print $rs->fields[0].' '.$rs->fields[1].'<BR>'; // fields[0] is surname, fields[1] is age $rs->MoveNext(); // Moves to the next row } // end while } // end else include("adodb.inc.php"); // include the ADODB library$db = NewADOConnection("$database_type"); $db->Connect("$host", "$user", "$password", "employees"); $sql = "SELECT surname, age FROM employees"; $db->SetFetchMode(ADODB_FETCH_ASSOC); // Return associative array $rs = $db->Execute($sql); if (!$rs) {print $db->ErrorMsg(); // display error if no results could be returned } else { while (!$rs->EOF) { print $rs->fields['surname']." ".$rs->fields['age']."<BR>"; $rs->MoveNext(); // Moves to the next row } // end while } // end else

Otra forma ...
include("adodb.inc.php"); // include the ADODB library $db = NewADOConnection("$database_type"); $db->Connect("$host", "$user", "$password", "employees"); $sql = "SELECT surname, age FROM employees"; $db->SetFetchMode(ADODB_FETCH_ASSOC); // Return associative array $rs = $db->Execute($sql); if (!$rs) { print $db->ErrorMsg(); // display error if no results could be returned } // loop through results while ($row = $rs->FetchNextObject()) { // The field names need to be uppercase print $row->SURNAME." ".$row->AGE."<BR>"; }

en este caso cada fila se recupera como un objeto (row object)

Y otra más ...
<?php $db = NewADOConnection("mysql"); $db->Connect("localhost", "john", "doe", "db278") or die("Unable to connect!"); $query = "SELECT * FROM library"; $result = $db->GetAll($query) or die("Error in query: $query. " . $db>ErrorMsg()); $db->Close(); foreach ($result as $row) { echo $row[1] . " - " . $row[2] . "\n"; } echo "\n[" . sizeof($result) . " rows returned]\n"; ?>

en este caso el método GetAll crea un array bidimensional que contiene el resultado completo de la consulta

Inserción

Actualización de la BD

$employee_surname = $db->qstr("d'Angelo"); $arrival_time = $db->DBDate(time()); $sql = "INSERT INTO employee_arrival (arrival_time,surname) values ($arrival_time,$employee_surname)"; if (!($db->Execute($sql))) { print 'Error inserting: '.$db->ErrorMsg().'<BR>'; }

Actualización
$sql = "UPDATE employees SET age='44' WHERE id='121')"; if (!($db->Execute($sql))) { print 'Error updating: '.$db->ErrorMsg().'<BR>'; }

Facilidades de Paginación
include_once('adodb.inc.php'); include_once('adodb-pager.inc.php'); session_start(); $db = NewADOConnection("$database_type"); $db->Connect('localhost','root','','xphplens'); $sql = "select * from adoxyz "; $pager = new ADODB_Pager($db,$sql); $pager->Render($rows_per_page=5);

GetMenu (sobre un result set)
GetMenu($name, [$default_str=''], [$blank1stItem=true], [$multiple_select=false], [$size=0], [$moreAttr=''])

$rs ->GetMenu('menu1','A',true) datos (A,1), (B, 2) y (C,3) )

(suponiendo

$rs ->GetMenu('menu1',array('A','B'),false)

• • • •

Home Page

Mas Info sobre ADOdb
http://adodb.sourceforge.net/

Manual http://phplens.com/adodb/ FAQ http://adodb.sourceforge.net/adodb-faq.html Otros

• • • •

http://www.aspfree.com/c/a/Database/Accessing-Databases-with-ADODB/ http://www.devshed.com/c/a/PHP/PHP-Application-Development-With-ADODB-part-1/ http://www.devshed.com/c/a/PHP/PHP-Application-Development-With-ADODB-part2/ http://www.devshed.com/c/a/PHP/PHP-Application-Development-With-ADODB-part2/

Las deudas ...

Funciones Especiales de Compatibilidad

Es común que diferentes DBMS difieran en cuanto a

• •

la forma aceptada de un string entre comillas el formato de fechas

ADOdb provee facilidades para manejar estas dos situaciones

• •

$employee_surname = $db -> qstr("d' Angelo"); $arrival_time = $db -> DBDate(time());

Invocación de Procedimientos Almacenados
PROCEDURE data_out(input IN VARCHAR, output OUT VARCHAR) IS BEGIN output := 'I love '|| input; END;

$stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;"); $input = 'Sophia Loren'; $db->InParameter($stmt,$input,'a1'); $db->OutParameter($stmt,$output,'a2'); $ok = $db->Execute($stmt); if ($ok) echo ($output == 'I love Sophia Loren') ? 'OK' : 'Failed';

Transacciones en ADOdb

Hay dos bibliotecas: una antigua (clásica) y una más nueva (smart transactions)

$conn->BeginTrans();! $ok = $conn->Execute($sql); if ($ok) $ok = $conn->Execute($sql2); if (!$ok) $conn->RollbackTrans(); else $conn->CommitTrans(); $conn->StartTrans(); $conn->Execute($sql); $conn->Execute($Sql2); $conn->CompleteTrans();

• • • •

CompleteTrans hace un rollback o commit segun sea necesario Es posible forzar el rollback con $conn->FailTrans(); No hay soporte de savepoints DBMS debe tener soporte de transacciones