jqGrid y Symfony: lo básico

jqGrid es un plugin de jquery que permite crear tablas dinámicas, ya sea con contenido embebido en la misma página HTML o con contenido dinámico extraído de un servidor. Este artículo aborda esta última modalidad.

La generación de tablas dinámicas con contenido extraído del servidor requiere como mínimo:

  • Un elemento <table /> en el DOM que servirá de base para que se genere la table dinámica
  • Las generación de una instancia de jqGrid con la especificación de por lo menos 4 opciones:
    • url – dirección de la que se van a extraer los datos
    • colModel – Especificación de las columnas de la tabla dinámica
    • colNames – Etiquetas de los encabezados de las columnas
  • datatype – Tipo de datos regresados por el servidor (JSON en este ejemplo)

Dependencias

A nivel Javascript la única dependencia indispensable para el funcionamient de jqGrid es jquery. Sin embargo es recomendable incluir las bibliotecas de idioma para hacer más placentera la experiencia del usuario. Por otra parte, el despliegue de las tablas requiere las hojas de estilo de jquery ui (mas no sus métodos). Dicho esto, una implementación minimum minimorum del jqGrid es la siguiente:

<!DOCTYPE html>
<html>
<head>
<title>jqGrid con Symfony</title>
<link rel="stylesheet" 
href="{{ asset('bundles/acmedemo/css/ui-lightness/jquery-ui.css') }}" />
<link 
rel="stylesheet" href="{{ asset('bundles/acmedemo/css/ui.jqgrid.css') }}" />
</head>
<body>
	<table id="grid" ></table>
	
	<script src="{{ asset('bundles/acmedemo/js/jquery.js') }}">
	</script>
	<script src="{{ asset('bundles/acmedemo/js/jquery.jqGrid.js') }}">
	</script>
	<script 
	src="{{ asset('bundles/acmedemo/js/i18n/grid.locale-es.js') }}">
	</script>
	<script language="javascript">
	$(function() {
		$("#grid").jqGrid({
			url: "{{ path('_grid_content') }}"
			, colModel: [
							{index:'nombre'}
							, {index:'apellidos'}
							, {index:'telefono'}
			]
			, colNames: ["Nombre(s)","Apellidos", "Tel\u00E9fono"]		
			, datatype: 'json'
		});
	});
	</script>
</body>
</html>

En la línea destacada del twig anterior es dónde se especifica a jqGrid cuál será el action de Symfony que ha de proporcionarle información. En tu controlador de Symfony debes tener un action que regrese información en formato JSON, de la siguiente manera:

/**
* @Route("/gridContent", name="_grid_content")
*/
public function contenidoDelGridAction() {
	$renglones = array();
	$renglones[] = array('id'=>1, 'cell'=> array('Alberto', 'Lopez', '111111111'));
	$renglones[] = array('id'=>2, 'cell'=> array('Juan', 'Sanchez', '12345556'));
	$renglones[] = array('id'=>3, 'cell'=> array('Jaime', 'Del Villar', '22222222'));
	$renglones[] = array('id'=>4, 'cell'=> array('Kim', 'Vaughn', '+45(445)272 4672'));
	$contenidoParaJqGrid = array(
		'total'=>1, 
		'page'=>1, 
		'records'=>1,
		'rows'=>$renglones
	);
	return new \Symfony\Component\HttpFoundation\Response(
		json_encode($contenidoParaJqGrid)
		, 200
		, array('content-type'=>'application/json') 
	);
}

La combinación anterior nos genera una tabla dinámica similar a la siguiente:

grid-basico

Tutorial

Vamos a aprovechar el bundle ejemplo que viene empacado con Symfony (AcmeDemoBundle). Si has descargado Symfony de symfony.com deberás tener la subcarpeta src/Acme/DemoBundle:

(Para información en español sobre la correcta instalación de Symfony recomiendo la guía en http://gitnacho.github.io/symfony-docs-es/book/installation.html. Para este tutorial no sigas la parte en la que dice “Cómo eliminar el AcmeDemoBundle” porque este será precisamente el bundle que utilizaremos).

Si puedes ver la página de bienvenida de Symfony y al dar clic en el botón “RUN THE DEMO” estás listo para continuar.

1) Modifica el archivo Symfony/src/Acme/DemoBundle/Controller/DemoController.php. Vas a insertar dos funciones nuevas a la clase DemoController:

/**
* @Route("/grid")
* @Template()
*/
public function gridAction() {
	return array();
}
	
	
/**
* @Route("/gridContent", name="_grid_content")
*/
public function contenidoDelGridAction() {
	$renglones = array();
	$renglones[] = array('id'=>1, 'cell'=> array('Alberto', 'Lopez', '111111111'));
	$renglones[] = array('id'=>2, 'cell'=> array('Juan', 'Sanchez', '12345556'));
	$renglones[] = array('id'=>3, 'cell'=> array('Jaime', 'Del Villar', '22222222'));
	$renglones[] = array('id'=>4, 'cell'=> array('Kim', 'Vaughn', '+45(445)272 4672'));
	$contenidoParaJqGrid = array(
		'total'=>1, 
		'page'=>1, 
		'records'=>1, 
		'rows'=>$renglones
	);
	return new \Symfony\Component\HttpFoundation\Response(
		json_encode($contenidoParaJqGrid)
		, 200
		, array('content-type'=>'application/json') 
	);
}

2) En el directorio Symfony/src/Acme/DemoBundle/Resources/views/Demo crea un nuevo archivo grid.html.twig y pon en él el código del principio de este artículo.

3) Para que el ejemplo funcione es necesario instalar las bibliotecas de hojas de estilo y de javascript de jquery, jquery ui y jqGrid. Por estándar estas bibliotecas debes instalarlas en Symfony/src/Acme/DemoBundle/Resources/public.

NOTA: Para fines didácticos he renombrado los archivos de las bibliotecas quitando la información referente a las versiones. Cuando prepares aplicaciones productivas es recomendable que incluyas dicha información para evitar problemas de compatibilidad en el futuro.

Tu estructura de directorios de recursos debería quedar como

Symfony/src/Acme/DemoBundle/Resources/public
	/js
		/jquery.jqGrid.js
		/jquery.js
		/i18n
			/grid-locale-xx.js (muchos como este)
	/css
		/demo.css (parte del AcmeDemoBundle original)
                /ui.jqgrid.css
		/ui-lightness
			/jquery-ui.css
			/images
				/todos lo iconos parte de jquery ui

4) Para que las bibliotecas css y js se traspasen al directorio de trabajo de Symfony y puedan ser accedidos desde un browser es necesario que ejecutes la siguiente línea de comando en el directorio base de Symfony:

php app/console assets:install web

NOTA: si por alguna razón la línea de comando te marca un error es seguramente por un problema de permisos. Consulta “Configurando permisos” en http://gitnacho.github.io/symfony-docs-es/book/installation.html para mayor información.

Si todo va bien podrás abrir con tu browser http://localhost/Symfony/web/app_dev.php/demo/grid y podrás ver tu primer tabla dinámica con jqGrid.

So you think you can deploy

I am deploying my first Python production app with django and other Stuff. I was really happy because I was about to launch the app with the industrial-strength Apache server, which all we know is the leaner, faster web server that exists… until I was told it isn’t! It happens to be that there are faster web servers for linux, and they are just as low cost as Apache. Lighttpd, TUX and Cherokee are just some among a myriad of light-weight web servers to be used and abused.

Apache is still the web-server-of-choice for dynamic content, though. Millions of LAMP apps seem to certify this fact. It only happens to be that Apache is comparatively slow delivering static content, and static content is very important in today’s rich Internet apps (my twitter.com home, for example, measures 599.2 KB, from which 279KB are static content -mostly Javascript and images).

I am going away with Apache as my dynamic content server and lighttpd for static content. I still have to work on this because, since the app features SSL, I foresee certificate problems and the annoying browser warning that mixed (i.e. secure and non-secure) content is going to be delivered.

That’s what happens when you spend 4 years under Microsoft spell! This is the wake up call, I guess.

I’ll keep you posted on developments.

Img0000

 

Posted by ShoZu

Carrera del día del padre 2009

La carrera estuvo bastante fluida y el recorrido fue un acierto. Espero que lo conserven para los siguientes años. La altimetría presagiaba una tragedia para mí: 10 Km de bajada + 10 Km de subida! Los que corren en el Bosque de Tlalpan no tuvieron problema (se la pasan corriendo 400 ms de bajada y 400 ms de subida, en su pistita para hamsters), pero los que solemos entrenar en cintas sufrimos cañón (ni pex, tendré que pegarle al pavimento más seguido).

Como es mi primera carrera del día del padre no sé qué sea tradicional en ella o no. A mí se me hizo un gran detalle el que hubiese un mariachi casi cada 2 Km…solo en México, me cae!

Otra cosa curiosa es que el pavimento se ponía resbaloso en las zonas de rehabastecimiento de Gatorade. O nunca me hábía dado cuenta, o el clima hizo que pasara en esta ocasión. A mi me dio algo de miedo (sobre todos después de mi azotón en la carrera nocturna).

¿Qué onda con la gente que carga su cinturón con 20 botellitas de agua? Si vas a correr a la Marquesa voy de acuerdo: no siempre encuentras un puesto de quesadillas para recargar el tanque. Pero en una carrera en la que avisan que te van a dar agua cada 2.5 Km, ¿para qúé gastarse? Se me hace algo así como ir a formarte a la casilla electoral para depositar tu voto nulo.

Los organizadores tuvieron una gran idea al convencer a Perisur de abrir el estacionamiento desde temprano. El problema fue que a la gente de Perisur se les fue el avión. Yo llegué a Perisur a las 6:00, solo para encontrarme conque SOLO UN ACCESO de Perisur estaba abierto (y para acabarla, era el único acceso que los organizadores de la carrera dijeron que iba a estar cerrado). Tardé 40 minutos en entrar al estacionamiento, una vez que a alguno de los polis de Perisur se le prendió el foco y abrió otros accesos.

Y para culminar con el problema del estacionamiento, la delegación tuvo la idea (sensata, debo reconocerlo) de no dejar salir a nadie de Perisur antes de las 11 de la mañana, hasta que el último corredor (¿caminador?) hubiese cruzado la meta. ¿Qué pasó a las 11? Que 11,000 corredores con sus familias quisieron salir todos al mismo tiempo de Perisur…otro caos.

Los héroes de la carrera son, como siempre, las personas de los abastos de agua, Gatorade, comida, medallas, etc. Y los superhéroes son las personas que se ponen a la orilla de la carrera a echar porras a 11,000 desmañanados idiotas que corren sin motivo alguno. Hasta a mí, Mr. Grinch Scroodge, me conmueven esos gestos espontáneos.

Todo bien: regreso cuando quieran. Nada más que para la otra, me voy en taxi y me regreso a ver cómo. Ni loco me llevo el carro!

Look ma’: no Java

My first PRODUCTION Spring.Net application

 My first Spring.Net application got deployed on production on Oct 1st. After two weeks stabilizing, the application is working smoothly and users are happy and management is not longer complaining about my bold decision.  How I got there: 

1)      One week studying and tweaking Spring.Net’s sample applications, namely SpringAir and the Northwind database example

2)      One week building and testing my POC

3)      One week designing GUI

4)      One week designing classes

5)      Two weeks trying to convince my staff to switch their monolitical view of .NET development. It was during this period that I heard a programmer saying “there’s not such thing as Interface’s in C#”. True story.

6)      1 month coding, testing and stabilizing

7)      2 painful weeks migrating data from former system

8 )      2 weekends trying to populate a GridView from a Spring.Net IN AN EFFICIENT WAY. I finally gave up and implemented a fast lane reader for the GridViews that reads from a plain-vanilla DataSet. There must be a better way, though. 

My conclusion: C# is a great language, and IMHO it is as good as Java. Visual Studio 2005, compared with Eclipse 3.1, sucks in every single category but debugging (I don’t expect much from VS 2008 anyway). What I missed most from Eclipse were the refactoring capabilities: Visual Studio doesn’t even have a feature to create setter and getters for all properties in a class: if you want to generate a setter-getter you have to do it property-by-property, and the refactoring “wizard” takes as long as 30 secs to generate a single setter-getter pair, requiring user interaction in the middle of the operation. If you have a 15 properties DTO, just do the math!

IMSS 2.0

No manchen! Quieren resucitar al muerto del proyecto del IMSS! No es por ser pesimistas, pero creo que después de gastar más de 1000 millones de pesos y cancelar el proyecto, ya se demostró que no va por ahí. Ojalá me equivoque, de veras que sí.

Lo que realmente me preocupa de este pedo, es que van a volver a calentar el mercado laboral y los recursos en Java otra vez van a estar carísimos e inencontrables. Consejo: si van a arrancar un proyecto en el corto o mediano plazo, vayan pensando seriamente en .NET como opción. Ya sé, ya sé, somos esclavos del capitalismo y blah, blah, blah…pero siendo realistas, el 99% de las licencias de .NET en la Ciudad de México se venden en Meave, así que no creo que Bill Gates se meta mucha lana si todo lo hacemos en .NET. Yo, por si las flies, ya estoy instalando CruiseControl.NET, NHibernate y Spring.NET, y haciendo mis pininos en NUnit.

No vaya a ser…

Hasta pronto JackBe, hola (de nuevo) Dominion

Como se habrán enterado, Julio fue mi último mes en JackBe y Agosto es mi primer mes de mi nueva etapa en Dominion.

¿Porqué?

Digamos que fue una cadena de sucesos desafortunados aunados a la inconciencia de Dominion de volverme a invitar a colaborar. Como siempre, no hay un solo motivo para las cosas, y al final día es una combinación de motivos los que me llevaron a tomar mi decisión. Entre ellos están:

  • Un reto muy atractivo en Dominio
  • El desgaste familiar en el que había incurrido dado el desafío del proyecto en JackBe
  • La lejanía geográfica

Por otra parte, debo agradecer muy especialmente a Ricardo Suárez, Director de JackBe México, su comprensión y apoyo en esta difícil transición; señoras y señoras de JackBe: sepan que en Ricardo siempre encontrarán a una persona que antepone el lado humano al negocio, y que siempre estará dispuesto a escuchar los motivos, a comprenderlos y por supuesto a aconsejar.

I am forever in your debt, Captain Ricardo

Por otra parte, creo que mi paso rápido por JackBe ha dejado su huella en mí. JackBe es una especia de virus benigno pero incurable, que te hace sentir una persona especial haciendo algo muy especial en un ambiente muy cabrón pero al que se le terminará domando. Es como una inconciencia colectiva que te hace dar más de tí con una visión común, de sí se puede, sí se puede, sí se puede, con un puñado de compañeros que nunca terminas de comprender porqué dan tanto de sí y porqué trabajan 14 horas diarias de Lunes a Lunes. ¿Eso es bueno? ¿Eso es malo? No lo sé. Me gusta pensar que tanto esfuerzo es palpable y redituable, y que al final del camino JackBe será una referencia obligada del éxito mexicano.

Otra cosa que JackBe me dejó es que ahora soy más pocho que nunca ¿you know? From now on, este blog se escribirá en Spanghish ;)! Creo que eso lo van a odiar un poquito los españoles y argentinos de Dominion…as long that this is poquito, it’s OK!

Estoy a sus órdenes en alberto.gaona@dominionmexico.com.mx

Se aceptan invitaciones para:

  • El Tenampa
  • El Estadio Azul
  • El Hooters
  • Java topics
  • Hablar de problemas Opics

¡En ese estricto orden!

Forever yours

Alberto Gaona

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.