Hoy es el 256º día del año, de modo que –apropiadamente– se celebra el Día del programador. Según parece en Rusia además consiguieron que fuera oficialmente un día festivo para quienes se dedican a ello como profesión.

Extraído de: microsiervos

Voy a explicaros una manera sencilla de hacer la paginación de vuestras webs y aplicaciones hechas con CakePHP en Ajax utilizando jQuery y un plugin para que el historial del navegador funcione correctamente.

Para mi ejemplo he utilizado CakePHP 1.3.3 y jQuery 1.4.2. El plugin que comentaba anteriormente se llama jQuery History Plugin y lo podéis descargar de gitHub.

Bien pues vamos a ello. Empecemos por el controlador. Simplemente tenéis que tener en cuenta que vamos a utilizar el helper de JavaScript, así que debemos activarlo:

1
2
3
4
5
6
7
8
9
10
<?php
class PagsController extends AppController
{
  var $helpers = array('Javascript');

  public function index()
  {
    $this->set('pags', $this->paginate());
  }
}

Ya veis que no tiene ninguna complicación. La vista tampoco es nada del otro mundo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<table id="pags">
  <thead>
    <tr>
      <th><?php echo $paginator->sort('id') ?></th>
      <th><?php echo $paginator->sort('title') ?></th>
      <th><?php echo $paginator->sort('conent') ?></th>
      <th><?php echo $paginator->sort('created') ?></th>
      <th><?php echo $paginator->sort('modified') ?></th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ( $pags as $pag ): ?>
    <tr>
      <td><?php echo $pag['Pag']['id'] ?></td>
      <td><?php echo $pag['Pag']['title'] ?></td>
      <td><?php echo $pag['Pag']['conent'] ?></td>
      <td><?php echo $pag['Pag']['created'] ?></td>
      <td><?php echo $pag['Pag']['modified'] ?></td>
    </tr>
    <?php endforeach ?>
    <tr>
      <td><?php echo $paginator->prev('« Anterior') ?></td>
      <td colspan='3'><?php echo $paginator->numbers() ?></td>
      <td><?php echo $paginator->next('Siguiente »') ?></td>
    </tr>
  </tbody>
</table>
<div class="ajax-loader">
  <?php echo $this->Html->image('loader.gif', array('alt' => 'Cargando...', 'style' => 'display: none')) ?>
</div>

Bien, ya tenemos la parte sencilla. Vamos al intríngulis de la cuestión: el JavaScript (o el jQuery, mejor dicho..).

En la vista que tenemos creada, vamos a cargar jQuery y el plugin de historial, que debéis tener ya descargados en vuestra carpeta js:

1
2
<?php
$this->Javascript->link(array('jquery-1.4.2.min', 'jquery.history'), false);

Y ahora, la paginación con Ajax. Debajo de la línea que acabamos de añadir para cargar jQuery y el History plugin añadid lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$script = '
jQuery(function($) { // paso $ para no tener problemas con otros frameworks JS
  $.history.init(function(url) {
    if (url == "") url = "' . $this->Html->url(array('controller' => 'pags', 'action' => 'index')) . '"; // si no recibimos URL tenemos que cargar el índice
    $(".ajax-loader img").fadeIn(); // mostramos el gif animado
    $.ajax({
      type: "GET",
      url: url,
      dataType: "html",
      success: function(data) {
        $("#pags").html($(data).find("#pags"));
        $(".ajax-loader img").fadeOut(); // ocultamos el gif animado
      }
    });
  });

  $("a[href*=/page:]").live("click", function(e) {
    $.history.load($(this).attr("href"));
    e.preventDefault(); // return false;
  });
});
';
$this->Javascript->codeBlock($script, array('inline' => false));

Bien, ¿qué estamos haciendo aquí? Voy a explicarlo paso por paso.

Hay que tener en cuenta que el plugin de historial hace que el código sea un poco distinto a si no lo tuviéramos con dicho plugin, ya que el método $.history.init() es el que se encarga de cargar la página mediante Ajax cuando $.history.load() es instanciado.

Por esto, dentro del método $.history.init() ejecutamos nuestro método de carga mediante Ajax. En la primera línea le indicamos que si no recibe url ésta debe ser el índice de nuestra paginación. Sin esta línea cada vez que entraseis a la página raíz (sin hash) tendríais un error de JavaScript, además de que no funcionaría el historial con la primera página nunca.

Después de eso, llamamos al método $.ajax() para hacer nuestra petición Ajax. De aquí todo está explicado en la documentación, salvo esta línea:

1
$('#pags').html($(data).find('#pags'));

Aquí indicamos que queremos reemplazar todo el contenido de la tabla #pags con ese mismo contenido de nuestra petición Ajax (de ahí el $(data).find("#pags") donde filtramos “#pags” de “data” [nuestra respuesta Ajax]).

Por último, en este trozo de código:

1
2
3
4
$('a[href*=/page:]').live('click', function(e) {
  $.history.load($(this).attr('href'));
  e.preventDefault(); // return false;
});

Estamos indicando que siempre que se pulse un enlace que contenga en su ruta (href) “/page:” se dispare el método $.history.load(), al que le pasamos la url del enlace que estemos pulsando.

Utilizamos el método “live” de jQuery, ya que al reemplazar los botones de la tabla, sin live, éstos no funcionarían.

El e.preventDefault(); equivale al típico return false; que utilizamos para evitar que el botón ejecute su método por defecto (cargar la página sin Ajax).

Pues ya está, de esta manera tan sencilla tenemos paginación Ajax con historial del navegador gracias a jQuery en nuestra aplicación CakePHP.

Podéis ver un ejemplo en la siguiente dirección: http://demos.racotecnic.com/tutorials/cake13/pags.

El problema de éste método de paginación es que, aunque le ahorramos tiempo de carga al cliente, nuestro servidor carga toda la página igualmente. Si quisierais reducir la carga de vuestro servidor con Ajax quizás deberíais ingeniároslas para cargar sólo esa parte de la vista y devolverla en formato XHTML en un JSON (o en un JSON directamente) y repoblar vuestra tabla con dicho resultado.

Algún día trataré de hacer un tutorial explicando esto con detalle ;)

**Enlaces:**

Edit: Cuando escribí esto no recordaba que la nueva versión de CakePHP lleva helpers para jQuery y para todo lo relacionado con Ajax. En cuanto pueda investigo cómo va el asunto y creo un tutorial con ello, pero mientras tanto…

¿A que se refiere esta entrada? Os voy a hacer una lista de las aplicaciones que instalo si o si en cualquier instalación nueva (para mi). Son las aplicaciones que considero esenciales para mi. Desde reproductores, programas ofimáticos… hasta navegadores.

Vamos a ello:

Mozilla Firefox

Básico, es lo primero que instalo (descargandolo desde Internet Explorer o desde el navegador por defecto del sistema).

Web: http://www.mozilla-europe.org/es/firefox/

Spotify

Mi reproductor de música. Atrás ha quedado Winamp y los demas. Casi toda la música que escucho la puedo encontrar aquí.

Web: http://www.spotify.com/es/

VLC Media Player

Indispensable. Es “el reproductor”. De todos los reproductores de video que he probado, el mejor, sin duda alguna.

Web: http://www.videolan.org/vlc/

OpenOffice

La suite gratuita OpenOffice tiene todo lo que cualquier persona puede necesitar. Writer, Calc e Impress son los programas que uso.

Web: http://www.openoffice.org/

uTorrent

Despues de muchos años usando distintos programas para gestionar los torrents, creo que a dia de hoy este es el mejor.

Web: http://www.utorrent.com/

Foxit Reader

Lector de PDF gratuito. Es mucho mas ligero, por lo que los documentos se abren bastante mas rápido que con Acrobat.

Web: http://www.foxitsoftware.com/pdf/reader/

Xampp

En “dos clicks” tienes tu propio servidor en local para poder trastear. Apache, PHP, MySql. Recomendable para desarrolladores web.

Web: http://www.apachefriends.org/es/xampp.html

Notepad++

Editor de código que soporta una gran cantidad de lenguajes de programación. Muy rápido y ligero. Incorpora pestañas.

Web: http://notepad-plus-plus.org/

Filezilla

Buen cliente FTP gratuito. Sencillo de usar, muy completo, multilenguaje, buena estructura de ventana. Alternativamente uso NicoFTP.

Web: http://filezilla-project.org/

Google Chrome

Solo por dos cosas. HTML5 y el modo aplicación, que elimina todas las barras y permite que una aplicación web aparente no serlo tanto.

Web: http://www.google.com/chrome?hl=es

Avira Antivir

Antivirus que instalo en las instalaciones Windows. Gratuito. El único inconveniente es la publicidad que salta al actualizarse.

Web: http://www.free-av.com/

WinRar

Compresor-descompresor de archivos que soporta una gran cantidad de formatos. RAR y ZIP, imprescindible para descargas.

Web: http://www.winrar.es/

Además de todas estas, tambien suelo instalar: Calibre, Messenger, Skype, K-Lite Codek Pack, Steam. Todas estas son las aplicaciones gratuitas. Las de pago que suelo tener instaladas son las siguientes: Adobe Master Collection, Nero, Guitar Pro y VMware.

Aviso:

Como la gran mayoría de gente sabe, ayer sábado 4 de septiembre Apple abrió su primera Apple Store en España. El sitio elegido ha sido un local en el centro comercial de La Maquinista (Barcelona). El local en sí es bastante grande (1300 metros cuadrados), pues hay que tener en cuenta que es la Apple Store en centro comercial mas grande de Europa.

La cola empezó el viernes por la mañana, antes de la apertura del centro comercial, cuando el primer cliente se “coló” en las instalaciones a las 6:30 de la mañana. Eso fue el inicio de lo que poco a poco iba a convertirse en una cola de entre una y dos horas para poder entrar a la tienda al dia siguiente. Comentar que a las 00:00 de la noche, se destapó la tienda, eliminando la barrera que impedía ver el interior bajo la atenta mirada de la cola, que a gritos y aplausos veían por primera vez el interior de la tienda. El sábado, a las 9:55 de la mañana, nos encontramos con esto:

Llegado cierto punto, incluso ciertos empleados nos proporcionaban gratuitamente una botella de agua (desconozco si eran empleados por parte de Apple o de la propia marca, pues no llevaban la indumentaria azul de los vendedores).

La cola iba avanzando. Un empleado iba pasando por la cola preguntando quién iba a comprar un iphone, puesto que habian dos colas (una general y otra para los compradores de iphone). Entre toda la gente, se podían observar una gran cantidad de aparatos Apple, desde iphones, ipads, ipods… y hasta algunos macbooks.

Hasta llegar a la entrada de la tienda, donde estaba el gran bulto de personas y empleados.

En la puerta, nos encontramos con un pasillo de empleados, que a gritos, silbidos, aplausos, choques de manos… nos daban la bienvenida al mas puro estilo americano. A su vez nos entregaban una cajita que contenía la camiseta (a las 1500 primeras personas) y un panfleto publicitario de la tienda y el centro comercial. Por fin, dentro de la tienda, nos encontramos con este aspecto:

La tienda esta distribuida en 4 filas de mesas y dos filas en las paredes laterales. Al fondo encontramos la genius bar, en sus laterales tenemos unas paredes con aplicaciones y accesorios de todo tipo. Justo delante de la genius bar, tenemos unas mesas mas del estilo cibercafé (con sillas), con ordenadores, de manera que se puede estar mas comodo que en las mesas principales (no disponen de sillas).

En cuanto al contenido, encontramos una gran cantidad de macbooks pro, muchos imacs de 21 pulgadas, muchos iphones, ipods, ipads… solo noté dos productos que estaban expuestos en poca cantidad. El imac de 27 pulgadas (solo tenían dos expuestos, uno con el core i3 y otro con el core i7) y el macbook clásico (solo encontré tres, justo a la izquierda de la entrada). A su vez, tenían un apple tv (version antigua) y un mac pro.

La verdad es que cualquiera que se este pensando en adquirir un producto Apple debería pasarse por la tienda, puesto que puedes comparar diferentes configuraciones (en el caso de los ordenadores) o trastear con los gadgets. Estuve pasando tests de geekbench a varios ordenadores (todos con la versión gratuita de 32 bits). El imac i7 puntuó mas de 9000, macbook pro con i5 alrededor de los 7000 y el macbook superó ampliamente los 3000. Además, a partir del lunes 6 de septiembre, empiezan los talleres (puedes mirarlos aquí), ideales para todos aquellos que quieran iniciarse en el mundo Apple.

Para finalizar os muestro la camiseta que nos regalaron:

Aviso:

En este tutorial aprenderéis a gestionar los errores de CakePHP con y sin Ajax.

Lo primero de todo que tenéis que hacer es poner el debug a cero en vuestro fichero core.php, ya que con debug > 0 no funcionaría.

Ahora pasemos a crear (si no existe) el fichero /app/app_error.php con el siguiente contenido.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// /app/app_error.php
class AppError extends ErrorHandler
{
  function error404($params)
  {
    // Importamos RequestHandler para verificar si la conexión es mediante Ajax
    App::import('Component', 'RequestHandler');
    $this->RequestHandler = new RequestHandlerComponent();
    if ($this->RequestHandler->isAjax()) {
      // En caso de ser Ajax creamos la cabecera 404
      $this->controller->header('HTTP/1.0 404 Not Found');
      // y pasamos algunas variables a la vista que ahora crearemos
      $this->controller->set('params', $params);
      $this->controller->layout = 'ajax';
      // Renderizamos la vista
      $this->_outputMessage('ajax_error404');
    }
    // Aquí iría la gestión del error sin Ajax, en nuestro caso llamamos al método padre.
    else parent::error404($params);
  }
}

Pasemos a la creación de la vista… /app/views/errors/ajax_error404.ctp

1
2
3
4
<?php
// /app/views/errors/ajax_error404.ctp
$error404 = array('message' => __('The requested address was not found on this server.',true), 'params' => $params);
echo $this->Javascript->object($error404);

Tan simple como eso : )

Finalmente, añadamos esto a nuestro template por defecto, o a nuestra hoja javascript común:

1
2
3
4
5
6
7
8
jQuery(document).ready(function($) {
  // Ajax not found
  $(this).ajaxError(function(event, request, opts) {
    if (request.status == 404) {
      alert(eval('(' + request.responseText + ')').message);
    }
  });
});

Con esto mostraremos una alerta mostrando el texto que hayamos definido en nuestro app_error al usuario que intente adquirir una url no existente en nuestra aplicación CakePHP.

Evidentemente podéis gestionar más errores a parte del típico error 404, simplemente añadiendo algún if más al código javascript y el método correspondiente en el app_error para gestionarlo.

El parámetro $params lo he pasado por si queréis utilizar alguna de sus variables. Por ejemplo, podríamos mostrar al usuario un mensaje tipo “La página /requetefuck no existe”.

Nota: Si estáis utilizando Cake 1.2 tened en cuenta que tenéis que reemplazar en la vista ajax_error404 el $this->Javascript por $javascript, ya que ha variado de una versión a otra.