- EL CONOCIMIENTO ES Y DEBE SER LIBRE -

jueves, enero 28, 2010

Modelando con Doctrine parte III

Teniendo el modelo de clases del post anterior procederemos a construir los métodos modificando el bootstrap.php y quedando del siguiente modo:
/***** bootstrap.php **********/
require_once(dirname(__FILE__) . '/doctrine-1.2.1/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));

Doctrine::loadModels('models');

$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL); //ACTIVAMOS LAS VALIDACIONES DE DOCTRINE
$manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);//PARA LA CREACION DE LOS METODOS

$dsn = 'mysql:dbname=comercial;host=127.0.0.1';
$user='root';
$password='123456';

$conn = Doctrine_Manager::connection(array($dsn, $user, $password));

La línea 9 le dice a Doctrine que cargué unas clases que vamos a crear en donde implementaremos los métodos. Estas clases deben de tener la siguiente forma [nombreClase]Table y las colocaremos dentro de la carpeta “models”.
En nuestro ejemplo en particular crearemos la clase UsuarioTable.
/**** UsuarioTable.php *******/
class UsuarioTable extends Doctrine_Table
{
public function GetAllUsuarios()
{
$q=Doctrine_Query::create()
->from('Usuario u')
->execute();
return $q->toArray();
}
public function GetAllCargosByOficina($idUsuario,$idOficina)
{
$q=Doctrine_Query::create()

->from('Oficina o')
->leftJoin('o.Cargo c')
->leftJoin('c.Asignacion a')
->leftJoin('a.Empleado e')
->leftJoin('e.Usuario u')
->where('o.id=?',$idOficina)
->andWhere('u.id=?',$idUsuario) 
->execute();

return $q->toArray(true); 
}
public function GetAllCargos($idUsuario)
{
$q=Doctrine_Query::create()

->from('Cargo c')
->leftJoin('c.Asignacion a')
->leftJoin('a.Empleado e')
->leftJoin('e.Usuario u')
->where('u.id=?',$idUsuario)

->execute();
return $q->toArray(true); 
}
}

Para probar el funcionamiento crearemos un archivo pruebaUsuario.php
/******** pruebaUsuario.php***********/
require_once("bootstrap.php");

$obj= Doctrine::getTable("Usuario");

print_r($obj->GetAllCargos(1));

print_r($obj->GetAllCargosByOficina(1,1));

Haciendo uso de DQL podemos ver que la consultas son bastante sencillas y demandan poco esfuerzo, la clave aquí es el método “toArray()” este método es una forma de serializar (Hydration, en realidad hay muchas formas de hydration) los datos en forma de arrays(objetos). El método “toArray()” puede recibir un parámetro booleano si este es false, nos mostrara el resultado teniendo en cuenta los “join” realizados en la consulta DQL. En caso sea true ocurrirá lo contrario.
Si es que estas trabajando por capas estos resultados hidratados son los que fluyen entre capas.
En mi particular experiencia si estas utilizando el patrón MVP (Model View Presenter) a estos datos hidratados le pasas la función “encode_json()” y se lo envías a la Vista (DHTMLX, GWT,FLASH, etc)
figura 1: MVC vs MVP

Quiero contarles que ahora esto muy metido en GWT (Google Web Toolkit) espero empezar a postear acerca de esta maravillosa idea de la gente de Google.

jueves, enero 07, 2010

Modelando con Doctrine parte II

figura 1
El modelo de clases de la figura 1 debemos de traducirlo a un formato YAML (un esquema que te permite administrar tus modelos de mapeo) para que doctrine genere el modelo de mapeo respectivo a partir de este. Pero como la mayoría de las personas (me incluyo) inmediatamente creamos nuestro modelo E/R y lo reflejamos en la BD elegida, a partir de ahí realizamos la ingeniería inversa que nos generara el mapeo respectivo.
Si Uds. se fijaron en el modelo de clases hay una relación de uno a uno (entre Usuario y Empleado) eso evidentemente va a generar proble mas en algunas BD, nosotros queremos que nuestra aplicación sea independiente de la BD, además que también podríamos tener una relación de mucho a muchos. Entonces la solución está en crear un YAML y partir de este generar el modelo de mapeo y como último paso crear la BD que hayamos elegido.

Para continuar necesitamos definir un estructura de proyecto del siguiente modo:

figura 2

En "data" se encontrara la data a llenar a la BD ( te la bajas de aquí ), en "models" se encuentra el modelo a mapear, en "yaml" se encuentra el esquema(te lo bajas de aquí). El archivo cli.php debe de lucir así:
/***** ARCHIVO CLI.PHP *****/
require_once(dirname(__FILE__) . '/doctrine-1.2.1/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));

$dsn = 'mysql:dbname=comercial;host=127.0.0.1';
$user='root';
$password='123456';

$conn = Doctrine_Manager::connection(array($dsn,$user,$password));

$config = array('data_fixtures_path' => 'data',
'models_path' => 'models',
'migrations_path' => '',
'sql_path' => '',
'yaml_schema_path' => 'yaml');

$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);
Doctrine brinda una interfaz de línea de comandos (CLI) que nos va a facilitar la creación de la BD, así como la generación del esquema y también los modelos a mapear.
  • Generamos el modelo: "c:\appserv\www\blogspot\php cli.php generate-models-yaml"
  • Creamos la BD: "c:\appserv\www\blogspot\php cli.php create-db"
  • Creamos las Tablas: "c:\appserv\www\blogspot\php cli.php create-tables"
  • Llenamos con Data: "c:\appserv\www\blogspot\php cli.php load-data"
OJO: Cuando generes el modelo no te olvides de añadir los "require_once" correspondientes.
/*** ARCHIVO BOOTSTRAP.PHP *****/
require_once(dirname(__FILE__) . '/doctrine-1.2.1/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));

$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL); //ACTIVAMOS LAS VALIDACIONES DE DOCTRINE
$manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);//PARA LA CREACION DE LOS METODOS

$dsn = 'mysql:dbname=comercial;host=127.0.0.1';
$user='root';
$password='123456';

$dbh = new PDO($dsn, $user, $password);
$conn = Doctrine_Manager::connection($dbh);

Los beneficios de generar la BD a partir de YAML son los siguientes:

  • Independencia de la BD.
  • Se esquematiza las relaciones uno a uno y mucho a muchos
  • Se esquematiza la herencia (podemos escoger como queremos que la herencia, de las múltiples formar que hay, sea implementada en la BD)
  • Se esquematiza la jerarquía de datos.


Debo de confesar que me da pereza aprender YAML ya me acostumbre a tratar el modelo mapeado directamente (clases php) yo normalmente hago lo siguiente:

  • Genero el Modelo E/R a partir del modelo de clases.
  • Creo la BD con sus respectivas relaciones y restricciones.
  • Creo el modelo de mapeado a partir de la BD.
  • Modifico a mano el modelo mapeado(relaciones one to one, many to many entre otros)

En el siguiente post implementaremos los métodos del modelo de clases