martes, 19 de octubre de 2010

KumbiaPHP - CRUD sencillo en KumbiaPHP usando AJAX y JQuery

En este universo de Frameworks PHP, existe uno que personalmente es mi favorito, bueno empecé a programar con Frameworks en PHP utilizando este, y me atrapó su filosofía que facilita en gran manera al programador, este es Kumbiaphp, para quien no sepa este es un Framework similar a CakePHP, pero desarrollado por una comunidad hispanohablante por lo que para todos los que hablamos esta maravillosa lengua nos viene perfecto. Está orientado al paradigma ActiveRecord y nos provee de un patrón MVC [Modelo-Vista-Controlador].



De paso quiero agradecer a los desarrolladores del proyecto por tan maravillosa herramienta.

Bueno vamos a saltarnos la configuración que no es más que descargar el paquete y desempaquetarlo dentro de nuestro web server, luego modificar algo del archivo config y ya tenemos todo listo, les dejo un enlace sobre esto Instalar Kumbiaphp

En este caso vamos a trabajar con la version 1.0 Spirit
Suponemos que ya tenermos todo nuestro entorno configurado, vamos a trabajar con una tabla sencilla:

Codigo SQL
create table marca (
id int auto_increment,
nombre varchar(55), 
siglas varchar(2), 
primary key (id) );

Primero crearemos nuestro archivo modelo, el cual será quien verá las transacciones con la BD, en Kumbiaphp este se ubica en [directorio de nuestra app]/app/models/
Dentro crearemos un archivo Marca.php

Marca es una clase que hereda de ActiveRecord
<?php
class Marca extends ActiveRecord {

//retorna un array de objetos cuyos campos son los mismos de la tabla Marca
//$page : es el numero o indice de pagina
//$ppage: es el numero de filas o registro por pagina

public function paginar($page, $ppage=10){
//order: permite especificar el campor por el cual se quiere se ordene el resultado
return $this->paginate("order: 2 ASC", "page: $page", "per_page: $ppage");
  }

/*
retorna todos los elementos de la tabla ordenados por el campo de ordinal 2, en este caso nombre
*/
  public function listar(){
         return $this->find("order: 2 asc");
 }

}
?>


Ahora crearemos nuestro controlador, este es quien se encargará de dirigir las acciones de los usuarios, en Kumbiaphp solo hay que crear un archivo en la carpeta [directorio de nuestra app]/app/controllers/ , siguiendo la convencion [nombre del controlador]_controller.php, para este ejemplo será marca_controller.php

MarcaController hereda de ApplicationController
<?php
class MarcaController extends ApplicationController {

 //carga el modelo Marca
 public $models=array('marca');

 //controlador para la pagina index
 public function index($page=1){
  $this->marcas=$this->Marca->paginar($page);
 }

 //controlador para la funcion crear
 public function crear(){
  if($this->has_post('marca')){
   $marca = new Marca($this->post('marca'));
   if(!$marca->save()){
    Flash::error('Falló Operación');
    $this->marca = $this->post('marca');
   }else{
    Flash::success('Operación exitosa');
   }
  }

 }

 //controlador para la funcion editar
 public function editar($id = null){
  if($id != null){
   $this->marca = $this->Marca->find($id);
  }
  if($this->has_post('marca')){
   if(!$this->Marca->update($this->post('marca'))){
    Flash::error('Falló Operación');
    $this->marca = $this->post('marca');
   }else{
    Router::route_to('action: index');
   }
  }
 }

 //controlador para la funcion borrar
 public function borrar($id=null){        
  if ($id) {
   if (!$this->Marca->delete($id)) {
    Flash::error('Falló Operación');
   }else{
    $this->marcas=$this->Marca->paginar(1);
    $this->set_response('view');
   }
  }      
 }

 //controlador para la funcion listar
 public function listar($page=1){
  $this->marcas=$this->Marca->paginar($page);
 }

}
?>
Antes de explicar cada uno de los metodos vamos crear nuestras vistas, las vistas son la presentacion al usuario. En Kumbiaphp se debe definir una carpeta con el nombre de nuestra tabla (si se prefiere para mantener un orden y porque buscara ahi por defecto, aunque se puede cambiar), esto se crea en
[directorio de nuestra app]/app/views, para el ejemplo crearemos una carpeta llamada marca
dentro de esta carpeta pondremos los siguientes archivos: index.phtml, crear.phtml, editar.phtml, borrar.phtml
Ahora vamos a procurar explicar combinando todo para que sea talvez más entendible, al menos muchas veces así hubiera querido yo que me lo expliquen, comenzemos.

Index
Es la primera pagina, esto quiere decir que cuando en nuestro navegador apuntemos a http://url_de_la_aplicacion/controlador/, por ejemplo http://localhost/miapp/marca nuestro controlador buscará automaticamente el metodo index, y este a su vez buscará la vista del mismo nombre en la carpeta views y en una carpeta con el mismo nombre de la url. En nuestro ejemplo se ve algo asi:

Las imagenes utilizadas en nuestra app se guardan en la carpeta [directorio de nuestra app]/app/public/img, luego con un poco de CSS se puede hacer algo como lo que ven
Bueno veamos paso a paso que ocurre, primero Kumbiaphp detecta que se hace una llamada al controlador Marca, una vez encontrado busca el metodo index, para nuestro ejemplo encontrará esto:

Metodo Index de la clase MarcaController
 //controlador para la pagina index
 public function index($page=1){
  $this->marcas=$this->Marca->paginar($page);
 }

Lo que hace es asignar a una variable [marcas](al usar $this->variable, permite que la variable pueda ser utilizada en la vista) la lista de objetos obtenidos de la consulta hecha a través del modelo, si recuerdan en nuestro model existe un metodo denominado paginar, cuyo codigo es:
Metodo paginar de la clase Marca
public function paginar($page, $ppage=10){
        return $this->paginate("order: 2 ASC", "page: $page", "per_page: $ppage");
    }

esta es la funcion que realiza la consulta a nuestra BD, mejor dicho hace un
select * from marca order by 2 asc limit 1,10;
Bien ya vimos como nuestro controlador hace la llamada al modelo y lo que este hace, ahora veamos como mostrarlo en el navegador, si recuerdan hablamos de un archivo en la vista denominado index.phtml, pues este es :
Archivo index.phtml (iremos explicando el archivo por partes )
Este es un metodo estatico que nos permite imprimir los mensajes definidos en nuestro controlador mediante la clase Flash
<?php View::content(); ?>

Kumbiaphp provee de una libreria denominada Helpers los cuales nos permiten crear etiquetas HTML, en este caso link_to crear una enlace o link a la url http://localhost/miapp/marca/crear, el texto sera Nuevo y le asigna una clase CSS denominada new.
<h2>Marcas</h2>
<?php echo link_to("marca/crear", 'Nuevo', 'class: new'); ?>

Imprimimos lo que vendria a ser la cabecera de nuestra tabla
<div id="lista">
<table>
<thead>
 <tr >
  <th colspan="6" class="header">Lista de Marcas</th>
 </tr>
 <tr>
  <th>N</th>
  <th>Nombre</th>
  <th>Siglas</th>
  <th>Acciones</th>
 </tr>
</thead>

Ahora vamos a poner el contenido, recorremos los datos almacenados en la variable $marcas, ya descrita lineas arriba en nuestro controlador, entonces usando la funcion foreach de php, decimos por cada item contenido en el array items que tiene $marcas.
<tbody>
<?php $n=0; ?>
<?php foreach($marcas->items as $item) : ?>

Creamos un contador, que nos permitirá poner un ordinal por cada registro, asi como para este ejemplo, hacer una tabla zebra a través de clases de CSS
<?php 
 $n++; 
 if($n%2 ==0){
  $trClass="light";
 }else{
  $trClass="dark";
 }
?>

Por cada registro imprimiremos una fila, la cual tendra como clase light o dark, y le pondremos un id que es el id de nuestros registros, concantenado con la letra c al principio
<tr class="<?php echo $trClass ?>" id='<?php echo "c$item->id" ?>'>  

ahora imprimiremos los valores de las celdas, como ya habiamos dicho la variable $n no es mas que un ordinal, luego siguen los campos, en este caso a la variable $item se le ha asignado un objeto de clase Marca, que abstrae un registro de la tabla Marca, por lo que al hacer $item->nombre estamos diciendo dame el campo nombre de ese registro.
 <td><?php echo $n ?></td>
 <td><?php echo $item->nombre ?></td>
 <td><?php echo $item->siglas ?></td>

Ahora vamos a agregarle las acciones editar y borrar, para eso utilizamos el helper antes descrito, en el caso de editar, apuntamos a http://localhost/marca/editar/[id del registro], para borrar hemos puesto el simbolo numeral porque aqui lo haremos utilizando Ajax.
 <td class="table_actions">
  <?php echo link_to("marca/editar/$item->id", 'Editar','class: edit') ?>
  <?php echo link_to("marca/#", 'Borrar','class: del', "onclick: borrar($item->id)") ?>
 </td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

Habiendo cerrado la tabla vamos a agregar el paginador, como se ha hablado existen los helpers en este caso es un paginador, que lo que hace es crear una barra de navegacion de acuerdo a los parametros que se especifican, para saber mas les dejo el enlace
<?php View::partial('paginators/classic', false, array('page' => $marcas, 'show' => 10, 'url' => 'marca/index')); ?>
Bien ahora vamos a agregarle nuestro pequeño metodo ajax, esto lo hacemos usando JQuery, primero capturamos la fila que se va ha eliminar y lo asignamos a rowSelected, luego para darle algo de interactividad a la app, el contenido de esa fila mostrara una animacion.
Mientras el usuario visualiza la animacion, llamamos de manera asincrona a marca/borrar/[id del registro]. Una vez que se realizó la operación, cargaremos nuevamente la tabla, pero unicamente el codigo html de la tabla.
<script style='javascript'>

function borrar(id){
 var rowSelected=$("body").find('#' + 'c' + id)
 rowSelected.html('<td colspan="4"> <img src="<?php echo PUBLIC_PATH ?>/img/ui/ajax-loader.gif" /> Eliminando ...</td>');
 $.ajax({
  type: "GET",
  url: "<?php echo PUBLIC_PATH . 'marca/borrar/' ?>" + id,
  success:
   function(data){
    $(rowSelected).hide();
    $('#lista').html(data);
   }
  
 });
}
</script>

Lo descrito para el borrado ocurre de la siguiente manera, al dar click sobre el boton borrar

Este ejecuta el evento javascript click, llamando a la funcion borrar (esto se puede hacer de otra manera pero por ahora esta asi, no es lo mejor tampoco) Como ya se dijo se llama a marca/borrar/[id del registro], en nuestro controlador es llamado el metodo borrar, el cual recibe como parametro el id del registro, aprovechando las funciones de ActiveRecord hacemos un delete de ese registro, si es exitosa la operacion volvemos a listar la tabla y OBSERVEN, definimos la respuesta del tipo view, esto indica que solo se procesara el html de esta vista y no se incluiran ni las plantillas ni css ni javascript en la respuesta que no hayan sido puestos explicitamente en ella.
public function borrar($id=null){        
  if ($id) {
   if (!$this->Marca->delete($id)) {
    Flash::error('Falló Operación');
   }else{
    $this->marcas=$this->Marca->paginar(1);
    $this->set_response('view');
   }
  }      
 }

Ahora el controlador borra nuestra vista borrar.phtml que no es mas que un clon de index.phtml por eso no lo pongo y lo imprime dentro de la etiqueta div con id "lista"
Hasta ahora hemos visto como listar los registros y elminarlos, ahora vamos a ver como agregarlos, de acuerdo a nuestra app en la parte superior de la tabla tenemos un boton Nuevo
 Al picar en este boton nos dirigirá a la url /marca/crear, con lo que ahora cargaremos el metodo crear de nuestro controlador
La primera condicional revisa si se han enviado datos por el metodo post y que contengan una variable denominada marca, de no ser asi simplemente buscara la vista crear.phtml en su respectiva carpeta.

De existir los datos entonces instanciará un objeto de la clase Marca y los guardará como un nuevo registro utilizando el metodo post, y se dirá como asigna los campos, bueno la variable marca que viaja por el metodo post es en realidad un array asociativo, que en nuestro html está definido algo así marca[nombre], tal como se ve en el codigo de más abajo.
Metodo crear de MarcaController.
 //controlador para la funcion crear
 public function crear(){
  if($this->has_post('marca')){
   $marca = new Marca($this->post('marca'));
   if(!$marca->save()){
    Flash::error('Falló Operación');
    $this->marca = $this->post('marca');
   }else{
    Flash::success('Operación exitosa');
   }
  }

 }
Como veran hechamos mano de varios de los helper de Kumbiaphp como el form_tag, text_field_tag y submit_tag, creo que todos ellos son autoexplicativos en su funcionalidad por eso no los detallaré.
Solo acotaré que el atributo que se pone es el name, en el caso de nombre en el text_field_tag dice marca.nombre, en el html se creará algo similar a
< input type="text" name="marca[nombre]"  id="marca_nombre" />
El boton cancelar lo unico que hace es dirigirnos a marca/ Vista crear.phtml
<?php View::content(); ?>
<div style='width: 330px;'>
 <h2>Nueva Marca</h2> 
 <?php echo form_tag('marca/crear/') ?>
  <fieldset>
   <legend>Datos de la Marca</legend>
   <label>Nombre</label>
   <?php echo text_field_tag('marca.nombre') ?>
   <br/>
   <label>Siglas</label>
   <?php echo text_field_tag('marca.siglas', 'size: 3','maxlength: 2') ?>
   <br />
   <?php echo submit_tag("Guardar","id: save", "class: submit")?>
   <?php echo link_to("marca/","Cancelar", "class: cancel")?>
  </fieldset>
 </form>
</div>
Tal como hemos visto en el codigo del controlador efectuará una comprobación al momento de guardar
$obj->save()
y si todo va bien mostrará un mensaje utilzando la clase Flash.
Por ultimo la acción editar, esta se llama al presionar el boton editar
 y llama a marca/editar/[id del registro], esta accion se busca en el controlador.

Como recibe como parametro el id, si id es nulo entonces carga en la variable marca el objeto encontrado mediante el metodo find de ActiveRecord, de esta manera cuando carguemos la vista editar.phtml, los datos del objeto se encuentre por defecto en el formulario.
De existir un valor, utilizamos el metodo update el cual de forma simil que en crear carga los datos del array marca.
public function editar($id = null){
  if($id != null){
   $this->marca = $this->Marca->find($id);
  }
  if($this->has_post('marca')){
   if(!$this->Marca->update($this->post('marca'))){
    Flash::error('Falló Operación');
    $this->marca = $this->post('marca');
   }else{
    Router::route_to('action: index');
   }
  }
 }
Vista editar.phtml cargada con los datos.
Este el codigo de nuestra vista.
Si se dan cuenta se diferencia de crear.phtml no solo en la direccion del formulario sino en que se agregar un elemento hidden el cual contiene el id del registro.
<?php View::content(); ?>
<div style='width: 330px;'>
 <h2>Editar Marca</h2>
 <?php echo form_tag('marca/editar/') ?>
  <?php echo hidden_field_tag("marca.id")?>
  <fieldset>
   <legend>Datos de la Marca</legend>
   <label>Nombre</label>
   <?php echo text_field_tag('marca.nombre') ?>
   <br/>
   <label>Siglas</label>
   <?php echo text_field_tag('marca.siglas', 'size: 3','maxlength: 2') ?>
   <br />
   <?php echo submit_tag("Guardar","id: save", "class: submit")?>
   <?php echo link_to("marca/","Cancelar", "class: cancel")?>
  </fieldset>
 </form>
</div>

Bueno espero haber sido bastante explicativo, si algo no entienden comenten para absolver sus preguntas.
Este ejemplo es bastante basico y puede ser mejorado por mucho, solo es para explicar la funcionalidad de este gran framework.

12 comentarios:

  1. algun link de un ejemplo para ver mejor el funcionamiento

    ResponderEliminar
  2. Ya estare subiendo algunos ejemplos a un hosting

    ResponderEliminar
  3. que buena practica muchas gracias por la información cuando tengas tiempo sigue compartiendo tus conocimientos

    ResponderEliminar
  4. Que bueno que les guste, ya comienzo a la carga otra vez

    ResponderEliminar
  5. Hola te digo que tus aportes me han servido mucho ya que soy novato en kumbiaphp pero realizando tu ejemplo cuando estoy en el index con el paginator y le doy clic a editar me lleva a la vista editar.phtml con el id que deseo editar pero no me carga las imagenes de mi palntilla... Y si copio en la url localhost/mIAPP/marca/edit si me carga bn la plantilla junto con las imagenes el problema digo yo es cuando le envio un id por q la url cambia a localhost/mIAPP/marca/edit/id y ahi carga la plantilla y el formulario para editar pero no las imagenes de mi plantilla

    ResponderEliminar
  6. Hola gracias por lo dicho, me alegra saber que mi pequeño aporte te ayuda.
    Sobre tu caso, postea tu codigo del controlador asi puedo ver que error puedes tener, de buenas a primeras pareciera algo con la validacion del id

    ResponderEliminar
  7. No ya le di con el chiste era colocar en la ruta relativa en vez de "../img" es "/img/x/x/
    Muchas gracias por estar al tanto la verdad es que me meti al IRC de Kumbia y me respondian como de mal genio no me gusto...Espero poder consultar en otras opurtunidades ahora buscare como es que haces para que desaparesca el mensaje flash jeje

    ResponderEliminar
  8. Soy nuevo trabajando con kumbia y quisiera saber si se puede paginar un formulario muy extenso y ps de ser asi como lo puedo hacer, muchas gracias...

    ResponderEliminar
  9. Disculpa la demora, cuando te refiereres a paginar un formulario entiendo que tu formulario tiene varios campos a llenar.
    Si es asi, eso lo puedes solucionar solo con HTML tal vez usando pestanias

    ResponderEliminar
  10. Muy buena la explicación... he seguido el ejemplo y funciona muy bien, excepto el borrar (el efecto de Eliminando aparece, pero no desaparece y refresca la lista)... me podrías enviar las hojas de estilo / imágenes por favor.
    diazeliana@gmail.com

    ResponderEliminar
  11. Me alegra que te haya servido el tutorial, los CSS, los empaqueto y los posteo para que todo el que guste pueda utilizarlos

    ResponderEliminar

 
Powered by Blogger