sábado, 11 de diciembre de 2010

Kumbia + jQuery


En esta entrada voy a seguir trabajando con nuestra tabla 'state'. Recordemos que un estado se encuentra dentro de un país, lo que en base de datos implementamos mediante una clave foranea country_id a la tabla 'country' en la tabla 'state'. A medida que agregamos estados, la lista completa de estados podría llegar a ser muy grande. Una manera alternativa de mostrar los datos, es permitiendo al usuario seleccionar un país (de una lista desplegable) y mostrar en la tabla sólo los estados que pertenecen al país seleccionado.

En computación, como en la vida misma, casi siempre un problema puede ser cierto de diversas formas. Esta no es la excepción. Yo voy a resolver este problema utilizando Ajax. Concretamente, utilizaré jQuery, una de las bibliotecas JavaScript más utilizadas en el mundo, la cual provee un conjunto de funciones que facilitan enormemente el trabajo con Ajax y el DOM.

La idea es programar una función (en JavaScript) que maneje el evento onChange de nuestro combo de países. Cada vez que seleccionemos un país de la lista, realizar una búsqueda en base de datos de los estados que pertenecen al país, y mostrar esa data en una región de página web (concretamente un DIV) definida desde el principio para ese propósito. Así, esta región cambiará dinámicamente cada vez que cambiamos de país, sin necesidad de recargar toda la página.


Agregando jQuery

Para poder utilizar las funciones de jQuery debemos incluir la siguiente línea:

<?php echo Tag::js('jquery/jquery.min'); ?>

en todos los archivos que necesitemos. Si vamos a utilizar jQuery en muchas interfaces, sería lógico incluirla en la plantilla. Pesa menos de 80KB en su versión comprimida.

En la versión actual de kumbia se incluye la versión 1.4.2 de jQuery. La versión más nueva al momento de escribir estas líneas es la 1.4.3, que puede descargarse de la web oficial.


Manos a la obra

Voy a explicar por capas lo que debemos hacer:

Modelo: a nuestro modelo state, debemos agregar una función que busque estados en la base de datos, por la clave del país.

Vista: debemos agregar una nueva vista, en la que tendremos nuestro combo, la función para manejar el evento onChange() del combo, el DIV en el cual mostraremos la tabla de estados.

Controlador: el controlador recibirá de la vista el id del país, debe realizar la búsqueda de estados por país programada ya en el modelo y debe enviar la tabla a la vista nuevamente.


Comencemos por lo más sencillo: el modelo. Necesitamos una función muy sencilla, que reciba el id de un país y busque en BD todos los estados cuyo país sea ese. Podemos utilizar la función find(), pero no lo haré, escribiré mi propio SQL:

public function getStatesWithCountry($page, $ppage=1000)
{
$sqlquery = "SELECT state.id, state.state_name, country.country_name FROM state INNER JOIN country ON(state.country_id = country.id)";
return
$this->paginate_by_sql($sqlquery, "page: $page", "per_page: $ppage");
}

Como vemos, una función muy sencilla. Siguiendo en orden de simplicidad, pasaré al controlador. A nuestro state_controller, agregamos una función index2() cuyo código es el siguiente:

public function index2()
{
$state = new State();

Load::models('country');
$country = new Country();
$listCountries = $country->getCountriesBySql();

$this->country_names = array();
foreach (
$listCountries as $item)
{
$this->country_names[$item->id] = $item->country_name;
}
if(
Input::hasPost('country_id'))
{
$this->listStates = $state->getStatesByCountry(Input::post('country_id'));
View::response('view');
View::select('response');
}
}


En esta función lo que hacemos es:

1) Buscar en BD los países, meter esos países en un arreglo que utilizaremos en nuestra vista para llenar el combo. Nótese que utilizo una función getCountriesBySql(), que hace simplemente un "SELECT * FROM country".
2) La parte importante. Si la función recibe por POST un 'country_id', entonces mediante la función que recien creamos (getStatesByCountry()) llenamos un arreglo con los estados que se encuentran dentro del país especificado y finalmente utilizamos las funciones mágicas: View::response('view') y View::select('response'). Con la primera indicamos que queremos que la respuesta se muestre en la misma vista y con la segunda indicamos el nombre del archivo phtml (en esta caso response.phtml) que embederemos en nuestra vista.

Ahora pasemos a las vistas. Recordemos que tenemos que crear nuestra vista principal (que llamamos index2) y una vista que contendrá el código html del contenido que mostraremos dentro de index2. Comenzamos con la primera:

<script>
$(document).ready(function()
{
$('.target').change(function()
{
var url = $(location).attr('href');
var key = $('.target option:selected').val();
$.post( url,
{ country_id: key },
function(data){
var capa = $('#result');
capa.html(data);
capa.hide();
capa.show('slow');
});
});
});
</script>

<div class="content">
<?php echo View::content(); ?>
<h3>States</h3>

<?php echo Form::open() ?>
<?php

echo
Form::select('country_id', $country_names, 'class="target"'); ?>
<?php echo Form::close() ?>

<!-- Este div sera luego sustituido con la respuesta -->
<div id="result">
<br>
Seleccione un pa&iacute;s
</div>

</div>

Lo primero que encontramos es un código JavaScript que se encargará de manejar el evento OnChange del combobox. Este trozo de código lo codifiqué en base a lo que se consigue sobre .change() en la documentación oficial de jQuery. Básicamente lo que hace es:
1) Cada vez que se produzca un cambio sobre (TODOS) los objetos de clase "target", se hace un POST a su misma dirección Es aquí cuando el controlador recibe el country_id y realiza la búsqueda y devuelve el código HTML de la vista 'response'.
2) Sustituye el código HTML que se encuentra dentro de (TODOS) los objetos con id "result" con la data devuelta.

Aunque creo que no hace falta (y sería bueno hacerlo de ejercicio), muestro a continuación el código de response.phtml:

<table>
<col class="first-column" />
<col span="2" />
<col class="last-column" />
<tr class="first-row">
<th>Season</th>
<th>League</th>
<th></th>
</tr>
<?php foreach ($listStates as $item) : ?>

<tr>
<td><?php echo $item->state_name ?></td>
<td><?php echo $item->country_3166 ?></td>
<td><?php echo Html::linkAction("edit/$item->id/", 'Edit') ?></td>
</tr>

<?php endforeach; ?>
</table>

Es un simple trozo de html en el que mostramos una tabla, con los datos que nos deja el controlador en la variable $listStates.

jQuery es una de las bibliotecas de JavaScript más utilizadas en estos días. Facilita mucho el trabajo y como vemos se integra fácilmente con kumbia. Recomiendo aprender a trabajar con ella. Acá dejo un par de enlaces que pueden ayudar:



Y por supuesto la documentación oficial, que es imprescindible:



Hasta la próxima entrada!

jueves, 21 de octubre de 2010

Jugando con Kumbia (2)


Ya tenemos una tabla country en BD, hicimos un modelo, un controlador y unas vistas para realizar sobre ella las operaciones básicas de un CRUD.

Ahora, para ir complicando las cosas, vamos a crear una tabla 'state' para almacenar estados de un país, en la cual vamos a tener una clave foránea a la tabla 'country'. El código SQL de la tabla es el siguiente:

CREATE TABLE state
(
id serial NOT NULL,
state_name character varying(128),
country_id bigint NOT NULL,
CONSTRAINT pk_state PRIMARY KEY (id),
CONSTRAINT fk_country FOREIGN KEY (country_id)
REFERENCES country (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE state OWNER TO beisboluser;

Creamos nuestro modelo, controlador y vistas, tal como creamos los propios para 'country'. Cuando lo probamos, e intentamos ingresar una tupla, nos enfrentamos al primer problema: tendríamos que insertar el id del país, lo cual simplemente no sirve. Lo lógico es que aquí contemos con un combo con todos los países y entre ellos seleccionemos el que corresponda.

Para ello, utilizamos el objeto Form::select(), al cual le vamos a pasar el arreglo con los datos que queremos mostrar (en este caso, países), así que primero, debemos ir a nuestro controlador y crear este arreglo. Esta es la función create de nuestro estate_controller.php:

public function create()
{
Load::models('country');
$country = new Country();
$listCountries = $country->getCountries(1);

$this->country_names = array();
foreach ($listCountries->items as $item)
{
$this->country_names[$item->id] = $item->country_name;
}

if(Input::hasPost('state'))
{
$state = new State(Input::post('state'));
if(!$state->save()){
Flash::error('Falló Operación');
}else{
Input::delete();
}
}
}

Lo 'nuevo' son las líneas al comienzo. Cargamos el modelo country y listamos los países. Luego simplemente recorremos la lista de países y vamos almacenando en un arreglo asociativo (así es el arreglo que recibe Form::select()) los ids junto con los nombres de los países.

Ahora veamos nuestro create.phtml:

<div class="content">
<?php View::content(); ?>
<h3>Add State</h3>

<?php echo Form::open(); ?>

<br>
<label>Name
<?php echo Form::text('state.state_name'); ?></label>

<br>
<label>Country
<?php echo Form::select('state.country_id',

$country_names)?></label>

<?php echo Form::submit('Add') ?>

<?php echo Form::close() ?>
</div>

A Form::select() le pasamos como primer parámetro el campo que se almacenará en BD (country_id), y como segundo argumento, el arreglo asociativo (no hace falta decir qué va en el option y qué se muestra en el navegdor).

Si volvemos a probar la interfaz de creación, debe aparecer nuestro combo para seleccionar el país. Insertemos algunos para probar.

El segundo fallo lo encontramos en la acción index. En la tabla, tendremos la lista de estados que hemos ingresado, junto con el id del país correspondiente. Lo lógico, sería que mostraramos el nombre del país y no el id.

Si hicimos nuestro 'state' tal como 'country' o como en el ejemplo Beta2 CRUD, el modelo tendrá sólo una función getStates(), que internamente utiliza paginate() para listar los elementos que se encuentran en la tabla state, mostrando por página la cantidad de tuplas que especifiquemos. El problema es que en esta tabla sólo tenemos el id del país y no el nombre: necesitamos hacer una unión con la tabla 'country'. Lo que haremos será crear otra función en el modelo, que llamaremos getStatesWithCountry, cuyo código es el siguiente:

public function getStatesWithCountry($page, $ppage=1000)
{
$sqlquery = "SELECT * FROM state INNER JOIN country ON (state.country_id = country.id)";
return $this->paginate_by_sql($sqlquery, "page: $page", "per_page: $ppage");
}

Lo que hicimos fue crear una cadena con nuestra consulta y pasársela como argumento a la función paginate_by_sql(), propia de Active Record. Luego, debemos modificar nuestro index, para que utilice getStatesWithCountry() y no getStates():

public function index($page=1)
{
$estate = new Estate();
$this->listStates = $estate->getStatesWithCountry($page);
}

Y lógicamente, modificaremos la vista index.phtml para que utilice el campo country_name, en vez de country_id:

<div class="content">
<?php echo View::content(); ?>
<h3>States</h3>

<?php echo Html::linkAction("create", 'Add') ?>

<table>
<col class="first-column" />
<col span="3" />
<col class="last-column" />
<tr class="first-row">
<th>Name</th>
<th>Country</th>
<th></th>
<th></th>
</tr>
<?php foreach ($listEstates->items as $item) : ?>
<tr>
<td><?php echo $item->estate_name ?></td>
<td><?php echo $item->country_name ?></td>
<td><?php echo Html::linkAction("edit/$item->id/", 'Edit') ?></td>
<td><?php echo Html::linkAction("del/$item->id/", 'Delete') ?></td>
</tr>
<?php endforeach; ?>
</table>

</div>


Y eso es todo, nuestra vista quedará funcionando. En este caso, utilizamos la función paginate_by_sql(), la cual retorna el mismo objeto que paginate(), pero ajustado a la sentencia SQL que ejecutemos. Esta es sólo una de las posibilidades que ofrece kumbia. También podemos utilizar la función find() y la función find_all_by_sql().

Kumbia recomienda evitar utilizar código SQL directamente. Yo no le encuentro ningún problema, de hecho, me agrada construir mis propias consultas SQL. Cuestión de gustos.

La función find_all_by_sql() también recibe la consulta SQL, pero no realiza paginado, es decir, que retorna en un arreglo todos los elementos consultados. La función sería así:

public function getEstatesWithCountry()
{
$sqlquery = "SELECT * FROM state INNER JOIN country ON (state.country_id = country.id)";
return $this->find_all_by_sql($sqlquery);
}

Y si utilizamos esta opción, tendríamos que modificar la vista, pues ahora no tenemos un objeto Page, sino un simple arreglo. Sólo necesitamos hacer un cambio en el foreach, que quedaría así:

<?php foreach ($listStates as $item) : ?>


Dejo la entrada hasta aquí. En el siguiente post seguiré introduciendo algunos otros conceptos de kumbia a medida que voy construyendo mi aplicación. Buenas noches


miércoles, 20 de octubre de 2010

Jugando con Kumbia


Después del percance que comenté en la entrada anterior, he comenzado a recuperar parte de las cosas que perdí con mi DD. Entre las decenas de aplicaciones que normalmente uso, está por supuesto XAMPP. Me he descargado la última versión (la 1.7.3) la cual -entre otros cambios- viene con PHP 5.3.1. Instalé, hice algunas pruebas y todo bien.

El problema se presentó cuando fui a instalar kumbiaPHP. Me descargué la versión que tienen en el website y cuando intenté hacer algunas cosillas, prácticamente todas las pruebas fueron infructuosas. Lo primero que pensé fue que kumbia no era compatible con PHP 5.3.x, pero gracias al soporte que me dieron en @kumbiaPHP, pude resolver de manera muy sencilla los errores y en minutos tener a kumbia trabajando perfectamente con PHP5.3.1.

Con sólo cambiar algunos archivos es suficiente, pero yo preferí conectarme vía bazaar al repositorio del proyecto. De esta manera me aseguro de estar al día con los cambios que se hacen en el framework. Bazaar, es una buena herramienta para trabajar con proyectos de forma versionada, recomendaría utilizar esta vía. De todas formas, para el que no le guste esta opción, aquí dejo una copia de la biblioteca, en zip, de sólo descargar y usar.

Resuelto el problema con PHP, todo lo demás se mantiene tal como lo expliqué en entradas anteriores. Recomiendo nuevamente echar una pasada por el wiki, que tiene muy buenos tutoriales.

Antes de ponerme a trabajar en función de conectarme a twitter, postear, recibir tweets, etc, decidí hacer un ejercicio puro en kumbia, concretamente un CRUD, para una base de datos sencilla que utilizaré para almacenar datos de beisbol. Es lo que estaré mostrando en este post, y en varios posts siguientes.

Para no perder la costumbre, he revisado las plantillas que ofrece opendesigns.org, y me he quedado con wide-blue. Igual que he hecho antes, dentro del directorio app/public/css he creado un subdirectorio "wide-blue" para almacenar las hojas de estilo de la plantilla, y en app/public/img he creado también un "wide-blue" para las imágenes.

En la versión que tengo de kumbia, los directorios han sido ligeramente movidos. Ahora, dentro de views, existe un directorio llamado _shared, que contiene los subdirectorios errors, partials, scaffolds y templates, en los cuales almacenaremos nuestros códigos, de la misma forma que hicimos antes.

Dentro de _shared/templates, está la plantilla por defecto: default.phtml, recordemos es la plantilla por defecto para toda nuestra aplicación. En ese directorio podemos todas las plantillas que queramos y utilizarlas cuando sea necesario. Yo, sin embargo, me fui con default.phtml, cuyo contenido sustituí con el código de wide-blue, por supuesto, teniendo en cuenta las modificaciones necesarias para incluir imágenes, css, y el view::Content().

Entre los cambios más recientes de kumbia, está la forma en que se incluyen imágenes, enlaces, elementos de formularios, etc. Por eso, incluyo algunos códigos a continuación.

Para incluir correctamente los archivos css:

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

En donde style.css es la hoja de estilo que se va a incluir, y está ubicada en el subdirectorio app/public/css/wide-blue.

Para incluir imágenes:

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

En el lugar que queramos mostrar el contenido específico, recordemos que debemos incluir:

<?php View::content(); ?>

Para incluir enlaces:

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

Conociendo estos códigos, podemos dejar nuestra plantilla lista para usar. Sobre la marcha iremos descubriendo nuevos elementos. Observe que el botón de búsqueda del banner superior es una imagen, y de momento no se ve. Luego explicaré con detalle el manejo de los formularios, por ahora sólo dejo el código que hay que sustituir por el código del submit-image para que funcione:

<?php
$args
= array('class="hledat"','type="image"');
echo
Form::submitImage('wide-blue/search-button.gif', $args);
?>


La Base de Datos

Supongo que ya tenemos nuestra plantilla funcional (es bueno comprobar que sea así). Ahora voy a explicar algo que no había explicado antes, y es el manejo de la base de datos. Mi base de datos de beisbol, que es con la que trabajaré en este post y en los siguientes, está almacenada en PostgreSQL.

Lo primero que debemos configurar es el archivo databases.ini (ubicado en app/config/) con nuestros datos. Como estamos haciendo pruebas, utilizo la base de datos de "development", que en mi caso dejé así:

[development]
host = localhost
username = beisbol
password = beisbolistico
name = mibeisbol
type = pgsql

Evidentemente el nombre de usuario, password y nombre de la base de datos depende de cada quien. Lo más importante que hay que notar es el tipo de manejador de BD (pgsql).


Manos a la obra

Voy a comenzar con un ejemplo muy muy simple. Una tabla country, donde voy a almacenar nombres de paises, y una abreviatura. Asumo que todo el que lea este artículo, está en capacidad de crear roles en postgres, crear bases de datos y agregar/editar tablas, así que me limito a dejar el código de la tabla country:

CREATE TABLE country
(
id serial NOT NULL,
country_name character varying(128),
country_3166 character varying(16),
CONSTRAINT pk_country PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE country OWNER TO beisboluser;

En country_name guardaremos el nombre del país, en country_id la abreviatura según el estándar ISO 3166 y nuestra clave primaria será id.

Teniendo nuestra tabla lista, necesitamos crear un modelo para manejar esa tabla. Los modelos se almacenan dentro de app/models. Allí crearemos nuestro country.php, cuyo contenido será el siguiente:

<?php
class Country extends ActiveRecord
{
public function
getCountries($page, $ppage=20)
{
return
$this->paginate("page: $page", "per_page: $ppage");
}
}
?>

Nuestra clase contiene sólo una función (getCountries()), que utilizaremos luego para traer los elementos de nuestra tabla country.

Ese es nuestro modelo, ahora vamos a crear nuestro controlador. Ya hemos trabajado con controladores, sin embargo, recuerdo que deben ir en el directorio app/controllers. Así que creamos nuestro country_controller.php allí. NOTA: el "_controller" en el nombre, es obligatorio.

Me he basado en el ejemplo Beta2 CRUD para realizar nuestro controlador. El código es el siguiente:

<?php

Load
::models('country');

class
CountryController extends ApplicationController {


public function
index($page=1)
{
$country = new Country();
$this->listCountries = $country->getCountries($page);
}

public function
create()
{
if(
Input::hasPost('country'))
{
$country = new Country(Input::post('country'));
if(!
$country->save()){
Flash::error('Falló Operación');
}else{
Flash::valid('Operación exitosa');
Input::delete();
}
}
}

public function
edit($id = NULL)
{
$country = new Country();
if(
$id != NULL)
$this->country = $country->find($id);

if(
Input::hasPost('country'))
{

if(!
$country->update(Input::post('country'))){
Flash::error('Falló Operación');
} else {
Flash::valid('Operación exitosa');
return
Router::redirect();
}
}
}

public function
del($id = NULL)
{
if (
$id) {
$country = new Country();
if (!
$country->delete($id)) {
Flash::error('Falló Operación');
}else{
Flash::valid('Operación exitosa');
}
}
return
Router::redirect();
}
}
?>

Bastante sencillo de digerir con una sola ojeada. Hemos incluido una función index() en la que mostraremos todos los países que tengamos en la base de datos, utilizando la función getCountries() del modelo. También hemos incluido funciones de creación, edición y eliminación.

Podemos prestar atención a como utilizamos Input, para manejar la información que nos llega de la capa de Vista (por ejemplo: Input::hasPost, Input::post, etc).

También podemos observar como utilizamos las funciones save(), update() y delete() sobre una instancia de nuestro modelo. Recordemos que uno de los pilares de kumbia es el concepto de Active Record, el cual facilita las operaciones básicas sobre nuestros modelos. Por ello, no fue necesario programar estas funciones, sino que kumbia ya sabe que hacer en cada caso.

En este punto, ya tenemos nuestro modelo y nuestro controlador listo, sólo nos falta crear las vistas. Recordemos que para las vistas debemos crear un subdirectorio con el nombre de nuestro elemento en app/views, y dentro de él, incluiremos un archivo con extensión .phtml por cada acción que queramos realizar.

Lo que vamos a hacer es crear un index, en el que mostraremos una tabla con todos los elementos que se encuentren en nuestra tabla y le incluiremos un enlace a la página de eliminación y edición. Yo trabajé un poco el ejemplo, para obtener un resultado más vistoso. Este el código de nuestro index.phtml:

<div class="content">
<?php echo View::content(); ?>
<h3>Countries</h3>

<?php echo Html::linkAction("create", 'New') ?>

<table>
<col class="first-column" />
<col span="3" />
<col class="last-column" />
<tr class="first-row">
<th>Name</th>
<th>Abbreviation</th>
<th></th>
<th></th>
</tr>
<?php foreach ($listCountries->items as $item) : ?>

<tr>
<td><?php echo $item->country_name ?></td>
<td><?php echo $item->country_3166 ?></td>
<td><?php echo Html::linkAction("edit/$item->id/", 'Edit') ?></td>
<td><?php echo Html::linkAction("del/$item->id/", 'Delete') ?></td>
</tr>

<?php endforeach; ?>
</table>

</div>

El código se explica solo. Para fijar lo explicado al principio, observe como se trabajan los enlaces (pregúntese cómo haría para incluir un enlace a una acción de otra entidad).

Observe el foreach. Lo que está haciendo es recorrer los elementos que se encuentren en el arreglo listCountries, creado en el controlador y por cada uno, escribir una fila de una tabla en HTML. Si vemos el resultado en el navegador, lógicamente veremos sólo el encabezado de nuestra tabla, porque aún no hemos ingresado datos. Es lo que haremos a continuación en nuestro archivo create.phtml:

<div class="content">
<?php View::content(); ?>
<h3>Add Country</h3>

<?php echo Form::open(); ?>

<br>
<label>Name
<?php echo Form::text('country.country_name'); ?></label>

<br>
<label>Abbreviation
<?php echo Form::text('country.country_3166'); ?></label>

<?php echo Form::submit('Add'); ?>

<?php echo Form::close() ?>
</div>

Aquí nos centraremos en el uso de formularios. La manera de marcar el inicio es mediante la función Form::open(). Más adelante, agregamos dos campos de texto mediante Form::text(), luego un botón submit (Form::submit) y finalmente cerramos mediante Form::close().

observe el nombre que le estamos colocando a cada uno de nuestros imputs (country.country_name y country.country_3166). Antes del punto va el nombre de nuestra entidad, y luego del punto, el campo correspondiente en base de datos. De esta manera, kumbia sabrá que hacer cuando invocamos en nuestro controlador la función save().

Con estas dos vistas, nuestra aplicación debe estar funcionando. En la siguiente entrada seguiremos trabajando con formularios, incluiremos otros elementos, incluyendo el submit-image que comentamos al comienzo. Como práctica, el lector puede realizar la vista de edición, tomando como referencia el ejemplo mostrado en Beta 2 CRUD.

Así termino esta entrada, espero que todo haya quedado claro. También a manera de práctica, el lector puede hacer lo que hicimos en este ejemplo con una tabla para guardar canales de TV.

Hasta la próxima!

martes, 12 de octubre de 2010

Break


Me he tomado un break por razones ajenas a mi voluntad, he perdido mi disco duro y con él, la mayor parte de mis proyectos informáticos. Esto incluye lo que venía mostrando en este blog. Utilizaré los tutoriales para ponerme al día otra vez con TuTuitero y al mismo tiempo ir corrigiendo errores y detalles que vaya viendo en el camino.

Volveré pronto.

martes, 31 de agosto de 2010

Feliz día del blog!


Sí, hoy es el día internacional del blog. Es un día especial, en el que no hablaré de cuestiones técnicas, es día de celebración.

El día del blog se celebra cada 31 de agosto, desde el año 2005, y se debe a la similitud de la fecha "3108" y la palabra blog. La ocurrencia se la debemos al blogger israelí Nir Ofir, que por supuesto hoy tiene twitter, y lo pueden seguir por: @nirofir.

Existe un sitio oficial para la celebración de este día: www.blogday.org. En español, podemos visitar www.diadelblog.com.

¿Qué se supone que hagamos los blogueros el día de hoy? Compartir, difundir. La idea es hacer llegar a quienes los leen, los blogs que nosotros leemos y que creemos que todo el mundo debe leer. Pues bien, es lo que haré ahora. Voy a recomendar algunos de los blogs que sigo con mayor atención.



El primer blog que voy a recomendar es uno muy muy famoso, de la gente de hipertextual, se trata de alt1040. Como ellos mismos se definen, son "la guía del geek". Seguro que alguna vez hemos visto alguna de sus entradas. Una redacción simple e impecable, muy agradable de leer.



Mi segunda recomendación va para kirai, otro de los infaltables en mis feeds. Un blog obligado para los amantes de la cultura japonesa. Excelente redacción y grandiosas imágenes.



Recomiendo también a la gran bloggera Yoani Sánchez y su Generación Y. Quienes la leemos (también por twitter: @YoaniSanchez) sabemos todo el esfuerzo que signifca para ella publicar una simple entrada, en un país donde la libertad de expresión básicamente no existe. Valiente mujer que narra día a día su vida en la verdadera Cuba.



Otro imperdible es el blog Google Operating System. Simplemente genial. En un solo blog tenemos todo lo que tenga que ver con la gente de Google. Como ellos mismos lo aclaran, es un blog no oficial, pero siempre actualizado con el mejor contenido.



Por último, recomiendo seguir a Blog de Series. Para los amantes de las series (como yo) es una excelente fuente de información, nos mantienen al día con todo lo que acontece con nuestras series favoritas. Un excelente blog, con información de calidad.


No me queda más que desearles a todos FELIZ DÍA DEL BLOG


martes, 24 de agosto de 2010

Botón oficial de Twitter


Bueno, hoy voy a apartarme un poco de lo que hemos venido haciendo con twitter y kumbia, para hablar acerca de los recientemente lanzados botones oficiales de twitter. Seguramente si estás en esto de twitter y desarrollar aplicaciones para twitter al menos te habrás enterado de su existencia (si no, es momento de que revises tus feeds).

Para qué sirven?

Sirven para compartir enlaces a través de twitter. Digamos que tenemos un blog interesante, con entradas interesantes, que presumimos que nuestros lectores les gustaría compartir con el mundo a través de twitter. Bien, el lector interesado podría copiar la URL, pasarla por un acortador de direcciones, copiar la dirección corta, pegarla en twitter, copiar el título de la página web, pegarlo en twitter, eventualmente añadir algún comentario y finalmente twittear.

Twitter ahora le ahorra a esos lectores todo este proceso, al permitirnos a nosotros colocar un botón, que con sólo presionarlo, twitteará el enlace por el lector. Simple.

Cómo lo coloco en mis páginas web?

Es muy muy simple. Twitter habilitó esta url donde podemos personalizar como queremos que se vea nuestro botón y nos da el código HTML para que lo insertemos en donde queramos. El sitio nos permite personalizar el botón y (opcionalmente) especificar uno o dos usuarios de twitter que recomendamos para seguir (básicamente, en nuestro tweet se verán como un mention 'via').

Es así de sencillo. Una vez colocado el código HTML en nuestra página, cuando un lector lo oprima, se levantará un pop-up donde nos saldrá el texto que se va a twittear (el cual podremos editar) y el botón para enviarlo.


JavaScript?

Sí, el botón trabaja sobre JavaScript, por lo que si lo que queremos es insertarlo en un foro o cualquier plataforma que bloquee scripts, simplemente NO servirá. Qué podemos hacer entonces?

Bueno, fijándonos un poco en como funciona esto, veremos que a la final lo que el pop-up hace una vez presionado el botón de tweet, es redireccionar a una página web. No hace falta ser un genio para darse cuenta esa url a la que redirecciona el pop-up la podemos colocar en un enlace común y silvestre en HTML. El enlace se ve así:

<a href="http://twitter.com/share?url=URL&text=TEXTO&via=BLOG&related=AUTOR">Twittear</a>

En donde:
  • URL es la url que queremos recomendar en el tweet.
  • TEXTO es el texto que queremos que aparezca en el tweet.
  • BLOG es el nombre de usuario del primer twittero que queremos que aparezca recomendado.
  • AUTOR es el nombre de usuario del segundo twittero que queremos que aparezca recomendado.

Sólo hay que tener en cuenta que el TEXTO debe estar codificado, pues es parte de una URL. L gente de alt4040 sugiere este sitio para codificar nuestro texto.

Blogger/Wordpress

Si queremos que el botón aparezca en todas las entradas de nuestro blog, podremos copiar y pegar el código html en todas las entradas. Una forma más inteligente es agregar el código a nuestra plantilla.

Para Blogger, en nuestra plantilla debemos ubicar la clase post-footer y colocar allí el siguiente código (reemplazando BLOG y AUTOR por los correspondientes):

<a expr:href='"http://twitter.com/share?text=" + data:post.title + "&url=" + data:post.url + "&via=BLOG&related=AUTOR"'>Twittear</a>

Para wordpress, debemos ubicar el archivo single.php y allí colocar el siguiente código:

<a href="http://twitter.com/share?url=<?php echo urlencode(the_permalink()); ?>&text=<?php echo urlencode(the_title()); ?>&via=BLOG&related=AUTOR">Twittear</a>

Es todo. Nuestro enlace se verá así:


De más estás decir que si no queremos que se vea un texto, sino un botón, o que se vea con cierta apariencia, podemos hacerlo utilizando HTML como siempre lo hemos usado.


Leído en: alt1040


jueves, 19 de agosto de 2010

Construyendo un sitio con KumbiaPHP (4)


En esta entrada voy a hacer uso de la API de twitter para mostrar en una vista mi Timeline, a manera de práctica y a la vez introducir un par de aspectos de kumbia no tratados hasta el momento.

Voy a seguir utilizando el twitter_controller de la entrada anterior, lo que voy a hacer es agregarle una nueva función que llamaré timeline, y por supuesto, una vista para dicha función.

public function timeline()
{
if (empty(
$_SESSION['oauth_token']) || empty($_SESSION['oauth_token_secret']))
{
return
$this->route_to('controller: oauth', 'action: index');
}
else
{
Load::lib("twitter");
Load::lib("config");
$twitter = new Twitter(CONSUMER_KEY, CONSUMER_SECRET);
$twitter->setOAuthToken($_SESSION['oauth_token']);
$twitter->setOAuthTokenSecret($_SESSION['oauth_token_secret']);

$this->tweets = $twitter->statusesHomeTimeline();
}

}

El código es básicamente el mismo que el de la función update, hasta el punto en el que asignamos los Tokens de Acceso. La diferencia está en que aquí utilizamos la función statusesHomeTimeLine() y su resultado se lo asignamos a una variable denominada tweets. Esta función devolverá un arreglo con los datos de 20 tweets más recientes de nuestro TL. Por tanto, tweets será un arreglo de tamaño 20, en el que cada celda almacena un conjunto de variables con información del respectivo tweet.

¿Cómo saber qué información tengo en cada celda del arreglo? Consultando la API de twitter, en la cual encontramos abundante información sobre cada una de las funciones. En este ejemplo utilizaré algunos de los (muchos) datos que la API nos provee por cada tweet.

No hay más nada que hacer en nuestro controlador, el resto es cuestión de vistas. Creamos el respectivo timeline.phtml dentro del subdirectorio app/views/twitter y comenzamos a trabajar en nuestra vista. En nuestro controlador hemos creado una variable denominada tweets, con el arreglo de los últimos 20 tweets de nuestro TL, pues desde la vista tenemos pleno acceso a esta variable, es así de sencillo como pasamos información desde la capa de controlador hacia la capa de vista.

El resto es cuestión de decidir qué vamos a mostrar y cómo lo vamos a mostrar. En este caso, voy a introducir otro concepto de kumbia: los helpers, que son métodos de ayuda para la capa de Vista, por ejemplo para formatear fechas, insertar widgets, etc. Los helpers se almacen dentro del directorio app/extensions/helpers y tienen extensión .php.

En este caso, parece útil utilizar un helper para formatear un arreglo de tweets, de manera que si luego queremos imprimir un arreglo de tweets en otra vista, mantengamos el mismo formato y además no tengamos que volver a escribir el código. Voy a crear entonces un helper twitterHelper.php, en el cual de momento sólo tendrá una función, la que formatea el arreglo de tweets:

<?php
class twitterHelper
{

public static function
buildTL($tweets)
{
Load::lib("util");

$tabla = "<table>";

foreach(
$tweets as $tweet)
{
$tabla .= "<tr>";

$tabla .= "<td><img src=".$tweet['user']['profile_image_url']." height=48 width=48></td>";

$tweet_formateado = url_to_anchor($tweet['text']);
$tweet_formateado = tag_twitter_accounts($tweet_formateado);

$tabla .= "<td>".$tweet_formateado."</td>";

$tabla .= "</tr>";
}

$tabla .= '</table>';

echo
$tabla;
}
}

?>

Es código php planito, no hay mucho que explicar. Nuestra función recibe el arreglo de tweets, y devuelve la cadena html para insertar el TL formateado. Por cada tweet lo que voy a mostrar es el avatar del usuario y el texto. Repito que la respuesta de la API de twitter trae mucha información, sólo es cuestión de revisarla para ver que vamos a necesitar dependiendo de lo que queramos hacer.

Noten que para darle un poco de vistosidad a los tweets, estoy utilizando un par de funciones que transforman los @user en @user y que transforman las url que se encuentren en el texto en hiperlinks. Estas funciones están definidas en una biblioteca llamada util.php que invoco al principio, y que como ya hemos visto, debemos almacenar en el directorio app/libs. Muestro el contenido de este archivo a continuación:

<?php

// Transforma una url en el codigo HTML del anchor
function url_to_anchor($inputString)
{
$outputString = preg_replace('/(www\.)(\S+)/', 'http://\\1\\2', $inputString);
$outputString = preg_replace('/(\w+:\/\/)(\S+)/', '<a href="\\1\\2" target="_blank">\\1\\2</a>', $outputString);

return
$outputString;
}


// Anchoriza cuentas twitter
function tag_twitter_accounts($inputString)
{
return
preg_replace("/(\@)([a-zA-Z0-9\_]+)/", "@<a href=\"http://twitter.com/\\2\">\\2</a>", $inputString);
}

?>

Ya tenemos nuestro helper listo, ahora lo podremos utilizar en cualquier vista con cualquier arreglo de tweets. Vamos a crear la vista para timeline, para ver cómo se invoca:

<div class="textboxright">
<h2>Mi TL</h2>
<br>
<?php
View
::helpers('twitterHelper');

twitterHelper::buildTL($tweets);
?>

</div>

Como vemos, nuestra vista se simplifica enormemente. La forma de utilizar el helper es simple. Creo que ya ha quedado claro, pero recuerdo que en nuestra vista estamos utilizando la variable $tweets (es el argumento con el que invocamos a nuestro método buildTL()), la cual creamos en la capa de controlador.

Es todo por el momento. Espero que todo haya quedado claro.