Archive for April 14th, 2007

Hayden es muy inteligente para nosotros …

Saturday, April 14th, 2007

Hayden Panettiere (La porrista de "Heroes"), ha iniciado una campaña de concientización sobre el mal uso de las herramientas de comunicación en internet (como los IM y chats) por parte de "cyberpredators", acosadores de niños y pedófilos, la campaña (que incluye un anillo con la frase 2smrt4u (too smart for you ó muy inteligente para tí) muy al estilo de la bandita livestrong) busca crear conciencia entre los jovenes sobre los peligros del Internet.

Aquí un vínculo al poster: http://www.2smrt4u.com/ad_march.html

y el vinculo a la página principal de 2smrt4u.

Nota:Como cosa rara en este mundo del internet, alguien ya compró 2SMART4U (solo varía a A); ahora aparece un "under construction" pero mañana capaz alguien le saca una página de mamadera de gallo como a google
http://www.gooogie.co.uk/

Eso me recuerda tambien el caso famoso de las bandas de gel Livestrong, se convirtieron en un artículo "fashion" donde todo el mundo quería una para estar "in"; llegandose a subastar por altas sumas en eBay; sin embargo, la bandita nació inicialmente como un articulo de caridad (vendida a un dolar cada una, aqui en Venezuela llegué a verlas en 50 mil Bs. (algo más de 25 US$ C/U)) y Lance Armstrong (el ciclista creador de la idea de la bandita) se sintió muy enojado y ofendido cuando esta gran cantidad de fondos de eBay y otras casas de subasta (y las ventas astronómicas en muchos países), nunca llegaron a ninguna fundación de lucha por el cancer ni nada parecido.
Porque como dicen las ULTRAFABULOSAS,  ahorrar no es chic, hay que derrochar!, la caridad no forma parte de lo fashion …

Esperemos que no le pase lo mismo al anillo …

Object Relational Mapping en PHP5 (capitulo 1)

Saturday, April 14th, 2007

Introducción:

Hace algún tiempo andaba persiguiendo la idea, el concepto de ORM (Object Relational Mapping) implica trasladar la lógica relacional de una tabla:
TABLA -> CAMPOS -> Registros
a un lógica de objetos, donde cada tabla sea representada por una clase, cada campo (atributo) sea representado por una propiedad de dicha clase y cada método represente una operación posible a realizar sobre dichos datos.
El concepto de capa de datos está tan estrechamente relacionado al concepto de Base de datos, que realmente indicar que se puede programar con nulo SQL es obviar la potencia de SQL (y restringir en muchas formas a la capa de datos); de hecho, le leído por ahi que grandes aplicaciones hechas con este concepto de abstracción, han cambiado a usar nuevamente SQL en su capa de datos y es que de hecho, RoR será todo lo que quieran, pero principalmente es … lento …
volviendo al tema de ORM, la lógica de objetos implicada en el acceso a los datos deviene de perl::dbi (aunque los de ruby digan que su invento el activerecord es genialidad propia) y consiste en:
una clase por tabla
class inscritos :
cada atributo (propiedad) representa un campo de la DB:
inscritos.nombre, inscritos.apellido, inscritos.cedula

y cada método, una operación realizable a la DB:

inscritos = new activerecord ('inscritos');

inscritos->nombre = 'Jesus'

inscritos->apellido = 'Lara'

inscritos->cedula = '13264658'

inscritos->fecha_inscrito = date()

inscritos->save() //método que me permite guardar el registro en la DB.

Como se ve, inscritos es un OBJETO y dentro de él contenemos el “mapa fisico” (lo que en teoría se conoce como la metadata de la tabla) de la tabla, con sus relaciones, indices primarios, tipos de datos, etc.

Hasta el momento existian 2 posibilidades conocidas (y un sinfin de desconocidos, aqui va otra más) para operar ORM en PHP, una de ellas PROPEL, este permitía tener un mapa completo de la tabla, pero debia ser “creado” usando un estilo “alternativo” de XML llamado YAML; si la tabla cambiaba de forma, habia que destruir el YAML y hacer uno nuevo, uno por cada tabla (no muy práctico tomando en cuenta que RoR hace este mapeo “on fly”).
el otro, CREOLE, es más una capa de abstracción que un ORM en sí …
CakePHP agrega su aproximación a un ActiveRecord con todas las limitaciones que un código PHP4 puede tener, entre ellos que te exige una forma “particular” de tener la tabla (como por ejemplo, un id en cada tabla para que pueda “identificar” quien es el PK (primary key) de la tabla); esto tiene algunas consecuencias, una tabla como esta:

CREATE TABLE  `ejemplos_ajax`.`dpt_parroquias` (

`id_entidad` int(8) unsigned NOT NULL,

`id_municipio` int(8) unsigned NOT NULL,

`id_parroquia` int(8) unsigned NOT NULL,

`parroquia` varchar(75) DEFAULT NULL,

`codigoe` char(3) NOT NULL,

`capital` varchar(128) DEFAULT NULL,

PRIMARY KEY (`id_entidad`,`id_municipio`,`id_parroquia`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1

Con un indice PK compuesto de 3 campos no es entendible por CakePHP (y en sistemas complejos son muchas más las tablas “extrañas” que las básicas tablas de blog id, nombre, apellido …).

Decidi hacer esta saga de “Haga su ORM en PHP5 en algunos pasos” … (y despues comase una pizza) …

Una idea inicial de “que debe hacer el ORM”:

Lo que perseguimos es llegar a un código (yo ya llegué, jijiji, lo iré publicando en seguidilla en esta serie de posts) que sea PHP5-only y con la potencia suficiente para realizar cosas como:

//cargar un activerecord de la tabla dpt_entidades

$orm = $db->activerecord('dpt_entidades');//decirle que se traiga TODOS los datos

$result = $orm->find_all();

//e iterar sobre ellos elegantemente en una consulta objeto $result->campo y no via array $result[array]

//usando do while

do {

echo $result->cod_entidad . ' ' . $result->entidad . ' ' . $result->capital . '<br/>';

} while($result->next());

//o usando foreach

foreach ($result as $value) {

echo $value->cod_entidad . ' ' . $value->entidad . ' ' . $value->capital . '<br/>';

}

Tambien crear filtros y sentencias más complejas:

//condicion between

$orm->cod_entidad->between('FAL', 'MON');

//ordenar:limit and offset (method chaining):

$orm->order_by('cod_entidad')->limit(10)->offset(0);

//donde el campo mostrar sea igual a uno

$orm->mostrar->where(1);

//y el campo entidad sea igual a Monagas O igual a Lara o distinto de Nulo

esto de aqui abajo, se conoce como "method chaining" y consiste en encadenar uno tras otro los métodos comunes, es una de las posibilidades de PHP5

$orm->entidad->where('Monagas')->where('Lara', true)->where(null, true);

//y por favor ordenalo por entidad

$orm->entidad->sort();

tambien puedes hacer LIKE

$orm->entidad->like('L')->like('M', 1,true);

o estructuras como IN, EXISTS y otras de las condiciones WHERE en SQL

$cod_entidad = array('DCA', 'MON', 'LAR', 'ZUL');

$orm->cod_entidad->in($cod_entidad)->in('SELECT cod_entidad FROM dpt_ciudades', true, true);//pido un ORM de la tabla dpt_ciudades

$ciudades = $db->activerecord('dpt_ciudades');

//indico que campos deseo en la consulta

$ciudades->select('id_entidad, count(*) as cantidad');

//y agrupo por el campo id_entidad

$ciudades->id_entidad->groupby();

//ademas, creo una condicion group (having)

$ciudades->having('count(*)', '>30'); //solo aquellas entidades con más de 30 ciudades

Tambien podemos ver algo mas complejo como:

$ciudades->select('DISTINCT e.entidad,  e.id_entidad, ciudad');

$ciudades->id_entidad->join('dpt_entidades e', 'e.id_entidad', 'LEFT');

$ciudades->limit(150);

$ciudades->id_entidad->between(6, 8);

/* esto causa una sentencia como:

SELECT DISTINCT e.entidad, e.id_entidad, ciudad FROM dpt_ciudades LEFT JOIN dpt_entidades e ON (dpt_ciudades.id_entidad=e.id_entidad) WHERE dpt_ciudades.id_entidad BETWEEN '6' AND '8' LIMIT 150

*/

Tambien se pueden operar los datos:

$entidad = $orm->create();

$entidad->cod_entidad = 'PDF';

$entidad->entidad = 'Principado del Distrito Federal';

$entidad->capital = 'Elbonia';

$entidad->save(); //al ser un nuevo registro, se inserta en la base de datos

echo "la ultima entidad guardada fue {$entidad->last_id}";

Donde se ha visto?

CodeIgniter (un framework para PHP4/5) tiene un conjunto de funciones que se aproximan a la comodidad de crear sentencias complejas como SQL de arriba pero usando solo métodos de objeto (de hecho, codeIgniter es donde he sacado muchas de las ideas), el único inconveniente de CodeIgniter es que usa a PROPEL, por ende, hay que crear los mapas de las tablas a mano usando YAML.
Sin embargo, todas las extensiones de conexión a datos de PHP5 soportan entregar metadata con las consultas, y al estilo RoR es simplemente hacer algo (internamente) como:
$result = $this->_db->query(”SHOW COLUMNS FROM {$tabla}”);
y ese SHOW COLUMNS devolvera toda la metadata necesaria para recrear la estructura de la DB dentro de un objeto.
simple no?

Dormir y Despertar:

No tanto, leer y parsear la DDLde cada tabla es un proceso lento (aunque en PHP5 no es tan severamente lento como RoR); sin embargo, aqui otra característica de PHP5 corre en nuestro auxilio, existe la posibilidad de “serializar” un objeto PHP5 en forma de una cadena binaria y guardarla en disco o en un DB, haciendo caché de la metadata y salvando milisegundos preciosos para nuestra aplicación.
Nota: para serializar un objeto se procede de la siguiente manera:
$inscritos = $db->activerecord(’inscritos’);
$cache = serialize($inscritos);

y se procede a guardarlo en una DB o en un archivo en disco, algo como:
file_put_contents(’cache_inscritos.tmp’, $cache);

para restaurarlo se hace:
$cache = file_get_contents(’cache_inscritos.tmp’);
y luego se le “restaura” a la forma objeto:
$inscritos = unserialize($cache);

Y como se restaura automáticamente la conexión?, es decir, los recursos (conexiones a DB, sockets, etc) son cosas inserializables, entonces PHP5 pone a nuestra disposición los métodos mágicos __sleep y __wakeup

public function __sleep() {
$this->connection->close();
}
__sleep se ejecuta previo a la serializacion de un objeto, te permite limpiar variables temporales para no ocupar espacio, cerrar conexiones a la DB, etc

luego
public function __wakeup() {
$this->connection->connect();
}

el metodo __wakeup se ejecuta cuando un objeto es “despertado” de una serialización, en este caso, podemos volver a conectarnos a la DB, revisar si todo está correcto, etc.

Y en la proxima …

En la próxima entrega explicaré como lograr iterar usando foreach sobre un objeto complejo y sobre como lograr acceder a los campos usando notación de objeto ($inscritos->nombre, $inscritos->cedula, etc).