En esta ocasión vamos a acelerar el desarrollo de nuestras aplicaciones, gracias a la técnica Object Relational Mapper. Para ello, vamos a utilizar una biblioteca bastante madura, sencilla y muy bien documentada, llamada DataMapper.
Instalación y configuración
¿Qué vamos a necesitar?
1.- CodeIgniter (Este tutorial trata sobre la versión 1.7.3)
2.- DataMapper (1.8.0 es la más actual, en el momento de escribir este tutorial)
La instalación de CodeIgniter es muy sencilla, como ya vimos en el anterior tutorial. Para añadir DataMapper al proyecto, simplemente tenemos que copiar el contenido del directorio "application" dentro del directorio "system/application" de nuestro CodeIgniter.
Configuración
Si todo ha ido bien, deberíamos poder configurar DataMapper editando el fichero "system/application/config/datamapper.php". En general, aunque dependiendo de la estructura de tu base de datos, para lo único que necesitas editar este fichero es para añadir las extensiones que queramos utilizar, ya hablaremos más adelante de esto. En cualquier caso, si tienes dudas, la documentación ofrece una tabla con la descripción de todos los parámetros de configuración.
Estructura de la base de datos
En este ejemplo vamos a dar los primeros pasos para crear un juego de rol, así que los modelos que vamos a necesitar en la base de datos serían:
· Usuarios ( users: id, username, password, created, updated )
· Personajes ( players: id, name, life, created, updated )
· Clases de personajes ( characters: id, name, created, updated )
· Objetos que llevan los personajes ( items: id, name, quantity, created, updated )
Aunque se puede configurar de otra manera a la hora de preparar el modelo de CodeIgniter, por defecto debemos escribir el nombre de las tablas de la base de datos en el plural del inglés. Básicamente hay que añadirle una s al final de la palabra, salvo las excepciones en las que terminan en y. Por ejemplo para el modelo pony, el nombre de la tabla sería ponies.
Tablas intermedias para las relaciones
DataMapper permite relaciones del tipo One to One, One to Many y Many to Many.
En nuestro juego, cada usuario puede tener un personaje (One to One), a su vez, un personaje sólo puede ser de un tipo (One to One). Sin embargo, un personaje puede llevar muchos objetos (One to Many).
Todas estas relaciones necesitan sus tablas en la base de datos, con esta estructura:
· players_users: id, player_id, user_id, created, updated
· characters_players: id, character_id, player_id, created, updated
· items_players: id, item_id, player_id, created, updated
El nombre de la tabla sería, en orden alfabético y plural, los dos nombres de las tablas que queremos relacionar.
Preparando los modelos en CodeIgniter
Ahora es cuando viene lo bueno de verdad, vamos a preparar los siguientes modelos en system/application/models:
User.php
<?php
class User extends DataMapper {
var $has_one = array('Player');
}
Un usuario nada más que puede tener un personaje.
Player.php
<?php
class Player extends DataMapper {
var $has_one = array('User', 'Character');
var $has_many = array('Item');
}
Un personaje puede tener un único usuario y una única clase, pero puede tener muchos objetos.
Character.php
<?php
class Character extends DataMapper {
var $has_many = array('Player');
}
Una clase de personaje puede pertenecer a su vez a muchos personajes, esto nos sirve para listar todos los personajes de una clase concreta.
Item.php
<?php
class Item extends DataMapper {
var $has_one = array('Player');
}
En nuestro juego, los objetos son físicos y no pueden pertenecer a varios personajes al mismo tiempo, si quisiéramos extender el juego, lo suyo sería hacer también clases de objetos.
Te lo creas o no, esa es la configuración más básica de nuestros modelos de objeto, del resto se encarga DataMapper... ¿cuánto tiempo has ahorrado preparando los modelos? =)
Cosas a destacar:
- Los modelos extienden a DataMapper, en lugar de a Model.
- Si queremos especificarle el nombre de la tabla -> var $table = 'tabla';
- Puedes consultar la documentación sobre la creación de modelos para ampliar información.
Controladores
Vamos a poner en acción esos modelos que hemos preparado para que veas el potencial. ¿Qué tal si creamos a nuestro primer usuario?:
// Lo primero es cargar nuestro modelo y
// crear una instancia del mismo
$this->load->model('User');
$user = new $this->User();
// Directamente le asignamos las variables
$user->username = 'piradoiv';
$user->password = md5('1234');
// Y lo guardamos en la base de datos
$user->save();
DataMapper se encargará de establecer automáticamente los campos created y updated.
Vamos a practicar un poco más creando un par de tipos de personajes:
$this->load->model('Character');
$barbarian = new $this->Character();
$assassin = new $this->Character();
$barbarian->name = 'Bárbaro';
$assassin->name = 'Asesina';
$barbarian->save();
$assassin->save();
Ahora vamos a preparar las relaciones, con un jugador:
// Voy a suponer que estamos en otro
// controlador diferente, así que necesitamos
// volver a cargar los modelos
$this->load->model('User');
$this->load->model('Player');
$this->load->model('Character');
// Instanciamos los modelos
$user = new User();
$player = new Player();
$character = new Character();
// Usamos un poco de magia para
// recuperar el usuario que habíamos
// creado y a mi personaje favorito
// del Diablo II, la asesina :P
$user->get_by_username('piradoiv');
$character->get_by_name('assassin');
// Ahora se lo vamos a asignar
// a un personaje nuevo
$player->name = 'Pirado IV';
$player->save();
// Para guardar relaciones, basta con
// invocar el método save, pasándole
// como parámetros los objetos
// relacionados.
$player->save(array($user, $character));
Como puedes ver, podemos hacer búsquedas con get_by_field. Otra manera de hacer exactamente lo mismo sería:
$user->get('username', 'piradoiv');
// Aprovechamos para actualizarle la
// contraseña al usuario
$user->password = md5('hoygan');
$user->save();
Como ves, save() también actualiza la base de datos.
Generando listados
Otra de las típicas cosas que vamos a querer hacer, es generar listados de objetos, vamos a aprovechar la base de datos tal y como la tenemos para practicar:
$characters = new Character();
$characters->get();
foreach($characters->all as $character) {
echo "$character->name<br />";
}
Si estás familiarizado con ActiveRecord, te sentirás a gusto filtrando y ordenando los listados:
// Ordenar por ID descendiente
$characters->order_by('id', 'desc')->get();
// O buscar con LIKE y limitar a un resultado
$characters->like('character', 'assa')->limit(1)->get();
Tienes todos los ejemplos en la documentación sobre el método Get
Accediendo a las relaciones
¡Casi se me olvida ponerlo!, para acceder a las relaciones basta con ejecutar un get(); en la propiedad a la que quieras acceder. Vamos a verlo con un ejemplo:
// Cargamos el modelo del usuario,
// los demás no nos van a hacer falta
// porque vienen incluídos al acceder
// a la relaciones.
$this->load->model('User');
$user = new $this->User();
$user->get_by_username('piradoiv');
// Cargamos nuestro personaje...
$user->player->get();
// Eso nos descargará únicamente los
// jugadores que tengan relación con
// ese usuario, vamos a descargarnos
// todos los items que tiene este
// usuario
$items = $user->player->item;
$items->get();
foreach($items->all as $item) {
echo "$item->name<br />";
}
Dos cositas más
DataMapper ha sido programado de manera que se le pueden crear extensiones de una manera sencilla. Entre otras, la versión actual incluye:
· Una extensión para generar arrays de tus objetos:
$character->get_by_name('barbarian');
print_r($character->to_array());
· Importar y exportar objetos desde ficheros CSV
$characters->get();
$characters->csv_export('/fichero.csv');
Tiene unas cuantas más, lo mejor es que le eches un ojo a la documentación. Lo que tienes que tener en cuenta es que para utilizar estas extensiones, debes añadirlas al fichero de configuración (system/application/config/datamapper.php):
$config['extensions'] = array('array', 'json', 'csv');
La otra cosa interesante de DataMapper es que funciona nativamente con las funciones de acceso a la base de datos de CodeIgniter, por lo que podremos utilizar el Profiler para encontrar cuellos de botella en nuestra aplicación. Si encontramos algo que necesitemos pulir, podemos optimizarlo al detalle con consultas directas ActiveRecord, SQL, ...
¡Cambio y corto!
Espero que este tutorial te haya servido de ayuda, ahora eres tú el que debes echarle un ojo en profundidad a la documentación.
http://datamapper.wanwizard.eu/
Y si aun así necesitas una mano, siempre estamos por #mv.nerd en Quakenet y #mvnerds en Twitter.