3.4 Modelo
El Modelo es la capa del patrón de diseño de la arquitectura MVC que interactúa con la base de datos, abstrayéndonos de escribir sentencias típicas SQL para la manipulación de datos. Encapsula toda la lógica de acceso a la base de datos. Éste nivel de abstracción se denomina ORM (Object Relational Mapping). Para su implementación nos hemos basado en el patrón de diseño
ActiveRecord descrito por Martin Fowler e implementado en el Framework
Rails.
Al crear una aplicación con OP_Framework debemos modelar los datos de nuestra estructura de base de datos relacional como clases en el modelo.
Estas clases se definen a nivel plataforma por lo que son accesibles por todas las aplicaciones de la misma.
OP_Framework/miplataforma/model
Veamos un ejemplo. Tenemos una aplicación denominada 'blog' con la siguiente base de datos.
Véase el apartado Convenciones para conocer las convenciones de nomenclatura de las tablasTenemos que crear por tanto las clases para modelar ésta estructura. Crearemos para ello un archivo denominado 'blog.php'
OP_Framework/miplataforma/model/blog.php
Ahora definiremos las clases que formarán muestro modelo. Por cada tabla escribiremos una clase con el mismo nombre que extenderá de 'OP_ModelActiveTable' de la siguiente forma.
class posts extends OP_ModelActiveTable
{
public function __construct() {
parent::__construct();
}
}
class comments extends OP_ModelActiveTable
{
public function __construct() {
parent::__construct();
}
}
El nombre de la clase, en este caso 'posts' y 'comments' debe coincidir con el nombre de la tabla de la base de datosPara la siguiente versión de OP_Framework está previsto la generación automática de éstas clases a partir de un archivo con la definición de la estructura de las tablasCon esto ya tenemos definido el modelo básico de nuestra aplicación 'blog'. Ya podriamos realizar operaciones de
inserción,
modificación y
borrado llamando a los siguientes métodos desde una acción en el controlador.
OP_Framework/miplataforma/apps/miaplicacion/modules/mimodulo/actions.class.phpclass postActions extends OP_Controller
{
public function add() {
$data = $this->context->getRequest()->getAllParameters('POST');
$posts = new Posts();
$posts->save($data);
}
public function delete() {
$posts = new Posts();
$id = array($this->context->getRequest()->getParameter('id_post', 'GET');
$posts->delete($id);
}
public function edit() {
$data = $this->context->getRequest()->getAllParameters('POST');
$id = array( 'id_post' => $this->context->getRequest()->getParameter('id_post'));
$data = array_merge($data, $id);
$posts = new Posts();
$posts->save($data)
}
}
En el ejemplo anterior hemos definido tres acciones,
add,
delete y
edit. Realizan operaciones de inserción, borrado y edición de datos respectivamente. Como se puede apreciar no hemos escrito ni una línea de SQL.
La variable
$data es un
vector asociativo que contiene como claves los nombres de los campos de la tabla y como valores los datos a insertar. Tanto para insertar como para modificar se utiliza el mismo método,
save($data). La diferencia está en que si se quiere modificar un registro se debe pasar en
$data el valor de la clave primaria.
Inserta un nuevo registro
$data = array('titulo' => 'texto del titulo');
$post->save($data);
Modifica un registro
$data = array('id_post' => 1, 'titulo' => 'texto del titulo modificado');
$post->save($data);
Haciendo Join's
En el ejempo tenemos dos tablas,
post y
comment que están relaciondas "uno a muchos". Para que el modelo tenga en cuenta esta relación se lo debemos indicar seteando las variables
$join_with y
$join_type en la clase de nuestro modelo. De esta manera indicamos con que tabla se relaciona y el tipo de relación que se establece.
Tipos de relación que podemos definir:
- one_to_one : uno a uno
- one_to_many : uno a muchos
- many_to_many : muchos a muchos
class posts extends OP_ModelActiveTable
{
public function __construct() {
parent::__construct();
$this->join_with = 'comments';
$this->join_type = 'one_to_many';
}
}
class comments extends OP_ModelActiveTable
{
public function __construct() {
parent::__construct();
}
}
Find()El método
find() devuelve un listado de registros en forma de vector asociativo. Aplicado a la clase
posts de nuestro modelo, devuelve un vector asociativo con los posts y los comentarios asociados.
OP_Framework/miplataforma/apps/miaplicacion/modules/mimodulo/actions.class.phpclass postActions extends OP_Controller
{
//...
public function list() {
$posts = new Posts();
$data = $posts->find();
}
En la variable
$data tendríamos un vector con la siguiente estructura según nuestro ejemplo de blog
$data = array(
'id_post' =>
'titulo' =>
'id_comment' =>
'comment' =>
)
Parámetros del método find()- Condiciones: Cadena con las codiciones que incluiría la clausula WHERE de una sentencia SQL.
- Orden: Se indica el campo y opcionalmente el criterio de ordenación (ASC o DESC).
- Límite: Se utiliza generalmente para la paginación de resultados. Es un número entero e indica el máximo número de resultados a mostrar
- Página: También tiene que ver con la paginación y se le pasa el número de página.
Ejemplo:
find('comment like "hola"','id_post DESC',5,2);
FindByPk()Este método nos permite buscar sólo un registro pasando el valor de la clave primaria. En nuestro blog de ejemplo lo vamos a utilizar para buscar un 'post' en concreto capturando el identificador por la url.
OP_Framework/miplataforma/apps/miaplicacion/modules/mimodulo/actions.class.phpclass postActions extends OP_Controller
{
//...
public function view() {
$data = $this->context->getRequest()->getAllParameters('GET');
$posts = new Posts();
$un_post = $posts->findByPk($data['id']);
}
//...
}
Validaciones
Es posible que los datos que pasemos al método 'Save()' para guardarlos no siempre cumplan una serie de condiciones de formato, tipo, etc. Para resolver ésto, antes de guardar podemos aplicar unas reglas de validación predefinidas en el modelo.
Las reglas de Validación que se pueden utilizar son:
- REQUIRED: Valida que siempre se le pase un valor.
- NUMERIC: Verifica que el tipo de dato de un número
- LETTERS_ONLY: Verifica que en la cadena solo aparecen letras
- ALPHANUMERIC: Verifica que sea una cadena alphanumérica
- NONZERO: El valor pasado no puede ser cero
- COMPARE: Compara que dos valores coincidan
- IN_RANGE: Comprueba que un valor se encuentra dentro de un rango de valores
- IN_RANGE_LENGTH: Comprueba la longitud de la cadena se encuentre dentro del rango
- EMAIL: Verifica que sea una dirección de email bien formada
¿Cómo utilizar e incluir las validaciones en nuestro modelo?Para incluir una o varias validaciones en nuestro modelo hay que incluir el método 'addRules()' en nuestra clase. Dentro del método agregamos las validaciones como se muestra en siguiente ejemplo. Hemos incluido todos los tipos de validación disponibles para ver un ejemplo de utlización de cada una.
class posts extends OP_ModelActiveTable
{
public function __construct() {
parent::__construct();
}
public function addRules() {
$this->validator->addRule(array('name','lastname', 'edad'), REQUIRED );
$this->validator->addRule(array('name','lastname'), LETTERS_ONLY );
$this->validator->addRule('name', COMPARE, array('message'=>'No coincide los valores de los campos name y lastname(solo para testing)', 'compare'=>'lastname') );
$this->validator->addRule('edad', NONZERO );
$this->validator->addRule('edad', NUMERIC );
$this->validator->addRule('name', IN_RANGE_LENGTH, array('min' => 6, 'max' => 10));
$this->validator->addRule('edad', IN_RANGE, array('message' => 'La edad deberá encontrarse entre 18 y 99','min' => 18, 'max'=>99));
$this->validator->addRule('email', EMAIL );
}
}
Hemos agregado una serie de reglas de validación, ahora sólo necesitamos saber la lista de errores producidos. Para ello, desde el controlador (la acción) tenemos que llamar al método 'getErrorsValidation()'. Nos devolverá una cadena en formato {ul}{li}{/li}{/ul} en el caso que se produzca algún error de validación.
OP_Framework/miplataforma/apps/miaplicacion/modules/mimodulo/actions.class.phpclass postActions extends OP_Controller
{
public function add() {
$data = $this->context->getRequest()->getAllParameters('GET');
$posts = new Posts();
$posts->save($data);
$errors_list = $posts->getErrorsValidation();
}
}
Una posible salida generada en $errors_list podría ser la siguiente:
<ul> Campo requerido
<li> El campo Title es obligatorio</li>
</ul>
«««
Configuración |
Vista »»»