The Askeet Tutorial

Be trained by symfony experts
Dec 10: Paris (1.1 - Francais)
Dec 10: Atlanta (1.1 - English)
Dec 17: Montreal (1.1 - Francais)
Jan 21: Paris (1.1 - Francais)
Feb 18: Paris (1.1 - Francais)
and more...
Askeet_logo_bar

askeet links

WARNING: The SVN source code found in the release_day tags is outdated. Please refer to the current version until each day code is updated.

About

You are currently reading "The Askeet Tutorial" which is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.

Search


powered by google

Chapter Content

Previamente en symfony

Agregar un indicador en el layout

Agregar una interacción AJAX para declarar interés

Llamador

Zona de resultados.

Acción del Server

Pruebas finales

Agregar un formulario de 'sign-in'

Agregar un formulario de login oculto al layout

Hacer que el formulario aparezca cuando un usuario-no-autenticado cliqueee en un enlace interested?

Loguear al usuario

Nos vemos mañana

You are currently browsing "The Askeet Tutorial" in Spanish for the 1.0 version. Switch to another language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Translation of this work into another language is explicitly allowed.

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), 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 <body> en el layout.php global:

<div id="indicator" style="display: none"></div>
 

Aunque oculto por defecto, este >div> será mostrado cuando una petición AJAX este pendiente. Esta vacío, pero la hoja de estilo main.cc (ubicada en el directorio askeet/web/css) le da forma y contenido:

div#indicator
{
  position: absolute;
  width: 100px;
  height: 40px;
  left: 10px;
  top: 10px;
  z-index: 900;
  background: url(/images/indicator.gif) no-repeat 0 0;
}
 

indicador de actividad

Agregar una interacción AJAX para declarar interés

Una interacción ajax esta compuesta por tres partes: un llamador (un enlace, un botón o cualquier control que el usuario manipula para lanzar la acción), una acción en el servidor, y una zona en la página para mostrar el resultado de la acción al usuario.

Llamador

Vayamos de nuevo a la muestra de la pregunta. Si recuerdas el día cuatro, una pregunta puede ser mostrada en la lista de preguntas y en los detalles de una pregunta.

lista de preguntas

Es por eso que el código para el titulo de la pregunta y el bloque interés fue refactorizado en el fragmento _interested_user.php. Abre este fragmento nuevamente, y agregar un enlace para permitir a los usuario declarar sus intereses:

<?php use_helper('User') ?>
 
<div class="interested_mark" id="mark_<?php echo $question->getId() ?>">
  <?php echo $question->getInterestedUsers() ?>
</div>
 
<?php echo link_to_user_interested($sf_user, $question) ?>
 

Este enlace va a hacer más que simplemente redireccionar hacia otra página. De hecho si ya declaro interés acerca de la pregunta, el/ella debe poder declararlo de nuevo. Y si el usuario no se encuentra autenticado... bueno, veremos este caso más tarde.

El enlace esta escrito en una función helper, que necesita ser creada en askeet/apps/frontend/lib/helper/UserHelper.php:

<?php
 
use_helper('Javascript');
 
function link_to_user_interested($user, $question)
{
  if ($user->isAuthenticated())
  {
    $interested = InterestPeer::retrieveByPk($question->getId(), $user->getSubscriberId());
    if ($interested)
    {
      // already interested
      return 'interested!';
    }
    else
    {
      // didn't declare interest yet
      return link_to_remote('interested?', array(
        'url'      => 'user/interested?id='.$question->getId(),
        'update'   => array('success' => 'block_'.$question->getId()),
        'loading'  => "Element.show('indicator')",
        'complete' => "Element.hide('indicator');".visual_effect('highlight', 'mark_'.$question->getId()),
      ));
    }
  }
  else
  {
    return link_to('interested?', 'user/login');
  }
}
 
?>
 

La función link_to_remote es el primer componente de una interacción AJAX: El llamador. Declara cual es la acción debe ser llamada cuando el usuario cliquea en el enlace (aquí: user/interested) y cual zona de la página necesita ser actualizada con el resultado de la acción (aquí: el elemento de id block_XX). Dos manejadores de eventos (loading y complete) son agregados y asociados a las funciones javascript de prototype. La librería prototype ofrece herramientas javascript muy útiles para aplicar efectos visuales en una página web con un simple llamado función. Su único defecto es la falta de documentación, pero el código es bastante sencillo.

Elegimos utilizar un helper en lugar de un parcial debido que esta función contiene mucho más código PHP que código HTML.

No olvide agregar el id id="block_<?php echo $question->getId() ?>" al fragmento question/_list.

<div class="interested_block" id="block_<?php echo $question->getId() ?>">
  <?php include_partial('interested_user', array('question' => $question)) ?>
</div>    
 

Esto funciona solo si definió apropiadamente el alias sf en la configuración de su servidor web, como fue explicado durante el día uno.

Zona de resultados.

El atributo update del helper javascript link_to_remote() específica la zona de resultados. En este caso, el resultado de la acción user/interested remplazara el contenido del elemento de id block_XX. Si se encuentra confundido, mire lo que la integración del fragmento en la plantilla:

...
<div class="interested_block" id="block_<?php echo $question->getId() ?>">
  <!-- entre aquí -->
  <?php use_helper('User') ?>
  <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">
    <?php echo $question->getInterestedUsers() ?>
  </div>
  <?php echo link_to_user_interested($sf_user, $question) ?>
  <!-- y aquí -->
</div>
...
 

La zona de resultado es la parte entre los dos comentarios. La acción, una vez ejecutada, remplazara este contenido.

El interese del segundo id (mark_XX) es puramente visual. El manejador del evento complete del helper link_to_remote resalta el <div> 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:

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 include_partial('question/interested_user', array('question' => $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:

ajax

Si desea más ejemplos acerca de los helpers AJAX, puedes leer el tutorial carrito de compra drag-and-drop, mira el screencast asociado o lee el capitulo relacionado del libro.

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 use_helper('Javascript') ?>
 
<div id="login" style="display: none">
  <h2>Please sign-in first</h2>
 
  <?php echo link_to_function('cancel', visual_effect('blind_up', 'login', array('duration' => 0.5))) ?>
 
  <?php echo form_tag('user/login', 'id=loginform') ?>
    nickname: <?php echo input_tag('nickname') ?><br />
    password: <?php echo input_password_tag('password') ?><br />
    <?php echo input_hidden_tag('referer', $sf_params->get('referer') ? $sf_params->get('referer') : $sf_request->getUri()) ?>
    <?php echo submit_tag('login') ?>
  </form>
</div>
 

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:

return link_to('interested?', 'user/login');
 

con está:

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?

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.

formulario de login revelado

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 aoff` 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. Si no tienes ningún problema, ven al foro askeet para responder preguntas de otros.

/askeet/1_0/es/9 »
« Calendario de symfony día siete: manipulación del modelo y las vistas

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the user mailing-list or to the forum.