Mostrando entradas con la etiqueta kumbia. Mostrar todas las entradas
Mostrando entradas con la etiqueta kumbia. Mostrar todas las entradas

viernes, 7 de octubre de 2011

Jugando con KumbiaPHP


Aunque ya he trabajado con KumbiaPHP en este blog, me tomaré unas 2 o 3 entradas, a manera de tutorial para explicar algunos aspectos del framework.

KumbiaPHP es un framework sumamente sencillo de usar y sobre todo práctico, implementa el patrón MVC y es además muy liviano, comparado con otros frameworks populares.

Otras razones para utilizar KumbiaPHP: está escrito en español, por hispanohablantes y se caracteriza por ser muy muy rápido. Aquí un benchmarking para comparar rendimiento con algunos frameworks.

Lo primero que debemos hacer es descargar la librería. Al momento de escribir este tutorial, la última versión oficial es la v1.0 Spirit, que se puede descargar desde la web. Sin embargo, mi recomendación es uitlizar la versión de desarrollo, que se encuentra en una fase estable y contiene muchas mejoras con respecto a la v1.0. Esta última, podemos descargarla del repositorio en launchpad. Es con esta versión que trabajaré en lo sucesivo.

Bien, luego de descargar, descomprimimos el archivo en nuestro directorio web y obtendremos la siguiente estructura:

kumbiaphp/
|--core
|--default
|--.htaccess

Para verificar que todo vaya bien, en un navegador vamos a la url de nuestro site, y debería mostrarse la página de bienvenida de kumbia.

Ahora detallemos un poco los directorios que vienen por omisión.

En core encontraremos todos los archivos del framework. En core/vendors están todas las bibliotecas externas que utiliza kumbia (es aquí donde debemos colocar cualquier biblioteca que necesitemos), y en core/libs están las bibliotecas desarrolladas/mantenidas por kumbia.

Con la descarga, viene un directorio default, el cual contiene una aplicación que sería la aplicación por omisión. Al mismo nivel de default podemos crear todas las aplicaciones que querramos.

En lo sucesivo trabajaré con default, pero repito, podemos crear otros directorios si queremos. Dentro de default, encontramos 2 subdirectorios: default/app y default/public. En el primero irá el core de nuestra aplicación, mientras que en el segundo almacenaremos todos los recursos (imágenes, scripts, hojas de estilo, archivos flash, etc) que se utilizarán en las páginas webs de nuestra aplicación.

En default/app/config están los archivos de configuración de nuestra aplicación. En default/app/models, default/app/views y default/app/controllers estarán los modelos, vistas y controladores.

Dentro de views/_shared/templates, está la plantilla por defecto: default.phtml (se usará en todas las vistas en las cuales no especifiquemos otra plantilla). En view/_shared/templates podemos guardar todas las plantillas que queramos y utilizarlas cuando sea necesario.


Un poco sobre MVC

No se trata de un tutorial del patrón MVC, así que daré sólo los detalles necesarios. Cada controlador está implementado como un archivo con nombre nombre_controller.php en el subdirectorio app/controllers. Por ejemplo, si queremos un cotrolador "principal", crearemos un archivo principal_controller.php. Este archivo es básicamente una clase, de nombre nombreController, heredada de AppController, con una serie de métodos públicos, que serían las acciones de nuestro controlador.

Por cada controlador, debe existir un subdirectorio en app/views con el mismo nombre de nuestro controlador. Por cada acción debe existir un archivo con extensión .phtml en este subdirectorio. Por ejemplo, si nuestro controlador principal tiene las acciones bienvenida y despedida, en app/views crearemos un directorio principal, que debe contener los archivos bienvenida.phtml y despedida.phtml.

La siguiente imagen, tomada del wiki de kumbia muestra cual es la relación entre controladores/acciones y URLs:



Esto si core y default están en el directorio raiz del directorio web del servidor. En nuestro caso, no es así, sino que están dentro de otro directorio que creamos dentro del directorio web del servidor y que hemos llamado kumbiaphp, por lo que nuestras rutas serían del tipo http://dominio/kumbiaphp/controller/action.

Sin mayor preámbulo, creamos nuestro primer controlador (principal_controller.php):

<?php 
class PrincipalController extends AppController {
    public function bienvenida() 
    {
        $this->bienvenida = "Bienvenido a KumbiaPHP";
    }

    public function despedida() 
    {
        $this->despedida = "Vuelve pronto";
    }
}
?>

Nuestra primera vista (bienvenida.phtml):

<h1>KumbiaPHP</h1> 
<p><?php echo $bienvenida ?></p>

Y nuestra segunda vista (despedida.phtml):

<h1>KumbiaPHP</h1> 
<p><?php echo $despedida ?></p>

Ahora si en el navegador vamos a http://localhost/kumbiaphp/principal/bienvenidahttp://localhost/kumbiaphp/principal/despedida, veremos los mensajes correspondientes a cada vista.

Debemos notar que aunque en las vistas sólo hay un par de líneas, en el navegador se ve nuestro contenido, enmarcado en la plantilla por omisión (default.phtml). Podemos modificar o sustituir esta plantilla por una nuestra. Sólo debemos tener presente 2 cosas:
  • No debemos eliminar la línea <?php View::content(); ?>, pues esa es la instrucción que le dice al framework que muestre el contenido propio de la vista (y en qué lugar dentro de la plantilla hacerlo).
  • La sintaxis para la inserción de contenido, que explicaré a continuación.


Incluyendo contenido en una plantilla

Bien sea que sustituyamos default.phtml, o que creemos una nueva plantilla, tenemos que saber como se incluyen ciertos elementos en nuestras vistas, a través de los numerosos helpers que provee el framework.

Para incluir correctamente archivos css:

<?php Tag::css('wide-blue/style') ?>
<?php echo Html::includeCss() ?>

Esto supone que tenemos un archivo style.css, y está ubicado en el subdirectorio app/public/css/wide-blue.

Para incluir imágenes:

<?php echo Html::img("lvbp.jpg"); ?>

Para incluir enlaces:

<?php echo Html::linkAction("enlace", 'Titulo') ?>

Para que estos helpers funcionen, debemos recordar que debemos guardar las imágenes, css y javascripts en los directorios correspondientes dentro de app/public.

En la próxima entrega...

De momento, con esto es suficiente para que elaboremos una o más plantillas y dejemos el entorno a punto para trabajar. Ya sabemos que para enviar información del controlador a la vista, basta con definir en el último, una variables $this->nombre_variable y luego en la vista podremos accederla como $nombre_variable. No hemos hablado de modelos porque no ha sido necesario, lo haremos en la siguiente entrega, al igual que el pase de datos desde las vistas hacia los controladores.




viernes, 30 de septiembre de 2011

Peticiones Ajax síncronas con jQuery

En la entrada pasada publiqué un código para asignar variables de sesión PHP desde jQuery con un POST enviado via Ajax. El código del script es el siguiente:

<script type="text/javascript">
  $(function() {
    $('.print_link').click(function() {
		var fixedurl = 'http://localhost/miapp/main/set_session_var';

		$.post( fixedurl,
		{ object_name: 'tmprow',
          id: $(this).attr('id'),
          monto: $(this).parent().parent().find('.monto').html()
		 },
			function(data){
			//donothing
		});

      return true;
    });
  });
</script>

Luego, en set_session_var (ya en PHP) se hacía el trabajo ordinario de asignar la variable de sesión. Hice la prueba con un ejemplo sencillo en que se tenían 2 vistas, test1 y test2, y cuando se hacía click a un enlace en test1 que llevaba a test2, se ejecutaba la función, justo antes de abandonar la página, de manera que ya en test2, "con suerte" se pudieran usar las variables recién asignadas.

He dicho "con suerte", porque, tratándose de Ajax y su asincronía, no tenemos la certeza de que cuando se cargue test2, ya las variables estén asignadas. El ejemplo mostrado era realmente sencillo, por lo que esto practicamente siempre se cumplía, pero luego comencé a hacer otras cosas en la función set_session_var, que hicieron que eventualmente, cuando cargara test2, aún no estaban mis variables de sesión.

¿La solución? Hacer el envío de forma síncrona, de manera que en el "return true;" garantice que ya se haya ejecutado el POST. Esto con $.post() de jQuery no se puede hacer, hay que utilizar $.ajax() directamente. Recordemos que $.post() es un atajo/simplificador de $.ajax para envío de POST asíncronos, el cual no permite especificar todas las opciones de $.ajax().

Bien, a $.ajax() podemos especificar la opción 'async' (que por omisión está en true, es decir, todo es enviado de forma asíncrona). Lo que tenemos que hacer es ponerla en false y ya. Es muy simple, en realidad. Dejo el código del script, sustituyendo el $.post() por $.ajax():

<script type="text/javascript">
  $(function() {
    $('.print_link').click(function() {
		var fixedurl = 'http://localhost/miapp/main/set_session_var';

		$.ajax({url: fixedurl,
		  type: 'POST',
		  async: false,
		  data: { object_name: 'tmprow',
           id: $(this).attr('id'),
           monto: $(this).parent().parent().find('.monto').html() }
		});
      return true;
    });
  });
</script>

jueves, 8 de septiembre de 2011

Sobre el reenvío de formularios via POST


A todo el mundo le ha pasado que en una aplicación web hay un formulario, la data se envía por POST, se realiza alguna acción con esa data, se muestra algo al usuario, el usuario pincha un link para ir a otra página del sitio, luego le da al botón Atrás y... ¡PUM! El navegador muestra al usuario ese horrible mensaje de que debe reenviar la información del formulario. Pasa en eztv.it, por ejemplo.

No es un bug de la aplicación, ni del navegador, pero es simplemente es desastroso para la imagen de nuestra aplicación frente al cliente.

Solución 1

Existen diversas formas de tratar el problema. La solución obvia, es no usar POST, sino GET. Particularmente no me gusta el método GET, pero si enviamos la data del formulario por esta via, no tendremos el problema, pues va en la propia URL.

Solución 2

Usar POST, pero con Ajax. Simple y elegante. Enviamos via AJAX nuestra mensaje POST a un método que nos devuelva el código HTML de la data que queremos y lo incrustamos en el DIV que tengamos destinados para mostrar la data. Con JQuery, por ejemplo hacer esto es realmente sencillo.

Ejemplo

Voy a mostrar un pequeño ejemplo, utilizando la librería KumbiaPHP con JQuery. Queremos una página para buscar (y listar) clientes de una tabla de clientes en BD. En la vista tenemos un campo input para que el usuario introduzca la palabra clave y un botón de submit

El controlador cliente_controller.php:

<?php
Load::models('cliente');

class ClienteController extends AppController
{
	public function index()
	{
		$cliente = new cliente();

		if(Input::hasPost('search_key'))
		{
			$search_key = Input::post('search_key');
			$this->clientes = $cliente->selectClienteByCedulaLike($search_key);
			View::select('p_clientes');
			View::template(null);
		}
		else
		{
			$this->clientes = null;
		}
	}
}
?>

La vista index.phtml:

<script type="text/javascript">
$(function() {
	$('#validateform').submit(function() {
		var url = $(location).attr('href');
		var key = $('#cedula').val();
		$.post( url,
		{ search_key: key },
			function(data){
			var capa = $('#tablecontainer');
			capa.html(data);
		});
		return false;
	});
});
</script>

<div id="content">

	<div id="page-heading"><h1>Gestión de Clientes</h1></div>

	<!--  start searchForm  -->
	<?php echo Form::open('','post','id="validateform"'); ?>
	<table>
	<tr>
	<td><?php echo Form::text('cedula','class="inp-form"') ?></td>
	<td><?php echo Form::submit('Buscar', 'class="form-search"') ?></td>
	</tr>
	</table>
	<?php echo Form::close() ?>
	<!--  end searchForm -->

	<div> </div>
	<div class="clear"></div>

	<!--  start client-table -->
	<div id="tablecontainer">
	<!--  Aqui es donde ira el contenido que luego incluiremos via Ajax -->
	</div>
	<!--  end client-table -->
</div>

La vista en la que crearemos la tabla p_clientes.phtml:

<table border="0" width="100%" cellpadding="0" cellspacing="0" id="client-table">
<tr>
	<th class="table-header-repeat line-left minwidth-1"><a href="">Cedula</a></th>
	<th class="table-header-repeat line-left minwidth-1"><a href="">Nombre</a></th>
	<th class="table-header-repeat line-left"><a href="">Telefono</a></th>
</tr>


<?php if($clientes != null) foreach ($clientes as $cliente) : ?>
<tr>
	<?php echo "<tr>"; ?>
	<td><?php echo $cliente->Cedula ?></td>
	<td><?php echo $cliente->nombre ?></td>
	<td><?php echo $cliente->telefono ?></td>
</tr>
<?php endforeach; ?>
</table>

Y eso es todo. Cada vez que el usuario de click al botón buscar, se ejecutará una petición POST con la palabra clave que introdujo el usuario, con el resultado de la búsqueda se construirá una tabla en la vista p_clientes.phtml, que será incrustada dentro del div "tablecontainer" de nuestra vista index.phtml.

No incluí el modelo, porque no lo considero relevante para lo que se quiere mostrar aquí.

Préstese especial atención al script que se encarga de sustituir la data. Es una simple función que se ejecuta cada vez que el usuario presiona el boton de enviar. Obsérvese además que esa función retorna false, pues no queremos que el post sea enviado tradicionalmente. Por supuesto, para mayor detalle, acudir a la documentación oficial de jQuery.