Bases de datos (AR) en Yii

| 2013-04-29 | No hay comentarios »

Active Record en Yii:

Aunque la DAO de Yii puede manejar virtualmente cualquier tarea relacionada con la base de datos, lo más probable es que gastemos el 90% de nuestro tiempo escribiendo algunas sentencias SQL relacionadas con la ejecución de las operaciones CRUD comunes. Es tambien dificil mantener nuestro código cuando éste está mezclado con sentencias SQL. Para solucionar estos problemas, podemos usar los Registros Activos (Active Record).

Registro Activo (AR) es una técnica popular de Mapeo Objeto-Relacional (ORM). Cada clase AR representa una tabla de la base de datos (o vista) cuyos atributos son representados como las propiedades de la clase AR, y una instancia AR representa una fila en esa tabla. La operaciones CRUD comunes son implementadas como metodos de la clase AR. Como resultado, podemos acceder a nuestros datos de una manera más orientada a objetos.

El soporte para AR está limitado por el DBMS. Actualmente, solo los siguientes DBMS están soportados:

Ejemplo concreto (Productos):

-- ----------------------------
 -- Table structure for `productos`
 -- ----------------------------
 CREATE TABLE `productos` (
 `id_producto` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `descripcion` varchar(150) NOT NULL,
 PRIMARY KEY (`id_producto`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Creando Registros

$producto=new Productos;
$producto->descripcion='TEST';
$producto->save();

Leyendo Registros

// encontrar el primer registro que cumpla la condición especificada
$producto=Productos::model()->find($condition,$params);
// encontrar la fila con la clave primaria especificada
$producto=Productos::model()->findByPk($postID,$condition,$params);
// encontrar la fila con los valores de los atributos especificados
$producto=Productos::model()->findByAttributes($attributes,$condition,$params);
// encontrar la primer fila usando la sentencia SQL especificada
$producto=Productos::model()->findBySql($sql,$params);

La forma sería algo así:
$producto=Productos::model()->find('id_producto=:id', array(':id'=>1));

Otra forma:
$criteria=new CDbCriteria;
$criteria->select='descripcion';  // seleccionar solo la columna 'title'
$criteria->condition='id_producto=:id';
$criteria->params=array(':id'=>1);
$producto=Productos::model()->find($criteria); // $params no es necesario

Otra forma:
$producto=Productos::model()->find(array(
    'select'=>'descripcion',
    'condition'=>'id_producto=:id',
    'params'=>array(':id'=>1),
));

Para poder acceder al registro: 
echo $producto->descripcion; echo $producto->id_producto;

Cuando múltiples filas de datos coinciden con una condición de consulta especificada, podemos traerlas todas juntas usando los siguientes métodos findAll, cada uno de los cuales tiene su método contrapartefind, que ya mencionamos anteriormente.

// encontrar todas las filas que cumplan la condición especificada
$producto=Productos::model()->findAll($condition,$params);
// encontrar todas las filas con la clave primaria especificada
$producto=Productos::model()->findAllByPk($postIDs,$condition,$params);
// encontrar todas las filas con los valores de atributos especificados
$producto=Productos::model()->findAllByAttributes($attributes,$condition,$params);
// encontrar todas las filas usando la sentencia SQL especificada
$producto=Productos::model()->findAllBySql($sql,$params);

Para poder acceder a los registros:

<?php foreach($producto as $row): ?>
<?php echo $row->id_producto; ?>
<?php endforeach; ?>

Además de los métodos find y findAll descriptos anteriormente, por conveniencia también se proveen los siguientes métodos:

// obtener el número de filas que cumplan la condición especificada
$n=Productos::model()->count($condition,$params);
// obtener el número de filas usando la sentencia SQL especificada
$n=Productos::model()->countBySql($sql,$params);
// comprobar si existe al menos una fila que cumpla la condición especificada
$exists=Productos::model()->exists($condition,$params);

Actualizando Registros

Luego de que una isntancia AR sea rellenada con valores, podemos cambiarlos y volver a guardarlos en la tabla de la base de datos.

$producto=Productos::model()->findByPk(1);
$producto->descripcion='nueva descripcion';
$producto->save(); // guardar cambios en la base de datos

// actualizar las filas que coincidan con la condición especificada
Productos::model()->updateAll($attributes,$condition,$params);
// actualizar las filas que coincidan con la condición especificada y con la(s) clave(s) primaria(s)
Productos::model()->updateByPk($pk,$attributes,$condition,$params);
// update counter columns in the rows satisfying the specified conditions
Productos::model()->updateCounters($counters,$condition,$params);

Borrando Registros

$producto=Productos::model()->findByPk(1); // asumiendo que existe un post cuyo ID es 10
$producto->delete(); // borra la fila de la tabla de la base de datos

// borra todas las filas que coincidan con la condición especificada
Productos::model()->deleteAll($condition,$params);
// borra todas las filas que coincidan con la condición especificada y con la(s) clave(s) primaria(s)
Productos::model()->deleteByPk($pk,$condition,$params);

Validación de Datos

Cuando insertamos o actualizamos una fila, frecuentemente necesitamos comprobar que los valores de las columnas cumplen ciertas reglas. Esto es especialmente importante si los valores de la columna son provistos por usuarios finales. En general, nunca debemos confiar en nada que provenga del lado del cliente.

AR ejecuta la validación de datos automáticamente cuando se invoca a save(). La validación está basada en las reglas especificadas en el método rules() de la clase AR. Para más detalles acerca de como especificar reglas de validación, ver la sección Declarando Relgas de Validación. A continuación está el flujo de trabajo típico necesario para guardar un registro:

if($post->save())
{
    // los datos son válidos y están insertados/actualizados exitosamente
}
else
{
    // los datos no son válidos. Llamar a  getErrors() para obtener los mensajes de error
}

Cuando los datos a insertar o actualizar son enviados por usarios finales en un formulario HTML, necesitamos asignarlos a las correspondientes propiedades AR. Podemos hacerlo como sigue:

$post->title=$_POST['title'];
$post->content=$_POST['content'];
$post->save();

Si existen muchas columnas, veremos una larga lista de dichas asignaciones. Esto se puede aliviar haciendo uso de la propiedad attributes como se muestra a continuación. Más detalles pueden ser encontrados en la sección Asegurando las Asignaciones de Atributos y en la sección Creating Action.

// asumimos que $_POST['Post'] es un arreglo de valores de columna indexados por nombres de columna
$post->attributes=$_POST['Post'];
$post->save();

Comparando Registros

Como las filas de las tablas, las instancias AR están identificadas de manera única por los valores de su clave primaria. Por lo tanto, para comparar dos instancias AR, solo es necesario comparar los valores de sus claves primarias, asumiendo que pertenezcan a la misma clase AR. Sin embargo, una manera más simple es llamar aCActiveRecord::equals().

Personalización

CActiveRecord provee algunos métodos que pueden ser sobreescritos en las clases que la heredan para personalizar su flujo de trabajo.

  • beforeValidate y afterValidate: estos métodos son invocados antes y después de que la validación sea ejecutada.
  • beforeSave y afterSave: estos métodos son invocados antes y después de que la instancia AR sea guardada.
  • beforeDelete y afterDelete: estos métodos son invocados antes y después de que la instancia AR sea borrada.
  • afterConstruct: este método es invocado por cada instancia AR creada usando el operador new.
  • afterFind: este método es invocado por cada instancia AR creada como resultado de una búsqueda.

Transacciones con AR

Cada instancia AR contiene una propiedad llamada dbConnection que es una instancia de CDbConnection. Por lo tanto podemos utilizar la característica transaction provista por el DAO de Yii si se desea cuando trabajamos con AR:

$model=Productos::model();
$transaction=$model->dbConnection->beginTransaction();
try
{
    // encontar y guardar son dos pasos que pueden ser intervenidos por otra solicitud
    // por lo tanto usaremos una transacción para asegurar su consistencia e integridad
    $producto=$model->findByPk(1);
    $producto->title='nueva descripcion';
    $producto->save();
    $transaction->commit();
}
catch(Exception $e)
{
    $transaction->rollBack();
}

Por más info ingresar a este link.

 

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.

Posts Relacionados

  • Phalcon – Framework PHP – Extensión de C
  • Reportes gráficos en Yii
  • Backup en Yii
  • Manual intermedio de Yii framework (PHP)



SEGUÍNOS EN FACEBOOK


GITHUB