wiki:DesarrolladoresAjaxOnCake

Ajax en CakePHP

Ajax

 Ajax (Asynchronous JavaScript? and XML) es un conjunto de tecnologías que nos permite evitar la sobrenavegación y tener un experiencia en el Web más similar a la que tenemos con las aplicaciones de escritorio como OpenOffice?.org o Nautilus.

Ajax se construye en torno al XMLHttpRequest, un objeto JavaScript? (JS) que nos permite hacer peticiones al Webserver "tras bambalinas" o en "background" sin tener que volver a recargar la página en el navegador.

Podemos usar el objeto XMLHttpRequest directamente en una función JS escrita por nosotros, pero es necesario considerar el navegador y la versión para construir el objeto, por ejemplo para construir el objeto para las diferentes versiones de Explorer:

// Provide the XMLHttpRequest class for IE 5.x-6.x:
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};

Esto es tedioso, afortunadamente han surgido varios frameworks JS que facilitan mucho trabajar con Ajax y se encargan (entre otras cosas) de lidiar con la versión y tipo de navegador. Los más usados de estos frameworks son  Prototype y  jQuery, ambos son usados en los proyectos de Chipotle Software, tanto en CakePHP como en Django. Además existe un animation framework  Scriptaculous que funciona junto con Prototype para agregar efectos visuales a nuestras peticiones ajax.

Ajax Helper

En el caso de CakePHP se usa Prototype y Script.aculo.us, ambos se deben descargar y colocar en el directorio APP/webroot/js/ de nuestra aplicación. Una vez hecho esto se cargan en la zona HEAD del layout del sitio de este modo:

if ( isset($javascript) ):  // comprueba que el Javascript helper está activado
      echo $html->charset('UTF-8');
      echo $javascript->link('prototype'); 
      echo $javascript->link('scriptaculous.js?load=effects'); 
endif;

El Javascript helper y Ajax helper deben estar declarados en el controlador. Para usar Ajax en CakePHP se siguen los siguiente pasos:

1) Se usa el Ajax helper para construir un objeto que llame al método de un controlador, el objeto puede ser un link o un botón de formulario. 2) Se define un div con id único ("qn" por ejemplo). 3) Se coloca una imagen animada pero con el atributo "visibility:none" para que permanezca oculta. 4) Al dar click sobre el objeto se llama al controlador en "background" y la imagen se hace visible para decirle al usuario que su petición está trabajando. 5) Al terminar el request el resultado se carga en "qn" y la imagen se vuelve a ocultar.

Por ejemplo en una vista tenemos el siguiente código:

 $ajax->link(    // este es un ajax link
      $html->image('static/show_icon.png',array('alt'=>__('Course description',true), 'title'=>__('Course description',true))),
      '/vclassrooms/description/'.$data['Vclassroom']['ecourse_id'],  // la llamada al método description
                      array('update' => 'qn',                         // el div donde se cargará el resultado
                     'loading'=>"Element.show('loading');",  // muestra la imagen 
                     'complete'=>"Element.hide('loading');Effect.Appear('qn')"),   // al completarse la imagen se vuelve a ocultar y se muestra el div qn 
                      null,false)
         );
	
echo $gags->imgLoad('loading');  // para detalles ver el gags helper 
 
echo $ajax->div('qn', array('style'=>'padding:3px')).$ajax->divEnd('qn');  // esto es sólo es un div vacío

El método description del controlador vclassrooms es asi:

public function description($ecourse_id) 
{
   $this->set('description', $this->Vclassroom->Ecourse->field('description', array('Ecourse.id'=>$ecourse_id)));
   $this->render('description', 'ajax');  // ejecuta y devuelve la vista description.ctp en modo ajax es decir sin el layout
}

Esto quiere decir que existe la vista APP/views/vclassrooms/description.ctp y que luego de procesarse el resultado se coloca en el div "qn" de la vista donde ejecutamos la petición Ajax. La vista description.ctp es como cualquier otra vista de Cake:

  //esto se coloca en el div qn luego de dar clic al elemento Ajax 
  echo $hmtl->div('title', $data['Ecourse']['title']);
  echo $hmtl->div('desc', $data['Ecourse']['description']);

Otro ejemplo

Podemos usar Ajax en un formulario, usando la opción submit para construir un botón que envia los datos al método del controlador:

 echo $ajax->form();
 echo $form->input('Model.field');
 echo $ajax->submit('Vote', array('url'      => '/pollrows/vote', 
	                                       'update'   => 'add_pollrow',
	                                       'loading'  => "Element.hide('add_pollrow');Element.show('loading')",
	                                       'complete' => "Element.hide('loading');Effect.Appear('add_pollrow')"
	        ));

Si en lugar de una liga usamos Ajax en un formulario podemos recibir y usar los datos en el método del controlador igual que siempre es decir:

   $this->data['Model'] = Sanitize::clean($this->data['Model']);
   $this->Model->save($this->data);

Permisos

Esté método description() (y cualquier otro método que usemos en Ajax) debe tener permisos de ejecución en el Auth Component o no se ejecutará,es decir denos agregar el método al array de los métodos permitidos :

public function beforeFilter()
{
  parent::beforeFilter();
  $this->Auth->allow(array('display', 'aboutme' 'description', 'chat'));
}

Para desarrollar y depurar código Ajax es casi indispensable usar la extensión  Firebug para Firefox pues asi podemos ver las respuesta de error y lo que envia Apache y CakePHP en "background".

Encoding

Al trabajar con Ajax se debe coordinar desde el incio que el Webserserver (Apache2), la BD (PostgreSQL), el lenguaje (PHP5) y el framework (CakePHP) tengan el Default Charset en UTF-8 y asi no tendremos problemas con las eñes y acentos.

En el caso de PostgreSQL si no se hizo desde el inicio es necesario hacer un pg_dump de la BD actual y crear una nueva base de datos con el encoding correcto:

  $createdb -E UNICODE DBNUEVA

Y cargar en ella los datos para que los guarde correctamente.

Live Chat en Karamelo

Karamelo tiene una implementación de Livechat que usa Ajax:

1) El modelo Chat guarda los mensajes del chat del vclassroom (Chat->belongsTo->Vclassroom).
2) El usuario pincha en el icono de chat del vClassroom que llama al método chat() del controlador vclassrooms que carga los mensajes.
3) La función Ajax getChatText(vclassroom_id) de la vista chat.ctp busca mensajes nuevos cada tres segundos y los coloca en el div updater.
4) Por otro lado la función Ajax sendPing(vclassroom_id) de la vista chat.ctp avisa al sistema que el usuario está y se mantien en el chat.
5) El elemento chat_messages.ctp es el que hace el loop con formato para el div updater.

Attachments