En este tema quiero mostrar el manejo de las claves foráneas en Yii framework mediante Active Record (AR).
Antes de usar AR para ejecutar consultas relacionales, necesitamos darle conocer a AR como una clase AR se relaciona con otra.
La relación entre dos clases AR está directamente asociada con la relación entre las tablas de la base de datos representadas por esas clases. Desde el punto de vista de la base de datos, una relación entre dos tablas A y B tiene tres tipos: uno-a-muchos (ej.: User
y Post
), uno-a-uno (ej.: User
y Profile
) y muchos-a-muchos (ej.: Category
y Post
). En AR, hay cuatro tipo de relaciones:
BELONGS_TO
: si la relación entre la tabla A y B es uno-a-muchos, entonces B pertenece a A (ej.:Post
pertenece aUser
);HAS_MANY
: si la relación entre la tabla A y B es uno-a-muchos, entonces A tiene muchos B (ej.:User
tiene muchosPost
);HAS_ONE
: este es un caso especial deHAS_MANY
donde A tiene a lo sumo un B (ej.:User
tiene a lo sumo unProfile
);MANY_MANY
: corresponde a la relación muchos-a-muchos en la base de datos Una tabla asociativa es necesaria para romper una relación muchos-a-muchos en relaciones uno-a-muchos, ya que la mayoría de los DBMS no soportan directamente la relación muchos-a-muchos. En nuestro esquema de la base de datos de ejemplo, la tablaPostCategory
sirve para este propósito. En terminología AR, podemos explicarMANY_MANY
como la combinación deBELONGS_TO
yHAS_MANY
. Por ejemplo,Post
pertenece a muchasCategory
yCategory
tiene muchosPost
.
Declarar relaciones en AR involucra sobreescribir el método relations() de CActiveRecord. El método devuelve un arreglo de configuraciones de relaciones. Cada elemento del arreglo representa una sola relación con el siguiente formato:
'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)
donde VarName
es el nombre de la relación; RelationType
especifica el tipo de relación, que puede ser una de las cuatro constantes: self::BELONGS_TO
, self::HAS_ONE
, self::HAS_MANY
y self::MANY_MANY
;ClassName
es el nombre de la clase relacionada a ésta clase AR; y ForeignKey
especifica la(s) clave(s) foránea(s) involucrada(s) en la relación. Pueden ser especificadas opciones adicionales al finad de cada relación (será descripto luego).
El siguiente código muestra como declarar las relaciones para las clases User
y Post
.
class Post extends CActiveRecord { public function relations() { return array( 'author'=>array(self::BELONGS_TO, 'User', 'authorID'), 'categories'=>array(self::MANY_MANY, 'Category', 'PostCategory(postID, categoryID)'), ); } } class User extends CActiveRecord { public function relations() { return array( 'posts'=>array(self::HAS_MANY, 'Post', 'authorID'), 'profile'=>array(self::HAS_ONE, 'Profile', 'ownerID'), ); } }
Ejemplo concreto (Productos y Categorias con sus modelos y crus creados con gii):
Modelo Productos:
public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'categoria' => array(self::BELONGS_TO, 'Categorias', 'id_categoria'), //Prestar atención a esta parte, ya que "categoria" será usado para acceder a dicho modelo y hacer consultas de una forma sencilla. //El modelo Categorias tiene los siguientes campos: id_categoria (pk) y desc_categoria ); }
– Por defecto Yii nos crea todas las relaciones cuando creamos el modelo, pero por ejemplo si agregamos una una tabla en nuestra base de datos podemos agregar la nueva relación manualmente.
– Por defecto también Yii crea los cruds pero no muestra el valor real de la FK, para poder mostrar los valores reales en las vistas (views), hacer lo siguiente:
view.php de Productos.
id_categoria', //Modificar esa linea por: array( 'name'=>'id_categoria', 'value'=>$model->categoria->desc_categoria, //Con esto se mostrará la descripción de la categoría en vez del id_categoria ),
_view.php de Productos.
Cambiar la linea donde se encuentra id_categoria por:
<b><?php echo CHtml::encode($data->getAttributeLabel('id_categoria')); ?>:</b> <?php echo CHtml::encode($data->categoria->desc_categoria); ?> //Con esto se mostrará la descripción de la categoría en vez del id_categoria <br />
admin.php de Productos.
Cambiar la linea donde se encuentra ‘id_categoria’, por:
array( 'name'=>'id_categoria', 'value'=>'$data->categoria->desc_categoria', //Con esto se mostrará la descripción de la categoría en vez del id_categoria 'filter'=>Categorias::getListCategorias(), //Esto ya es un agregado, muestra un combobox con todas las categorias para poder filtrarlas, si no lo ponemos usa el id_categoria por defecto //Debemos de crear una función estática en el modelo Categorias que se llame getListCategorias(), esto es totalmente opcional ),
Agregar la función al modelo Categorias (models/Categorias.php) para usar el filtro en la vista admin.php y también para crear o actualizar nuevos Productos:
public static function getListCategorias() { return CHtml::listData(Categorias::model()->findAll(),'id_categoria','desc_categoria'); }
Para crear o actualizar productos y que aparezca un combobox para elegir las categorías hacer lo siguiente:
Modificar el _form.php, justamente reemplazar la parte donde encontremos el id_categoria por el siguiente código:
<?php echo $form->labelEx($model,'id_categoria'); ?> <?php echo $form->dropDownList($model,'id_categoria',Categorias::getListCategorias(),array('empty'=>'seleccione categoria')); //Esto es lo agregado para mostrar el combobox, como verán usa la misma función estática que agregamos en el modelo Categorias ?>
Espero les haya servido de utilidad este tema, lo pueden adaptar todo según sus necesidades, es por eso que puse un ejemplo concreto.
Por más información sobre el tema, visitar este link