Calendario de syfmony día ocho: Interacciones AJAX
====================================================
Previamente en symfony
---------------------
Después de siete horas de trabajo, la aplicación askeet ha avanzado bien. La página de inicio muestra una lista de preguntas, el detalle de una pregunta muestra sus respuestas, los usuarios tienen una página de perfil, y una lista temática esta disponible para cada página en la **sidebar**. Nuestro FAQ mejorado-por-la-comunidad esta en la dirección correcta (mira la lista de acciones disponibles para [ayer](7.txt)), y el usuario aun no puede alterar su propia información por ahora.
Si la base para la manipulación de datos en la web han sido por mucho tiempo los formularios, hoy técnicas AJAX y mejoras en la usabilidad pueden cambiar la forma en una aplicación es construida. Y eso aplica a askeet, también. Este tutorial le mostrara como agregar interacciones mejoradas-por-AJAX a askeet. El objetivo es permitir al usuario registrado declarar interés en una pregunta.
Agregar un indicador en el layout
---------------------------------
Mientras una petición asíncrona está pendiente, los usuario de website proveídos de AJAX no tiene ninguna de las pistas usuales que su acción fue tomada en cuenta y que el resultado será pronto mostrado. Esta es la razón por la cual cada página conteniendo interacciones AJAX debería ser capaz de mostrar un indicador de actividad.
Para este propósito, agregue arriba de `
` en el `layout.php` global:
[php]
` `interested_mark` del interés clicqueado... después que la acción retorne e incremente el número de interés.
### Acción del Server
El llamado AJAX apunta a la acción `user/interested`. Esta acción debe ser crear un nuevo registro en la tabla `Interest` para la pregunta actual y el usuario actual. Así es como se hace en symfony:
[php]
public function executeInterested()
{
$this->question = QuestionPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->question);
$user = $this->getUser()->getSubscriber();
$interest = new Interest();
$interest->setQuestion($this->question);
$interest->setUser($user);
$interest->save();
}
Recuerde que el método `->save()` del objeto `Interest` fue modificado para incrementar el campo `interested_user` del `User` relacionado. Así el número de usuarios interesados acerca de la pregunta actual será mágicamente incrementada en la pantalla después de la llamada a la acción.
¿Y que debería mostrar la plantilla `interestedSuccess.php` resultante?
[php]
$question)) ?>
Muestra el fragmento `_interested_user.php` del módulo `question`. Este es el más grande interés de haber escrito este fragmento en primer lugar.
También debemos desactivar el layout para esta plantilla (`modules/user/config/view.yml`):
interestedSuccess:
has_layout: off
### Pruebas finales
El desarrollo del interés AJAX esta terminado. Puedes probarlo ingresando un login/password existente en la página de login, mostrando la lista de preguntas y luego clicqueando un enlace 'interested?'. El indicador aparece mientras la petición es enviada al servidor. Entonces, el numero es incrementado en remarcado cuando el servidor responde. Note que el enlace 'interested?' es ahora un texto 'interested!' sin enlace, gracias a nuestro helper `link_to_user_interested`:

Si desea más ejemplos acerca de los helpers AJAX, puedes leer el [tutorial carrito de compra drag-and-drop](http://www.symfony-project.com/tutorial/symfony_ajax.html), mira el [screencast](http://downloads.symfony-project.com/demo/cart/cart.mov) asociado o lee el [capitulo relacionado del libro](http://www.symfony-project.com/content/book/page/javascript.html).
Agregar un formulario de 'sign-in'
----------------------------------
Previamente mencionamos que sólo usuarios registrados pueden declarar interés sobre un pregunta. Esto significa que si un usuario-no-autorizado cliquea en un enlace 'interested?', la página de login debe ser mostrada primero.
Pero espere. ¿Por que un usuario cargaría una nueva página para loguearse, y perder contacto con la pregunta que el/ella ha declarado interés? Una mejor idea sería tener un formulario de login en la página. Eso es lo que vamos a hacer.
### Agregar un formulario de login oculto al layout
Abre el layout global (en `askeet/apps/frontend/templates/layout.php`), y agrega (entre el div `header` y el `content`):
[php]
Please sign-in first
0.5))) ?>
nickname:
password:
get('referer') ? $sf_params->get('referer') : $sf_request->getUri()) ?>
Una vez más, este formulario esta escondido por defecto. La etiqueta `referer` contiene el parámetro `referer` de la petición si existe, o sino la actual URI.
### Hacer que el formulario aparezca cuando un usuario-no-autenticado cliqueee en un enlace interested?
¿Recuerdas el helper `User` que escribimos previamente? Ahora lidiaremos con el caso cuando el usuario no está autenticado. Abre nuevamente el archivo `askeet/lib/helper/UserHelper.php` y cambie la linea:
[php]
return link_to('interested?', 'user/login');
con está:
[php]
return link_to_function('interested?', visual_effect('blind_down', 'login', array('duration' => 0.5)));
Cuando el usuario no esta autenticado, el enlace en la la palabra 'interested?' lanza un efecto javascript de prototype (`blind_down`) que revela el elemento de id `login` - y este es el formulario que acabamos de agregar al layout.
### Loguear al usuario
La acción `user/login` ya fue escrita durante el quinto día, y refactorizado durante el día seis. ¿Debemos modificarlo nuevamente?
[php]
public function executeLogin()
{
if ($this->getRequest()->getMethod() != sfRequest::POST)
{
// display the form
$this->getRequest()->getParameterHolder()->set('referer', $this->getRequest()->getReferer());
return sfView::SUCCESS;
}
else
{
// handle the form submission
// redirect to last page
return $this->redirect($this->getRequestParameter('referer', '@homepage'));
}
}
Después de todo, no. Funciona perfectamente como esta, el manejo del referer, redireccionará al usuario a la página donde el/ella se encontraba cuando el enlace fue cliqueado.
Prueba la funcionalidad AJAX ahora. Un usuario sin registrarse será presentado con un formulario de login sin dejar la página actual. Si el nickname y el password son reconocidos, la página se refrescara y el usuario será capaz de cliquear en el enlace 'interested?' que intentó clicar anteriormente.

>**Nota**: En muchas interacciones AJAX como esta, la plantilla del servidor es simplemente un `include_partial`. Esto es debido a que un resultado inicial es generalmente presentado cuando la página se presenta por primera vez, y porque la parte que es actualizada por la acción AJAX es parte de la plantilla inicial.
Nos vemos mañana
-------------
Lo más difícil en diseñar interacciones AJAX es definir apropiadamente el llamador, la acción del server, y la zona resultante. Una vez que los conoces, symfony provee los helpers que realizan el resto. Para estar seguro de que entiendes, mira como implementamos el mismo mecanismo para declarar interés para la declarar interés para la relevancia de un respuesta. Esta vez, la acción AJAX llamada es `user/vote`, el parcial es `_answer.php` es separado en dos partes (creando el parcial `_user_vote.php`), y dos helpers `link_to_user_relevancy_up()` y `link_to_user_relevancy_down` son creado en el helper `User`. El módulo `User` gano una acción `vote` y una plantilla `voteSuccess.php. No olvide de establecer el layout a `off` para esta plantilla también.
Askeet comienza a verse como una aplicación web 2.0. Y es solo el comienzo: En unos días, le agregaremos algunas más interacciones AJAX. Mañana tomaremos la ocasión para hacer un repaso general de técnicas MVC en symfony, e implementar una librería externa.
Si encuentra un problema mientras tratas de seguir el tutorial de hoy, puedes descargar el código completo etiquetado `release_day_8` desde el [repositorio SVN de askeet](http://svn.askeet.com/tags/release_day_8). Si no tienes ningún problema, ven al [foro askeet](http://www.symfony-project.com/forum/index.php/f/8/) para responder preguntas de otros.