Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... ·...

78
Diseño de Aplicaciones Web PHP Gestión de Datos

Transcript of Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... ·...

Page 1: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Diseño de Aplicaciones Web

PHP

Gestión de Datos

Page 2: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Almacenamiento de Datos en PHP

• Alternativas de almacenamiento en PHP:– Almacenamiento contra el API de MySQL.

– API extendida de MySQL.

– Objetos de datos: PDO (PHP Data Objects))

– Serialización y almacenamiento de objetos.

– Proyección de datos relacionales en objetos: ORM (Object-Relational

Mapping)• Doctrine

• Propel

• Xyster

DAW 2

Page 3: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

MySQL en PHP

API de MySQL y MySQLi

DAW 3

Page 4: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Establecimiento de conexión:

– El resultado de la llamada es un recurso (manejador al enlace

establecido) de la conexión con la BD.

– Dicho valor se usa como parámetro en las posteriores llamadas.

DAW 4

resource mysql_connect (

[ string $server = ini_get("mysql.default_host")

[, string $username = ini_get("mysql.default_user")

[, string $password = ini_get("mysql.default_password")

[, bool $new_link = false

[, int $client_flags = 0 ]]]]] )

$handler= mysql_connect('localhost', ‘chema', ‘patata');

if (!$ handler) {

die(‘Error de conexión: ' . mysql_error());

}

echo ‘Conexión establecida';

La referencia al servidor se

realiza con el formato:

servidor:puerto

Por ejemplo:

laurel.datsi.fi.upm.es:4577

Page 5: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Selección de la base de datos:

– Utilizando el manejador al enlace se selecciona la BD a utilizar.

– Esta operación es análoga al mandado de MySQL:

DAW 5

bool mysql_select_db (string $database_name [, resource $link_identifier = NULL ] )

$handler= mysql_connect('localhost', ‘chema', ‘patata');

if (!$ handler) {

die(‘Error de conexión: ' . mysql_error());

}

echo ‘Conexión establecida';

$bd_ok = mysql_select_db('foo', $handler);

if (!$bd_ok) {

die ('No se puede accede a foo : ' . mysql_error());

}

USE base_de_datos;

El utilizar o no una base de datos no es

excluyente, en MySQL es posible

acceder tablas de otras bases de datos

utilizando la sintaxis:

bd.tabla

Ejemplo:

SELECT * FROM stock.productos;

Page 6: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Consultas SQL:

Operaciones CRUD (Create, Read, Update and Delete):– Operaciones que devuelve listas de registos (típicamente SELECT,

SHOW, DESCRIBE, EXPLAIN): El valor devuelto es otro recurso

(manejador del cursor de la consulta) al que se le puede consultar

por el número de registros devueltos:

– Operaciones que modifican registros (típicamente INSERT, UPDATE,

DELETE, DROP): No se devuelve un recurso, pero se puede obtener

el número de registros afectados:

DAW 6

mixed mysql_query ( string $query [, resource $link_identifier = NULL ] )

int mysql_num_rows ( resource $result )

int mysql_affected_rows ([ resource $link_identifier = NULL ] )

Page 7: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Recuperación de registros de un SELECT (modo cursor):

– Esta llamada devuelve un array con el siguiente registro del

manejador de cursos proporcionado o falso si no hay más registros.

– El tipo de resultado indica si el array producido está indexado por

números o por nombres de columnas (o por ambos).

DAW 7

array mysql_fetch_array ( resource $result [, int $result_type = MYSQL_BOTH ] )

mysql_connect('localhost', 'chema', 'patata');

mysql_select_db('foo');

$resultado = mysql_query('SELECT id, nombre FROM tabla');

while ($fila = mysql_fetch_array($resultado, MYSQL_BOTH)) {

printf('ID: %s Nombre: %s', $fila['id'], $fila['nombre']);

}

Page 8: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Recuperación de registros de un SELECT (modo cursor con

objetos):

– La operativa es idéntica al caso anterior pero el elemento devuelto no

es un array sino que es un objeto con los atributos de los campos del

registro.

DAW 8

object mysql_fetch_object ( resource $result [, string $class_name [, array $params ]] )

mysql_connect('localhost', 'chema', 'patata');

mysql_select_db('foo');

$resultado = mysql_query('SELECT id, nombre FROM tabla');

while ($fila = mysql_fetch_object($resultado)) {

printf('ID: %s Nombre: %s', $fila->id, $fila->nombre);

}

Page 9: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Lectura de un resultado de un SELECT (modo indexado):

– Esta alternativa permite acceder a los resultados indexando número

de fila y el campo.

– El indicador del campo puede ser tanto el índice, como el nombre del

mismo (incluyendo el formato “tabla.campo”).

DAW 9

string mysql_result ( resource $result , int $row [, mixed $field = 0 ] )

mysql_connect('localhost', 'chema', 'patata');

mysql_select_db('foo');

$resultado = mysql_query('SELECT id, nombre FROM tabla');

for ($f = 0; $f < mysql_num_rows($resultado); $f++) {

printf('ID: %s Nombre: %s',

mysql_result($resultado, $f, 'id'),

mysql_result($resultado, $f, 'nombre'));

}

Page 10: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Sentencias de modificación de registros:– Vale con verificar si el resultado de ejecutar la consulta ha sido

verdadero o no.

DAW 10

mysql_connect('localhost', 'chema', 'patata');

mysql_select_db('foo');

$sql = "INSERT INTO agenda (nombre, direccion, telefono, email) ".

"VALUES ('$nombre', '$direccion', '$telefono', '$email')";

$resultado = mysql_query($sql);

if (!$resultado) {

print('Error en INSERT: '. mysql_error());

die();

}

$sql = "UPDATE agenda SET nombre='$nombre', direccion='$direccion',".

"telefono='$telefono', email='$email'";

$resultado = mysql_query($sql);

if(!$resultado) {

print('Error en UPDATE: '. mysql_error());

die();

}

Page 11: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Otras funciones de utilidad:– Modificación de cadenas con secuencias de escape:

– Gestión de errores:

– Obtención de identificador generado automáticamente:

– Obtener el número de campos de una consulta SELECT:

– Borrado de una base de datos

• Equivale al mandato SQL:DAW 11

string mysql_real_escape_string ( string $unescaped_string

[, resource $link_identifier = NULL ] )

int mysql_errno ([ resource $link_identifier = NULL ] )

string mysql_error ([ resource $link_identifier = NULL ] )

int mysql_insert_id ([ resource $link_identifier = NULL ] )

int mysql_num_fields ( resource $result )

bool mysql_drop_db ( string $database_name [, resource $link_identifier = NULL ] )

DROP DATABASE base_de_datos;

Page 12: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Gestión de transacciones:– No existen llamadas al API específicas para ello.

– Se realizan consultas SQL estándar usando la función mysql_query().

DAW 12

mysql_query("START TRANSACTION");

mysql_query("BEGIN");

$resultado = mysql_query("DELETE FROM facturas WHERE cliente_id='$id'");

if (!$resultado) {

mysql_query(“ROLLBACK");

die('Error al borrar FACTURAS: '. mysql_error());

}

$resultado = mysql_query("DELETE FROM clientes WHERE id='$id'");

if (!$resultado) {

mysql_query(“ROLLBACK");

die('Error al borrar CLIENTES: '. mysql_error());

}

mysql_query("COMMIT");

Page 13: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

API de MySQL en PHP

Liberación de recursos:– Cerrado de la conexión (opuesto a mysql_connect()):

– Liberar la memoria de un cursos de consulta (el resultado de un

mysql_query() de tipo SELECT):

Conexiones persistentes:

– No se cierran cuando el script termina y se intentan reutilizar en otras

llamadas del mismo tipo.

DAW 13

bool mysql_close ([ resource $link_identifier = NULL ] )

bool mysql_free_result ( resource $result )

resource mysql_pconnect (

[ string $server = ini_get("mysql.default_host")

[, string $username = ini_get("mysql.default_user")

[, string $password = ini_get("mysql.default_password")

[, int $client_flags = 0 ]]]]] )

Page 14: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Limitaciones API Nativa de MySQL

• Resulta necesario realizar las consultas “picando” SQL.

• Además: – Es necesario establecer la protección ante valores de campos que

puedan ser peligrosos:• Usando mysql_real_escape_string().

– A la hora de insertar registros con campos de autoincremento se

necesita consultar y gestionar los identificadores:• Usando mysql_insert_id().

• Y, sobre todo, es procedimental no Orientado a Objetos.

DAW 14

Page 15: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Evolución de las APIs de MySQL

DAW 15

PHP 4 PHP 5

PHP 5.5.0API (procedimental) de MySQL:

• Funciones mysql_…()

API (orientada a objetos) de MySQL:

• Objeto mysqli

mysqli {

__construct ([ string $host = ini_get("mysqli.default_host")

[, string $username = ini_get("mysqli.default_user")

[,string $passwd = ini_get("mysqli.default_pw")

[, string $dbname = ""

[, int $port = ini_get("mysqli.default_port")

[, string $socket = ini_get("mysqli.default_socket") ]]]]]] )

Page 16: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

MySQLi

DAW 16

$db = new mysqli('localhost', 'chema', 'patata', 'foo');

if ($db->connect_errno > 0){

die('Error de conexión: ' . $db->connect_error );

}

if (!$resultado = $db->query('SELECT id, nombre FROM tabla')){

die('Error en la consulta: ' . $db->error);

}

while ($fila = $resultado->fetch_array(MYSQLI_NUM)) {

printf('ID: %s Nombre: %s', $fila['id'], $fila['nombre']);

}

printf('Se han obtenido %s filas', $resultado->num_rows);

if (!$db->query('DELETE FROM tabla WHERE edad<18')){

die('Error en la consulta: ' . $db->error);

}

printf('Se han borrado %s filas', $db->affected_rows);

Page 17: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Sentencias Preparadas en MySQLi

Permite tener mandatos y consultas SQL preprocesadas:

– Estas sentencias pueden estar parametrizadas:

– Para recoger los resultados también se enlazan variables:

DAW 17

$db = new mysqli('localhost', 'chema', 'patata', 'foo');

$sentencia = $db->prepare('SELECT id, nombre FROM tabla');

$sentencia->execute();

$sentencia = $db->prepare('SELECT id, nombre FROM tabla WHERE nombre=? ');

$nombre='Efigenia';

$sentencia->bind_param('s', $nombre);

$sentencia->bind_result($res_id, $res_nombre);

while($sentencia->fetch()) {

printf('ID: %s Nombre: %s', $resid, $resnombre);

}

Page 18: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Limitaciones API de MySQLi

• En esencia es un recubrimiento orientado a objetos del API nativa.

• Se sigue teniendo que escribir SQL.

• Al igual que el API nativa de MySQL es completamente dependiente de

la tecnología de BD (MySQL).

DAW 18

Page 19: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Objetos de Datos PHP

Generalización de Acceso a Bases de Datos y

PDO de PHP

DAW 19

Page 20: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Interfaz PDO

• Objetivo: Independencia de la tecnología de base de datos.

• PDO (PHP Data Objects) es una extensión al estilo de otras

capas intermedias de estándares de acceso a bases de datos

(e.g., ODBC o JDBC).

DAW 20

PDO {

__construct ( string $dsn

[, string $username

[, string $password

[, array $options ]]] )

$db = new PDO("pgsql:host=localhost;dbname=foo", “chema", “patata" );

• El soporte de tecnologías de

bases de datos concretas se

realizan por medio de drivers.

• El driver y los parámetros de

configuración se proporcionan en

la creación del objeto PDO.

PostgreSQL:

MySQL:

SQLite:

$db = new PDO("mysql:host=localhost;dbname=foo", “chema", “patata" );

$db = new PDO("sqlite:/ruta/a/la/base_de_datos.sdb");

Page 21: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Interfaz PDO

• Ejecución de consultas que devuelven registros:

• Ejecución de consultas que modifican registros:

DAW 21

try {

$db = new PDO("mysql:host=localhost;dbname=foo", “chema", “patata" );

foreach ($db->query('SELECT id, nombre FROM tabla') as $fila) {

printf('ID: %s Nombre: %s', $fila['id'], $fila['nombre']);

}

$cuantas = $db->exec('DELETE FROM tabla WHERE edad<18');

printf('Se han borrado %s filas', $cuantas);

}

catch (PDOException $e) {

echo $e->getMessage();

}

public PDOStatement PDO::query ( string $statement )

public int PDO::exec ( string $statement )

Page 22: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Interfaz PDO

• Recuperación de datos con fetch():

– Como un array: nombre o índice

– Como un objeto (anónimo):

DAW 22

public mixed PDOStatement::fetch (

[ int $fetch_style

[, int $cursor_orientation = PDO::FETCH_ORI_NEXT

[, int$cursor_offset = 0 ]]] )

$array = $sentencia->fetch(PDO::FETCH_ASSOC);

printf('ID: %s Nombre: %s', $array['id'], $array['nombre']);

$sentencia = $db->query('SELECT id, nombre FROM tabla');

$objeto = $sentencia->fetch(PDO::FETCH_OBJ);

printf('ID: %s Nombre: %s', $objeto->id, $objeto->nombre);

Page 23: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Interfaz PDO

– Como un objeto

de una clase

definida:

– Con un cursor:

DAW 23

class Persona {

public $id;

public $nombre;

public function nombre_mayusculas() {

return ucwords($this->nombre);

}

}

try {

$db = new PDO("mysql:host=localhost;dbname=foo", “chema", "patata" );

$sql = "SELECT id, nombre FROM tabla";

$sentencia = $db->query($sql);

$pepe = $sentencia->fetch(PDO::FETCH_CLASS, 'Persona');

echo $pepe->nombre_mayusculas();

$cursor = $sentencia->fetchALL(PDO::FETCH_CLASS, 'Persona');

foreach($cursor as $persona)

echo $persona->nombre_mayusculas();

}

catch(PDOException $e) {

echo $e->getMessage();

}

Page 24: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Tecnologías Soportadas por PDO

Las tecnologías de bases de datos soportadas por PDO:– CUBRID: Cubrid databases.

– DBLIB: FreeTDS / Microsoft SQL Server / Sybase

– Firebird (http://firebird.sourceforge.net/): Firebird/Interbase 6

– IBM (IBM DB2)

– INFORMIX - IBM Informix Dynamic Server

– MYSQL (http://www.mysql.com/): MySQL 3.x/4.x/5.x

– OCI (http://www.oracle.com): Oracle Call Interface

– ODBC: ODBC v3 (IBM DB2, unixODBC y win32 ODBC)

– PGSQL (http://www.postgresql.org/): PostgreSQL

– SQLITE (http://sqlite.org/): SQLite 2.x/3.x

– SQLSRV (http://msdn.microsoft.com/): Microsoft SQL Server / SQL

Azure

– 4D (http://www.4d.com/): 4th Dimension.DAW 24

Page 25: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Limitaciones PDO

• No quiero escribir más SQL!!!!!

DAW 25

Page 26: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Necesidades de Almacenamiento de

Objetos

Limitaciones de Soluciones Relacionales y

Serialización de Objetos en PHP

DAW 26

Page 27: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Gestión de Datos en Aplicaciones Web

• Necesidades de almacenamientos de datos:– Información estructurada

– Documentos (ficheros)

– Documentos (objetos)

• Desde el punto de vista de funcionalidad lo que necesita el

nivel de aplicación es que– Todo objeto de datos tenga su respaldo y

– Que el acceso al respaldo (grabar y recuperar) sea eficiente.

DAW 27

Page 28: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Limitaciones del Modelo Relacional

• Las BD almacenan la información en filas y columnas.

• El desarrollo de las aplicaciones e hace sobre estructuras de

datos y objetos.– Se puede simular las referencias entre objetos y las colecciones de

datos por medio de relaciones entre filas de las tablas.

– Las restricciones que aseguran unicidad de identificadores o campos

son difíciles de asegurar e implementar en los objetos.

– Conceptos de campos dinámicos, algunas funcionalidades de las

herencias y ciertas colecciones de objetos se transcriben mal en el

modelo relacional.

DAW 28

Page 29: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Almacenamiento de Objetos

• La orientación a objetos en su aplicación al almacenamientos

de datos puede ser:– Que las estructuras de datos a nivel aplicación sean objetos y se

almacenen como tales.

– Que las estructuras de datos a nivel aplicación sean objetos y se

almacenen como tablas (relacionales) de datos.

DAW 29

Aplicación OBJ OBJ

Objeto

Registro de una tabla

Objeto

Sistema de

Ficheros NoSQL

Fichero Documento

Page 30: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Almacenamiento de Objetos

• Que las estructuras de datos a nivel aplicación sean objetos y

se almacenen como tales:– Serialización de objetos.

– E.g., JSON o XML:

DAW 30

{"employees":[

{"firstName":"John", "lastName":"Doe"},

{"firstName":"Anna", "lastName":"Smith"},

{"firstName":"Peter", "lastName":"Jones"}

]}

<employees>

<employee>

<firstName>John</firstName> <lastName>Doe</lastName>

</employee>

<employee>

<firstName>Anna</firstName> <lastName>Smith</lastName>

</employee>

<employee>

<firstName>Peter</firstName> <lastName>Jones</lastName>

</employee>

</employees>

...

var txt = JSON.stringify(employeeList, replacer);

...

var obj = JSON.parse(txt, reviver);

...

XML

JSON

JavaScript

Page 31: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Serialización en PHP

Se apoya en dos métodos:

El métodos serialize() convierte un objeto en una cadena de caracteres y unserialize()

convierte una cadena de caracteres en un objeto.

Adicionalmente hay dos funciones a implementar en una clase serializable:

Que devuelve un array de los strings de los campos a serializar. Dicha función se invoca

inmediatamente antes de serializar.

Que se ejecuta inmediatamente después de deserializar el objeto.

La serialización es con un formato propio de PHP.

DAW 31

string serialize ( mixed $value )

mixed unserialize ( string $str )

public array __sleep ( void )

void __wakeup ( void )

Page 32: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Serialización en PHP

DAW 32

class Empleado {

public $nombre;

public $apellido;

public $edad;

private $sueldo;

function __construct ($n, $a, $e, $s) {

$this->nombre = $n;

$this->apellido = $a;

$this->edad = $e;

$this->sueldo = $s;

}

}

$pepe = new Empleado("Pepe", "Potamo", 32, 1900);

var_dump($pepe);

$str=serialize($pepe);

print $str;

$copia = unserialize($str);

var_dump($copia);

object(Empleado)[1]

public 'nombre' => string 'Pepe' (length=4)public 'apellido' => string 'Potamo' (length=6)public 'edad' => int 32

private 'sueldo' => int 1900

O:8:"Empleado":4:{s:6:"nombre";s:4:"Pepe";s:8:"

apellido";s:6:"Potamo";s:4:"edad";i:32;s:16:"Em

pleadosueldo";i:1900;}

object(Empleado)[2]

public 'nombre' => string 'Pepe' (length=4)public 'apellido' => string 'Potamo' (length=6)public 'edad' => int 32

private 'sueldo' => int 1900

Page 33: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Serialización en PHP

DAW 33

class Empleado {

public $nombre;

public $apellido;

public $edad;

private $clave;

function __construct ($n, $a, $e, $c) {

$this->nombre = $n;

$this->apellido = $a;

$this->edad = $e;

$this->clave = $c;

}

function __sleep() {

$this->clave=str_rot13($this->clave);

return array('nombre', 'apellido', 'edad', 'clave');

}

function __wakeup() {

$this->clave=str_rot13($this->clave);

}

}

object(Empleado)[1]

public 'nombre' => string 'Pepe' (length=4)public 'apellido' => string 'Potamo' (length=6)public 'edad' => int 32

private ' clave' => string ‘patata' (length=6)

O:8:"Empleado":4:{s:6:"nombre";s:4:"Pepe";s:8:"

apellido";s:6:"Potamo";s:4:"edad";i:32;s:16:"Em

pleadoclave";s:6:"cngngn";}

Page 34: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Proyección Objeto-Relacional

ORM General y Versiones de Doctrine

DAW 34

Page 35: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Proyección Objeto-Relacional

• En inglés “Object-Relational Mapping” (ORM)

• Propósito:– Guardar un objeto como una fila en una tabla de una BD.

– Recuperar datos de las tablas y convertirlos en objetos.

– Guardar y recrear asociaciones entre objetos.

• Objetivos del diseño:– Separar los servicios de mapping entre objetos y relaciones del resto

del programa.

– Minimizar el impacto de cambiar la tecnología (y modelo) de la BD.

DAW 35

Page 36: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Ejemplo

DAW 36

Curso

nombre: String

horario: Date

créditos: int

Aula

número: int

bloque: int

plazas: int

Profesor

nombre: String

despacho: String

Alumno

nombre: String

matrícula: int

aula

1

curso

1

profesores

*

* cursos

* alumnosAdicionalmente, se puede

asumir que todas las clases

disponen de un atributo id()

que es único para todos los

objetos de esa clase (una

clave).

Page 37: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Object-Relational Mapping

• Clase:– Debe tener un atributo que actúe

como identificador (id).

• Data mapper:– Convierte:

• Clase Tabla

• Objeto Fila

– Adapta los tipos de datos.

– Instancia los objetos.

• Tabla:– El atributo identificador es

típicamente la clave primaria.

DAW 37

AULAS

id VARCHAR(12)

número INTEGER

bloque INTEGER

plazas INTEGER

PK

Aula

número: int

bloque: int

plazas: int

ORM

Page 38: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Object-Relational Mapping

DAW 38

(Aula) aqui

número=5101

bloque=5

plazas=125

AULAS

número

3201

5101

5102

id

C01

E02

E03

bloque

3

5

5

plazas

145

125

117

AlmacenadoRecuperación

Page 39: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Object-Relational Mapping

• Funcionalidades de almacenamiento:– Almacenamiento explícito:

• Se indica explícitamente cuándo y qué almacenar.

• Llamada de tipo save().

– Almacenamiento de modificaciones realizadas:• Todo un conjunto de modificaciones se mandan a almacenar.

• Se realizan mediante llamada flush().

– Persistencia transparente:• Un objeto se declara como persistente.

• Cada cambio de uno de sus atributos se sincroniza con el soporte de

almacenamiento.

• Comienza en el momento en el que el elemento se registra en el gestor

correspondiente (register()).

• Es necesario capturar los métodos que modifican atributos.

DAW 39

Page 40: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Active Record vs. Data Mapper

• Dos patrones de implementación de un ORM:

DAW 40

ACTIVE RECORD• Los objetos derivan de una clase de la

biblioteca de ORM de donde hereda

métodos explícitos de

almacenado/recuperación.

• El diseño de los objetos establece qué

atributos son almacenables y aspectos

tales como el tipo de datos y nombre de

la columna de la tabla.

• Se pueden construir los objetos del

código a la BD o viceversa.

Ejemplos: Doctrine 1.2 (PHP), Ruby on

Rails o Laravel

DATA MAPPER• Los objetos no heredan de nada, son

objetos “simples” del lenguaje.

• Los objetos están desacoplado de cómo

almacenarlos (los métodos que

implementan eso los mantiene un Entity

Manager).

• La interacción entre este elemento y la

BD es más estricta.

• Se puede ver como un DAL (Data

Access Layer) sofisticado que se las

entiende con objetos

Ejemplos: Doctrine 2+ (PHP), Boockself.js

o ROM

Page 41: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Active Record vs. Data Mapper

• Ventajas de Active Record:– El código puede invocar expresamente al almacenamiento,

actualización y recuperación de datos donde resulte más adecuado

(es más flexible).

– Más habituales y generalizadas y de utilidad en prototipado rápido.

• Ventajas de Data Mapper:– Los objetos son más ligeros (no mantienen la implementación de los

métodos de almacenamiento).

– Al estar desacoplados los objetos de negocio del almacenamiento es

más fácil ser estricto con MVC.

– Se puede ver como un DAL (Data Access Layer) sofisticado que se

las entiende con objetos.

– Facilita la persistencia transparente.

DAW 41

Page 42: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Active Record vs. Data Mapper

DAW 42

$alumna = new Alumno("j070212", "Elena", "Nito del Bosque");

$alumna->creditos_aprobados = 207;

$alumna->save();

$alumna->save();

EntityManager::persist($alumna);

Active Record Data Mapper

Implementaciones de ORM en PHP

Doctrine 1.2 Doctrine 2

Page 43: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Identificadores en un ORM

• La identificación (identidad) de un objeto se implementa por

medio de dos mecanismos:– Está alojado en la misma ubicación (o son la misma referencia),

operador A==B (igual).

– Existe un método de comparación equals() o compareWith().

• En una BD la comparación está asociada a tener la misma

clave primaria.

• La comparación y la identidad de elementos está en la base

de la gestión de caches, de modificaciones y de transacciones.

DAW 43

Page 44: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Relaciones entre Objetos

DAW 44

CURSOS

id VARCHAR(8)

nombre VARCHAR(64)

horario DATETIME

créditos INTEGER

PK

ORM

Curso

nombre: String

horario: Date

créditos: int

Profesor

nombre: String

despacho: String

curso

1

profesores

*

PROFESORES

id VARCHAR(12)

nombre VARCHAR(64)

despacho VARCHAR(16)

id_curso VARCHAR(8)

PK

FK

Page 45: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Relaciones entre Objetos

• En el momento que los objetos están relacionados el

almacenamiento tiene que ser consistente con ello:– Si se almacena un objeto y hay modificaciones en objetos

relacionados con él se deben de guardar todas las modificaciones del

grafo.

– Si se da las persistencia transparente esto debe de hacerse de forma

automática.

DAW 45

creado

gestionado

desacoplado

eliminado

new …

Registrar

Combinar

Buscar

Desregistrar

Registrar

Liberar

basura

Page 46: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Flujos de Desarrollo con ORMs

DAW 46

Code First: Se

comienza por el

desarrollo de las clase

y luego se proyectan

en BD

Database First: Se

comienza por el modelo

de datos implementado

en la BD y de él se

extraen las clases.

Variante Model First: Cuando se comienzo con una herramienta

de modelado (tipo UML) de la estructura de clases.

Page 47: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Problemas con Database First

Este flujo se apoya en una herramienta que analiza la estructura

de la base de datos y general el código de las clases que la

implementan en el modelo de objetos.

DAW 47

Problemas:

• ¿Qué ocurre si sobre el código generado yo lo

modifico y luego vuelvo a solicitar que se re-genere

desde la base de datos?

• Se puede solucionar etiquetando las partes de

código generadas manual o automáticamente.

• Derivar una subclase de la clase generada

automáticamente.

Persona

Personas

DatoPersona

mi_método()

Page 48: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine

• Implementación de un ORM para PHP.– Versión Doctrine 1.2 basada en el patrón de implementación de

Active Record.

DAW 48

© Wikipedia

Page 49: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 1.2

• Las clases de objetos almacenables en BD deben extender la

clase Doctrine_Record:– Si se implementa como flujo Code First, se debe implementar el

método setTableDefinition():

– Utilización:

DAW 49

class Alumno extends Doctrine_Record {

public function setTableDefinition() {

$this->setTableName('Alumnos');

$this->hasColumn('nombre', 'string', 255, array('type' => 'string', 'length' => '255'));

$this->hasColumn('matricula', 'integer', 8, array('unsigned' => true));

}

}

CREATE TABLE Alumnos ( nombre VARCHAR(255), matricula INT(8) UNSIGNED);

$elena = new Alumno();

$elena->nombre ="Elena Nito del Bosque";

$elena->matricula = 70212;

$elena->save();

Page 50: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 1.2

• Las relaciones entre tablas se diseñan como relaciones entro

clases:

DAW 50

class Alumno extends Doctrine_Record {

public function setTableDefinition() {

<…>

}

public function setUp() {

$this->hasMany('Notas as Notas', array('refClass' => 'Nota', 'local' => 'id', 'foreign' => 'alumno_id'));

}

}

class Nota extends Doctrine_Record {

public function setTableDefinition() {

$this->setTableName('Notas');

$this->hasColumn('asignatura', 'string', 255, array('type' => 'string', 'length' => '255'));

$this->hasColumn('alumno_id', 'integer', 8, array('unsigned' => true));

$this->hasColumn(‘calificacion', 'integer', 2, array('unsigned' => true));

}

public function setUp() {

$this->hasOne('Alumno', array('refClass' => 'Alumno', 'local' => 'alumno_id', 'foreign' => 'matricula'));

}

}

Page 51: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 1.2

DAW 51

$elena = new Alumno();

$elena->nombre ="Elena Nito del Bosque";

$elena->matricula = 70212;

$nota = new Nota();

$nota->asignatura = "Diseño de Aplicaciones Web";

$nota->calificacion = 9;

$elena->Notas[] = $nota;

$nota->Alumno = $elena;

$elana->save();

Alumnos

Notas

tienen

ALUMNOS

Matrícula Nombre

70212 Elena Nito del BosqueNOTAS

Matrícula Asignatura Calificación

70212 Diseño de Aplicaciones Web 9

Page 52: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Alternativas de Flujos de Generación

• Alternativa:– Declaración de estructura vía YAML:

• Fichero: alumno.yml

DAW 52

Alumno:

columns:

nombre: string (255)

matricula: integer (8)

Ficheros

YAML

Base de

Datos CódigoDoctrine_Core::generateTablesFromModels

Doctrine_Core::generateModelsFromDb

Doctrine_Core::generateSqlFromModels

Page 53: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Alternativas de Flujos de Generación

• Model first:

• Database first:

DAW 53

echo 'Generando código... ';

Doctrine_Core::generateModelsFromYaml(‘estructura.yml', '/Modelos');

echo “hecho!\n";

echo 'Reconstruyendo tablas de la base de datos... ';

Doctrine_Core::dropDatabases();

Doctrine_Core::createDatabases();

Doctrine_Core::createTablesFromModels('/Modelos');

echo “hecho!\n";

echo 'Generando descripción... ';

Doctrine_Core::generateYamlFromDb( ‘estructura.yml', $conexion, $opciones );

echo “hecho!\n";

echo 'Generando código... ';

Doctrine_Core::generateModelsFromDb( '/Modelos', $conexion, $opciones );

echo “hecho!\n";

Page 54: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Limitaciones de Doctrine 1.2

• La definición de las tablas se hace desde la definición de las

clase de forma programática.

• Si se hace desde la base de datos, la semántica de las

relaciones hay que hacerla a mano.

• Hay mucho código oscuro de PHP por debajo.

• Todos los objetos de datos deben derivar de la clase

Doctrine_Record.

DAW 54

Page 55: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Versión 2 basada en el patrón de implementación Data

Mapper. – Inspirado en el diseño de la Java Persistence API (JPA).

– El diseño separa el soporte de persistencia de la lógica de dominio:• Eso permite almacenar los objetos de datos no sólo en SQL sino

también en NoSQL, XML, …

– Mejora en rendimiento sobre Doctrine 1.2 (x3).

– Los objetos de datos no tiene que derivar de ninguna clase del

soporte de almacenamiento.

– La selección de objetos y campos a almacenar se hace por medio de

anotaciones de mapeado.

– Soportado desde PHP 5.3 e integrado en Symfony.

DAW 55

Page 56: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Creación de la clase:

Métodos (set/get):

DAW 56

namespace Entity;

class Alumno {

/** @var int */

private $matricula;

/** @var string */

private $nombre;

}

/**

* @return int

*/

public function getMatricula() {

return $this->matricula;

}

/**

* @param int $matricula

*/

public function setMatricula($matricula) {

$this->matricula = (int) $matricula;

}

/**

* @return string

*/

public function getNombre() {

return $this->nombre;

}

/**

* @param string $nombre

*/

public function setNombre($nombre) {

$this->nombre = (string) $nombre;

}

/** Constructor

* @param int $matricula

*/

public function __construct($matricula) {

$this->setMatricula($matricula);

}

Constructor

Page 57: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Anotaciones @ORM para

el mapeo de la clase:– Identificar lo que va a ser

una entidad (tabla).

– Identificar los campos y sus

tipos.

– Identificar la clave.

DAW 57

namespace Entity;

use Doctrine\ORM\Mapping as ORM;

/**

* @ORM\Entity

*/

class Alumno {

/**

* @ORM\Id()

* @ORM\Column(type="integer")

* @var int

*/

private $matricula;

/**

* @ORM\Column(type="string", length=255)

* @var string

*/

private $nombre;

// El resto

}

Page 58: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Entity Manager (fichero config.php):– Es el componente encargado de almacenar/recuperar los datos entre

el objeto de datos (la clase) y el soporte de persistencia.

– En PHP es necesario activar el soporte de autocargado que permite

que el intérprete de PHP, si encuentra una referencia a una clase y

no está declarada explícitamente el use correspondiente, la pueda

carga de forma dinámica:

DAW 58

use Doctrine\Common\ClassLoader;

//Autocargado

require_once __DIR__ . '/version/autoload.php';

$cargador1 = new ClassLoader('Entity', __DIR__ . '/Librerias');

$cargador1->register();

$cargador2 = new ClassLoader('EntityProxy', __DIR__ . '/Librerias');

$ cargador2 ->register();

Page 59: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Entity Manager (fichero config.php, cont.):– Configuración y metadatos:

DAW 59

use Doctrine\ORM\Configuration,

Doctrine\Common\Cache\ArrayCache,

Doctrine\Common\Annotations\AnnotationRegistry,

Doctrine\Common\Annotations\AnnotationReader,

Doctrine\ORM\Mapping\Driver\AnnotationDriver;

//Configuración

$config = new Configuration();

$cache = new ArrayCache();

$config->setQueryCacheImpl($cache);

$config->setProxyDir(__DIR__ . '/Librerias/EntityProxy');

$config->setProxyNamespace('EntityProxy');

$config->setAutoGenerateProxyClasses(true);

//mapping (example uses annotations, could be any of XML/YAML or plain PHP)

AnnotationRegistry::registerFile(__DIR__ . '/DoctrineDriver/DoctrineAnnotations.php');

$driver = new AnnotationDriver(new AnnotationReader(), array(__DIR__ . '/Librerias/Entity') );

$config->setMetadataDriverImpl($driver);

$config->setMetadataCacheImpl($cache);

Page 60: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Entity Manager (fichero config.php, cont.):– Creación del EntityManager:

• Aquí se le pasan los parámetros (al estilo PDO) de cuál es la BD que

actuará como repositorio.

DAW 60

use Doctrine\ORM\ EntityManager;

//Obtener el EntityManager

$em = EntityManager::create(

array(

'driver' => 'pdo_sqlite',

'path' => 'database.sqlite‘

),

$config);

Page 61: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Creación de la base de datos desde el modelo:– Para ello se crea un pequeño ejecutable (crear.php) que usará el

fichero anterior (config.php):

– Que se lanzará como aplicación de consola:

DAW 61

//crear.php

use Symfony\Component\Console\Helper\HelperSet,

Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper,

Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper,

Doctrine\ORM\Tools\Console\ConsoleRunner;

require_once __DIR__ . '/config.php';

$helperSet = new HelperSet(array(

'em' => new EntityManagerHelper($em),

'conn' => new ConnectionHelper($em->getConnection()) ));

ConsoleRunner::run($helperSet);

$ php crear.php orm:schema-tool:create

Page 62: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo de uso (alta):

DAW 62

use Entity\Alumno;

require_once __DIR__ . '/config.php';

//Creamos un nuevo alumno

$elena = new Alumno(70212);

$elena->setNombre("Elena Nito del Bosque");

//Registramos a $elena en el EntityManager

$em->persist($elena);

//Cambiamos de nombre a $elena

$elena->setNombre("Elena Nito del Prado");

//Sincronizamos todos los cambios con la base de datos

$em->flush();

echo 'OK!';

Page 63: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo de uso (búsqueda y modificación):

DAW 63

require_once __DIR__ . '/config.php';

//Encontrar al alumno con matrícula = 70212

$alumno= $em->find('Entity\Alumno', 70212);

if($alumno) { //El EntityManager ha encontrado algún objeto de Entity\Alumno

echo 'He encontrado a un alumno (instancia de la clase ' . get_class($alumno)

. ') con nombre ' . $alumno->getNombre();

$alumno->setNombre("Cantalicio Floreal");

$em->flush();

}

else {

echo 'No he encontrado a nadie!!!';

}

Page 64: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo de uso (búsqueda general):

DAW 64

require_once __DIR__ . '/config.php';

//Un repository es el concepto de tabla relacional

// que contiene entidades de un tipo (clase) determinado

$repo = $em->getRepository('Entity\Alumno');

//Buscar el alumno con nombre = "Elena Nito del Bosque"

$elenas = $repo->findBy(array('nombre' => 'Elena Nito del Bosque'));

//Mostrar resultados

echo 'Encontrados ' . count($elenas) . ' alumnos con ese nombre:' . PHP_EOL;

foreach($elenas as $el) {

echo ' - ' . $el->getMatricula() . PHP_EOL;

}

Page 65: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo de uso (búsqueda DQL):– Extensión genérica similar a SQL.

DAW 65

require_once __DIR__ . '/config.php';

//Creamos una consulta DQL para buscar todos los alumnos del año 07

$alumnos = $em

->createQuery('SELECT a FROM Entity\Alumno a '

. ' WHERE a.matricula >= 70000 AND a.matricula <= 79999')

->getResult();

//Mostrar resultados

echo 'Encontrados ' . count($alumnos) . ' alumnos de ese año:' . PHP_EOL;

foreach($alumnos as $a) {

echo ' - ' . $a->getMatricula() . ": " . $a->getNombre() . PHP_EOL;

}

Page 66: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo de uso (borrar):

DAW 66

require_once __DIR__ . '/config.php';

//Buscamos el último matriculado

$alumnos = $em

->createQuery('SELECT a FROM Entity\Alumno a ORDER BY a.matricula DESC')

->setMaxResults(1) //sólo vamos a querer un resultado

->getResult();

if(!empty($alumnos)) {

$al = reset($alumnos);

echo 'El último número de matrícula es "' . $al->getMatricula()

. '" y corresponde al alumno "' . $al->getNombre() . '"' . PHP_EOL;

$em->remove($al);

$em->flush();

echo 'Alumno borrado!' . PHP_EOL;

}

Page 67: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Definición de relaciones:– En Doctrine las relaciones no se

establecen explicitando los identificadores

que se cruzan.

– En cambio se dice las cardinalidades de

las relaciones de entidad contra entidad:• Un Alumno tiene N Notas

• Una Nota pertenece a 1 Alumno.

– Doctrine utiliza una nomenclatura propia:

DAW 67

Alumnos

Notas

tienen

Alumno::notas es una relación OneToMany con Notas mapeada por Nota::alumno

Nota::alumno es una relación ManyToOne con Alumnos invertida por Alumno::notas

Alumno::notas Nota::alumnoOneToMany mapped by

ManyToOneinverted by

Page 68: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Definición de relaciones:– Cardinalidades disponibles:

• OneToMany (mapped by ManyToOne)

• ManyToOne (inversed by OneToMany)

• OneToOne (inversed/mapped by OneToOne)

• ManyToMany (inversed/mapped by ManyToMany)

– Las relaciones OneToMany y ManyToMany se representan en

Doctrine como instancias del interfaz

Doctrine\Common\Collections\Collection.

DAW 68

Page 69: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Definición de relaciones:– Direccionalidad:

• Las relaciones pueden ser uni- o bi-direccionales (inversibles).

– Propietarios de las relaciones: • Toda relación tiene uno de sus extremos que es propietario de la

misma.

• Las relaciones bidireccionales tiene tanto lado propietario como lado

inverso.

• Las relaciones unidireccionales sólo tienen lado propietario.

• El lado que es propietario es el que verifica Doctrine para propagar los

cambios.

• Referencia:http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html

DAW 69

Page 70: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Modificamos la clase Alumno:

DAW 70

/**

* @ORM\OneToMany(targetEntity="Entity\Nota", mappedBy="alumno")

* @var Collection

*/

private $notas;

public function __construct($matricula) {

//Inicializamos la colección. Doctrine interpreta Collections, no arrays!

$this->notas = new ArrayCollection();

$this->setMatricula($matricula);

}

/** @return Collection */

public function getNotas() {

return $this->notas;

}

/** @param Nota $nota */

public function addNota(Nota $nota) {

$this->notas->add($nota);

$nota->setAlumno($this);

}

Page 71: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Creamos la clase Nota:

continua …DAW 71

/** @ORM\Entity */

class Nota {

/**@ORM\Id()

* @ORM\Column(type="integer")

* @ORM\GeneratedValue(strategy="AUTO")

* @var int */

private $id;

/**@ORM\Column(type="string", length=255)

* @var string */

private $asignatura;

/**@ORM\Column(type="integer")

* @var int */

private $calificacion;

public function __construct($asignatura) {

$this->setAsignatura($asignatura);

}

Page 72: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Creamos la clase Nota:

DAW 72

/** @ORM\ManyToOne(targetEntity="Entity\Alumno", inversedBy="notas")

* @var Alumno|null */

private $alumno;

// Los getter y setter de $asignatura y de $calificacion

/** @return Alumno|null */

public function getAlumno() {

return $this->alumno;

}

/** @param Alumno $alumno */

public function setAlumno(Alumno $alumno) {

if($alumno === null || $alumno instanceof Alumno) {

$this->alumno = $alumno;

}

else {

throw new InvalidArgumentException('$alumno debe ser instancia de Entity\Alumno o null!');

}

}

}

Page 73: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

• Ejemplo (creación):

DAW 73

use Entity\Alumno,

Entity\Nota;

require_once __DIR__ . '/config.php';

$chema = new Alumno(080332);

$chema->setNombe('Chema Pamundi');

$em->persist($chema);

$nota = new Nota('Danzas eslavas');

$nota->setCalificacion(10);

$em->persist($nota);

$alumno->addNota($nota);

$em->flush();

Page 74: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

DAW 74

require_once __DIR__ . '/config.php';

$alumno = $em->find('Entity\Alumno', 080332);

if($alumno) {

echo 'Encontrado alumno: ' . PHP_EOL

. $alumno->getMatricula() . ' => ' . $alumno->getNombre() . '(' . get_class($alumno) . ')' . PHP_EOL

. 'y ' . $alumno->getNotas()->count() . ' Notas asociadas con él: ' . PHP_EOL;

foreach($alumno->getNotas() as $nota) {

echo ' ' . $nota->getAsignatura() . ': ' . $nota->getCalificacion()

. ' (' . get_class($nota) . ')' . PHP_EOL;

}

}

else {

echo 'No se ha encontrado alumno con matrícula=080332';

}

• Ejemplo (consulta):

Page 75: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

DAW 75

require_once __DIR__ . '/config.php';

$alumno = $em->find('Entity\Alumno', 080332);

if($alumno) {

echo 'Encontrado alumno: ' . PHP_EOL

. $alumno->getMatricula() . ' => ' . $alumno->getNombre() . '(' . get_class($alumno) . ')' . PHP_EOL

. 'y ' . $alumno->getNotas()->count() . ' Notas asociadas con él: ' . PHP_EOL;

foreach($alumno->getNotas() as $nota) {

$em->remove($nota);

}

$em->flush();

}

else {

echo 'No se ha encontrado alumno con matrícula=080332';

}

• Ejemplo (borrado):

Page 76: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Doctrine 2

DAW 76

require_once __DIR__ . '/config.php';

echo 'Obtener todas las matrículas de honor de el año 08: ' . PHP_EOL;

$alumnos = $em

->createQuery('SELECT a FROM Entity\Alumno a JOIN a.notas n WHERE‘

. ' n.calificacion >= :calificacion AND ‘

. ' a.matricula >= (:ano*10000) AND a.matricula < ((:ano+1)*1000)')

->setParameter('calificacion', 10)

->setParameter('ano', 8)

->getResult();

echo 'Se encontraron ' . count($alumnos) . ' casos:' . PHP_EOL;

foreach($alumnos as $al) {

echo ' ' . $alumno->getMatricula() . ' => ' . $alumno->getNombre() . PHP_EOL;

}

• Ejemplo (consultas con DQL):

Page 77: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Bases de Datos NoSQL Documentales

• No todo es SQL:– Más próximas a lo que sería el concepto

de un ORM.

– Son objetos que directamente se pueden

guardar y recuperar.

– Pero el sustrato de almacenamiento ya no

es una BD relacional.

– Formatos de almacenamiento

documental: XML, YAML, JSON o BSON.

– Bases de datos documentales puras:

MongoDB o CouchDB

– Otras variantes: Cassandra o Redis

– Extensiones de RDBMS: PostgresSQL o

InformixDAW 77

Page 78: Diseño de Aplicaciones Web - UPMlaurel.datsi.fi.upm.es/_media/docencia/asignaturas/daw/... · 2015-04-20 · API de MySQL en PHP Recuperación de registros de un SELECT (modo cursor):

Fernando PérezJosé M. Peña

Santiago GonzálezFrancisco Rosales

Santiago RodríguezAntonio LaTorreJuan Morales

Bibliografía

• Gilmore, W.J. (2010) Beginning PHP 5 and MySQL: From

Novice to Professional

• Romer, M. (2013). Persistence in PHP with the Doctrine 2

ORM. Concepts, Techniques & Practical Solutions.

• Tutoriales:

http://php.net/manual/es/set.mysqlinfo.php

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

http://doctrine-orm.readthedocs.org/en/latest/tutorials/getting-started.html

https://github.com/Ocramius/Doctrine2ORMSlidesTutorial (M. Pivetta)

DAW 78