Monthly Archives: March 2009

Introducción al AJAX con Mootools 1.2.1

Introducción.

De vuelta a Mootools, fue el primero de los frameworks de Javascript que utilicé hace un poco mas de un año.  Después he experimentado un poco mas con Prototype/Scriptaculous y ahora estoy empezando a leer un poco acerca de jQuery.  Sin embargo siempre me ha gustado Mootools y es hora de documentar, tal y como se hizo con Prototype, como se realizan los llamados asíncronos (AJAX) con él.

En este artículo voy a describir las cuatro maneras como es posible realizar llamados con AJAX utilizando MooTools.

  1. El método load de los elementos.
  2. El método Request.HTML.
  3. El objeto Request directamente.
  4. El método Request.JSON.

1. El método load de los elementos.

Este método lo tienen los elementos (componentes) de Mootools.  Es muy útil porque permite actualizar rápidamente cualquier elemento con el contenido HTML retornado por un llamado asíncrono.  A pesar de ser muy fácil de utilizar, carece de las opciones y la flexibilidad de los métodos siguientes, por ejemplo, del paso de parámetros.

Para hacer uso de este método se utiliza la siguiente instrucción.

$('componente').load(urlRemota);

Donde componente es el elemento que se desea actualizar (un div por ejemplo) y urlRemota es el URL que se invoca de manera asíncrona para obtener el código HTML con el que se reemplazará el contenido del elemento.

Para más información acerca de este método consultar la documentación de Request.HTML.

2. El método Request.HTML.

Este método es una facilidad implementada sobre el método analizado a continuación.  Permite obtener el mismo objetivo del método anterior con una mayor flexibilidad.

    var myHTMLRequest = new Request
        .HTML({
            url:       urlRemota,
            update:    'componente',
            method:    'post',
            data:      $('formulario'),
            onRequest: function()
            {
                // Al iniciar la solicitud.
            },
            onComplete: function(html)
            {
                // Al completarse la solicitud.
            },
            onSuccess: function(responseTree, responseElements, responseHTML, responseJavaScript)
            {
                // Si la solicitud se completó exitosamente.
                /*
                   responseTree - (element) The node list of the remote response.
                   responseElements - (array) An array containing all elements of the remote response.
                   responseHTML - (string) The content of the remote response.
                   responseJavaScript - (string) The portion of JavaScript from the remote response.
                */
            },
            onFailure: function(elemento)
            {
                // Si la solicitud se completó con problemas.
            }
        })
        .send();

De manera similar al método anterior, el atributo url define el URL que se invocará para obtener de manera asíncrona el código HTML para actualizar el elemento referenciado por el atributo update.  El atributo method define si se utilizará POST o GET para la invocación del llamado.

El resto de atributos son opcionales.   El atributo data permite especificar variables que van a ser incluídas con el requerimiento.  Pueden especificarse como un query string de la forma "var1=valor1&var2=valor2", como un hash de la forma {"var1": "valor1", "var2": "valor2"} o enviando un formulario por completo de la forma $('id_formulario').

Los atributos onXXX son manejadores de eventos a manera de callbacks y son ejecutados según lo que acontezca durante la solicitud del llamado asíncrono.

  • onRequest: ha sido iniciado el proceso de la solicitud.
  • onComplete: la solicitud ha terminado.
  • onSuccess: la solicitud ya ha terminado y terminó exitosamente.
  • onFailure: la solicitud ya ha terminado y terminó de manera fallida.

Para más información acerca de este método consultar la documentación de Request.HTML.

3. El objeto Request directamente.

Esta es la forma mas flexible de utilizar AJAX con MooTools ya que permite realizar la solicitud y manipular que se desea hacer con el resultado obtenido, ya no necesariamente actualizar un elemento.

    var myRequest = new Request({
        url:    urlRemota,
        method: 'post',
        data:   $('formulario'),
        onRequest: function()
        {
            // Al iniciar la solicitud.
        },
        onComplete: function(html)
        {
            // Al completarse la solicitud.
        },
        onSuccess: function(responseText, responseXML)
        {
            // Si la solicitud se terminó exitosamente.
            /*
                responseText - (string) The returned text from the request.
                responseXML - (mixed) The response XML from the request.
            */
            // Aquí se implementa que hacer con la respuesta del llamado asíncrono
            // cuando el procedimiento fue exitoso.
            /*
                Actualizando manualmente el componente,
                reproduce la funcionalidad de Request.HTML:
                $('componente').set('html', responseText);
            */
        },
        onFailure: function(xhr)
        {
            // Si la solicitud se completó con problemas.
            /*
                xhr - (XMLHttpRequest) The transport instance.
            */
            // Aquí se implementa que hacer con la respuesta del llamado asíncrono
            // cuando el procedimiento fue fallido.
        },
        onCancel: function()
        {
            // La solicitud fue cancelada.
        },
        onException: function(headerName, value)
        {
            // La transmisión de la cabecerá falló.
            /*
                headerName - (string) The name of the failing header.
                value - (string) The value of the failing header.
            */
        }
    }).send();

Se incluyen dos manejadores de eventos adicionales.

  • onCancel: la solicitud ha sido cancelada.
  • onException: la transmisión de la cabecera (header) provocó una excepción.

Se incluyen además, entre otras cosas, la propiedad running que permite verificar si el objeto myRequest se encuentra o no actualmente procesando una solicitud y al método cancel() que permite cancelar la solicitud activa, generando consecuentemente un evento de cancelación (ver onCancel).

Para más información acerca de este método consultar la documentación de Request.

4. El método Request.JSON.

Es una facilidad construída sobre el objeto Request que permite manipular respuestas de llamadas asíncronas en formato JSON (Javascript Object Notation).

    var jsonRequest = new Request.JSON({
        url:    urlRemota,
        method: 'post',
        data:   $('formulario'),
        onRequest: function()
        {
            // Al iniciar la solicitud.
        },
        onComplete: function(responseJSON)
        {
            // Al completarse la solicitud.
        },
        onSuccess: function(responseJSON, responseText)
        {
            // Si la solicitud se terminó exitosamente.
            /*
                responseJSON - (object) The JSON response object from the remote request.
                responseText - (string) The JSON response as string.
            */
            /*
                La información recibida del llamado asíncrono se puede obtener como atributos
                del objeto responseJSON, por ejemplo acceder a responseJSON.nombres
            */
        },
        onFailure: function(xhr)
        {
            // Si la solicitud se completó con problemas.
            /*
                xhr - (XMLHttpRequest) The transport instance.
            */
        }
    }).send();

Para más información acerca de este método consultar la documentación de Request.JSON.

Ejemplo funcional.

La aplicación de ejemplo obtiene información dinámica del servidor de manera asíncrona, para actualizar los campos DIV de la página utilizando cada una de las cuatro técnicas descritas en este artículo.

Para la generación de la información dinámica del lado del servidor se utilizaron dos scripts muy simples desarrollado en PHP, uno de ellos genera una cadena constante junto con la fecha actual y el otro prepara la respuesta JSON a partir de la información recibida.  Además muestra la información recibida a través del POST.  El script ContenidoRemoto.php es utilizado para los métodos 1, 2 y 3 mientras que el script Contenido RemotoJson.php es utilizado para el método 4.

Para consultar el ejemplo funcionando en el servidor de demostración se debe seguir este enlace.

Para consultar el código fuente de cada uno de los archivos que componen el ejemplo se deben seguir los enlaces dispuestos a continuación: index.php, ContenidoRemoto.php y ContenidoRemotoJson.php.

Enlaces.

Moviendo a mi blog de subdominio

Por ninguna razón aparente, hoy cambié mi blog de dominio.  Hasta esta mañana era http://jorgeivanmeza.com/blog/, ahora es http://blog.jorgeivanmeza.com/.

El procedimiento no fue interesante, simplemente creé el nuevo subdominio y copié los archivos con un cp -rf, sin embargo si me interesa documentar el pequeño cambio que tuve que hacer para conservar la ruta anterior y no romper enlaces antiguos al sitio, especialmente el del RSS.

Es necesario indicarle a Apache que la ubicación antigua ha sido movida a la nueva ubicación.  Para esto agregué la siguiente instrucción al archivo .htaccess ubicado en el directorio raíz correspondiente con el URL http://jorgeivanmeza.com/.

redirect 301 /blog/ http://blog.jorgeivanmeza.com/

El formato de la instrucción redirect es el siguiente.

  • Movido permanentemente: 301.
  • Ubicación antigua: /blog/.
  • Nueva ubicación: http://blog.jorgeivanmeza.com/.

Gracias a esto mis feeds se pueden consultar tanto desde el nuevo sitio: http://blog.jorgeivanmeza.com/feed/ como desde el anterior: http://jorgeivanmeza.com/blog/feed/.

Enlaces.

Actualización de Pidgin para Ubuntu (versión oficial)

Los creadores de Pidgin, el cliente de mensajería instantánea incluído en Ubuntu, han creado un repositorio para la actualización fácil de sus paquetes.  Para instalar los repositorios se deben ejecutar los siguientes comandos desde la línea de comando de un shell.

$ sudo apt-key adv –recv-keys –keyserver keyserver.ubuntu.com 67265eb522bdd6b1c69e66ed7fb8bee0a1f196a8

$ . /etc/lsb-release

$ echo deb http://ppa.launchpad.net/pidgin-developers/ppa/ubuntu \
$DISTRIB_CODENAME main | \
sudo tee /etc/apt/sources.list.d/pidgin-ppa.list

Para buscar e instalar nuevas versiones de Pidgin siga estos pasos.

  1. Abrir el Update Manager: System > Administration > Update Manager.
  2. Presione el botón Check.
  3. Seleccione los paquetes correspondientes a Pigin y LibPurple.
  4. Presione el botón Install Updates para iniciar la actualización.

Enlaces.

Resaltando la sintáxis de códigos en WordPress

Hasta ahora no he encontrado una solución para resaltar la sintáxis de segmentos de código en WordPress.  Hasta la fecha he utilizado varios plugins con resultados parcialmente exitosos.

El primero que probé fue CodeHighlighterPlugin de IdeaThinking.com.  Es simple, resalta la sintáxis de múltiples lenguajes y opcionalmente permite mostrar un número de línea.  Para señalar el código a resaltar se debe encerrar entre etiquetas <pre lang="XXXX" lineno="1">…</pre>.

Después encontré a varios blogs que resaltaban el código de manera mas elegante, con segmentos que coloreaban las líneas y permitían cambiar entre vista enrriquecida y vista plana así como copiar al portapapeles.  Encontré entonces al Google Syntax Highlighter for WordPress de Peter Ryan.  Soporta menos lenguajes (no incluye a bash por ejemplo) sin embargo es mi favorito hasta el momento.  Para segmentar el código a resaltar se debe encerrar entre etiquetas <pre name="code" class="XXXX">…</pre>.

El problema hasta ahora es que TinyMCE, el editor WYSIWYG de WordPress, es felíz borrándome los atributos de los pre convirtiéndo mis fragmentos de código en invisibles para el resaltador haciendo que cada vez que edite o cree un artículo con códigos tenga que editar los textos de manera visual y después tenga que corregir las etiquetas de manera HTML.  Es infame!

Buscando una mejor opción ante este problema encontré el plugin SyntaxHighlighter2 de S H Mohanjith el cual hábilmente utiliza una sintaxis BBCode para segmentar el código a resaltar:  [source language='XXXX']…[/source].

Sin embargo le encontré un problema colateral al plugin: al no utilizar etiquetas pre, el editor/navegador no respetan los espacios en blanco que contenga el código a su izquierda, es decir, se ignora la identación.  El autor muy amablemente me sugirió copiar y pegar los códigos desde el modo HTML sin embargo esto es lo que precisamente quiero evitar.

Anoche, ante la imposibilidad de encontrar una mejor solución y mi testarudez, tuve una idea: utilizar el plugin de Peter Ryan el cual no funciona como quisiera porque el editor le remueve el atributo name y agregárselo de manera dinámica cuando cuando la página se ha desplegado en el cliente.

Hoy me dí manos a la obra y encontré que WordPress utiliza jQuery así que investigué como manipular el evento onLoad, obtener todas las etiquetas pre y como agregarles el atributo name='code' faltante.  El siguiente fue el resultado.

<script type='text/javascript'>
jQuery(document).ready(function() {
    jQuery('pre').each(function () {
         jQuery(this).attr('name', 'code');
    });
});
</script>

Por razones aún desconocidas no pude hacer funcionar el plugin en el onLoad también para que se encolaran los códigos y terminaran ejecutándose secuencialemente cuando el árbol DOM estuviera listo.  Como alternativa modifiqué apropiadamente el archivo fuente del plugin que inserta el script en la página del blog.

En wp-content/plugins/google-syntax-highlighter/google_syntax_highlighter.php agregué las siguientes líneas al final del código.

<script class="javascript">
/* sección de código agregada */
jQuery('pre').each(function () {
        jQuery(this).attr('name', 'code');
});
/* código ya existente en el archivo */
dp.SyntaxHighlighter.ClipboardSwf = '<?php echo $current_path; ?>Scripts/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('code');
</script>

Aún tengo que utilizar el módo HTML o utilizar el botón Insert/Edit Attributes de TinyMCE para indicarle a las etiquetas pre cual es el lenguaje de su contenido (class), sin embargo ya no tengo que preocuparme por el atributo name ni porque este sea borrado cada vez que edite al artículo.

Enlaces.

Humor de madrugada – 20090320

sorpresa_celestial

getreal

Actualizar mi Twitter desde línea de comando

Instalar Curl.

$ sudo apt-get install curl

Actualizar el estado actual.

$ curl http://twitter.com/statuses/update.xml -u jimezam:********* -d status="Updating my Twitter from command line."

El formato es del comando es el siguiente.

$ curl http://twitter.com/statuses/update.FORMATO -u USUARIO:CONTRASEÑA -d status="ESTADO"

    • El FORMATO hace referencia al tipo de resupuesta enviada de regreso por el servidor, puede ser xml o json.
    • El USUARIO y la CONTRASEÑA corresponden al servicio de Twitter.
    • El ESTADO es el mensaje que se desea actualizar en el post.

La respuesta recibida.

<?xml version="1.0" encoding="UTF-8"?>
<status>
<created_at>Thu Mar 19 18:19:09 +0000 2009</created_at>
<id>1355830378</id>
<text>Updating my Twitter from command line.</text>
<source>web</source>
<truncated>false</truncated>
<in_reply_to_status_id></in_reply_to_status_id>
<in_reply_to_user_id></in_reply_to_user_id>
<favorited>false</favorited>
<in_reply_to_screen_name></in_reply_to_screen_name>
<user>
<id>14373210</id>
<name>Jorge I. Meza</name>
<screen_name>jimezam</screen_name>
<location>Manizales</location>
<description></description>
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/55581776/Avatar3_normal.jpg</profile_image_url>
<url>http://www.jorgeivanmeza.com</url>
<protected>false</protected>
<followers_count>4</followers_count>
</user>
</status>

El resultado obtenido.

screenshot1

Introducción al MVC de CodeIgniter – Parte I

Controladores.

  • Actúa como intermediario entre el requerimiento del usuario y, los modelos, las vistas y otros recursos que generan su respuesta.
  • Su clase base es Controller.
  • Su identificador empieza con minúsculas: user.
  • El nombre de su clase empieza con mayúsculas: User.
  • El nombre de archivo coincide con el identificador y la extensión .php.
  • Se almacenan bajo application/controllers.  Es posible agrupar controladores en subdirectorios, estas rutas se deberán ver reflejadas en el requerimiento del usuario.
  • Si se define un constructor para el controlador: __construct para PHP5, su primera instrucción deberá ser invocar al constructor padre: parent::Controller().
  • Las acciones (o funciones) corresponden con los métodos del controlador y es allí donde se implementa su lógica.
  • Los nombres de las acciones comienzan con minúsculas.
  • Las acciones pueden recibir información adicional del requerimiento de usuario a través de sus parámetros.
  • El controlador por defecto es welcome, esto personalizarse modificando el valor de $route['default_controller'] en application/config/routes.php.
  • La acción por defecto es index.
  • Los controladores y las acciones por defecto son utilizadas si el usuario no las referencia explícitamente en su requerimiento.
  • Para definir métodos privados en el controlador que no serán tomados en cuenta como acciones, deberán declararse como private o protected (PHP5) y su nombre deberá empezar por un guión-bajo (PHP 4 y 5).
  • Es posible personalizar la manipulación de las acciones de un controlador sobreescribiendo el método _remap($method) del último.  No es frecuente hacerlo.
  • Es posible manipular, como postprocesar, la información que va a ser enviada de regreso al usuario desde un controlador sobreescribiendo su método _output($output).  No es frecuente hacerlo.

[source='php']
// Archivo application/controllers/user.php

class User extends Controller
{
public function __construct()
{
parent::Controller();
// Constructor del controlador.
}

public function index()
{
// Acción por defecto.
}

public function changeName($firstName, $lastName)
{
// Acción con parámetros enviados desde el requerimiento.
}

private function _myInternalMethod()
{
// Método privado no acción.
}
}
[/source]

Vistas.

  • Se encarga de preparar y organizar la información resultante que será presentada al usuario como respuesta a su requerimiento.
  • Son archivos con contenido XHTML y PHP.
  • No son invocados directamente, son utilizados por los controladores.
  • El nombre de su identificador puede ser arbitrario.
  • El nombre del archivo será su identificador junto con la extensión .php.
  • Se almacenan bajo application/views.  Es posible agrupar vistas en subdirectorios, estas rutas se deberán ver reflejadas en su llamado desde el controlador.
  • Para cargar una vista desde el controlador: $this -> load -> view('ruta/archivo').  La extensión de la vista puede omitirse si se utilizó la extensión por defecto.
  • Este método envía inmediatamente el contenido de la vista procesada al usuario.
  • Es posible enviar información desde el controlador hacia la vista modificando su carga: $this -> load -> view('ruta/archivo', $data).
  • $data puede ser un arreglo relacional o un objeto.  En el primer caso, las celdas del arreglo se convierten en variables de la vista siendo el índice de cada celda el nombre y el contenido su correspondiente valor de la variable.  De igual manera ocurre en el segundo caso, convirtiéndose en variables de la vista a los atributos del objeto.
  • Es posible cargar una vista y almacenarla en una variable para su posterior uso en lugar de enviarla directamente al usuario: $myView = $this -> load -> view('ruta/archivo', $data, true).

[source='php']
// Archivo application/controllers/user.php

class User extends Controller
{
public function index()
{
$data['title'] = "System Administration";
$data['suibtitle'] = "User management";

$this -> load -> view('user/index', $data);
}
}

// Archivo application/views/user/index.php



< ?php echo $subtitle; ?>


[/source]

Modelos.

  • Representan a la lógica del negocio y la información del sistema.
  • Su clase base es Model.
  • Su identificador empieza con minúsculas: user.
  • El nombre de su clase corresponde con el identificador empezando con mayúsculas y terminando con el postfijo _model: User_model.
  • El nombre de archivo coincide con el nombre de la clase en minúsculas y la extensión .php: user_model.php.
  • Se almacenan bajo application/models.  Es posible agrupar modelos en subdirectorios, estas rutas se deberán ver reflejadas en el momento de invocarlos.
  • Si se define un constructor para el modelo: __construct para PHP5, su primera instrucción deberá ser invocar al constructor padre: parent::Model().
  • Para cargar un modelo desde el controlador: $this -> load -> model('ruta/Nombre_modelo').  Esto comúnmente se realiza en el constructor de la clase que lo utiliza para garantizar su uso a todo su largo.
  • Después de cargado el modelo puede utilizarse de la siguiente manera: $this -> Nombre_modelo -> método().
  • Es posible especificar el nombre del objeto donde se cargan los modelos: $this -> load -> model('ruta/Nombre_modelo', 'otroNombre'), esto permite acceder a él de la siguiente manera: $this -> otroNombre -> método().
  • Un tercer parámetro enviado durante la carga de un modelo le permite a este autoconectarse a la base de datos del sistema: $this -> load -> model('ruta/Nombre_modelo', ", true).
  • Es posible indicarle al framework que cargue automáticamente una lista de modelos al listarlos en el arreglo $autoload['model'] de application/config/autoload.php.

[source='php']
// Archivo application/controllers/user.php

class User extends Controller
{
function __construct()
{
parent::Controller();
$this -> load -> model('admin/user');
}

public function index()
{
$data['info'] = $this -> User -> miMetodo();

$this -> load -> view('user/index', $data);
}
}

// Archivo application/models/admin/user.php

class User_model extends Model
{
function __construct()
{
parent::Model();
}

public function miMetodo()
{
// Implementación de la lógica del negocio
}
}

[/source]

Requerimiento del usuario.

  • El requerimiento del usuario incluye la información que encapsula su solicitud, así como todos los datos requeridos interpretarla.
  • La información proviene desde dos fuentes: el URL (dirección) y el contenido POST (formularios).
  • El URL por defecto sigue este formato: server.com/index.php/controller/action/data1/data2.  Cada parte del URL es conocida como un segmento.  Los segmentos controller y action corresponden con los identificadores del controlador y de la acción, incluyendo las rutas adicionales si se utilizaron, que son requeridos por el usuario.
  • Los segmentos adicionales (data1 y data2) son pasados a la acción como parámetros del método.
  • La información enviada a través de variables POST, como es el caso de los formularios, es recibida a través de la clase Input de la seiguiente manera: $this -> input -> post('nombreVariable', true).  El segundo parámetro (booleano) indica si la variable debe ser o no pasada por el filtro XSS de contenido antes de ser accedida.

Enlaces.

Instalación de CodeIgniter 1.7.x en Linux

Introducción.

CodeIgniter es un framework muy interesante para el desarrollo de aplicaciones web.  Lo he estado utilizando por dos años y ha sido muy útil.  Su curva de aprendizaje no es muy pronunciada lo que ha facilitado que desarrolladores no muy experimentados lo aprendan a usar rapidamente.  Su misión es la de proveer una base para el desarrollo de aplicaciones web con PHP brindándonos una serie de herramientas y estructuras facilitadoras que, gracias a su arquitectura desacoplada, no son obligatorias ni restringen el uso de facilidades de terceros.  Es un framework general, es útil y flexible, y no es el mas complejo o restrictivo del mercado.

Ventajas tiene muchas, algunas de las cuales ya he mencionado: fácil aprendizaje, flexible, desacoplado, buen desempeño en términos de tiempo de ejecución y consumo de memoria, muy utilizado y bien documentado.  En pocas palabras, utilizar CodeIgniter le permitirá desarrollar PHP de la misma forma como lo realizaba anteriormente pero de una manera mas estructurada y con algunas herramientas que le permitirán agilizar su implementación.

Como desventajas se encuentra el hecho de que su desarrollo recaiga sobre un sólo hombre, Derek Allard, haciendo que su proceso de actualización fuera lento en comparación con los deseos de la comunidad; sin embargo he estado leyendo un poco acerca de que ahora es un grupo de personas quienes lideran el desarrollo del framawork motivo por el cual me imagino que esto ha cambiado.  Una desventaja muy mencionada es su empeño por seguir soportando PHP4 además de PHP5 impidiéndole tomar ventaja de las mejoras que trajo el lenguaje en su última versión.  Otro punto en contra de CodeIgniter es que podría mejorarse su orientación a objetos en varios aspectos (probablemente producido por lo mencionado anteriormente), por ejemplo, los ayudantes (helpers) son en realidad una librería de funciones.

Por estos motivos un subconjunto de sus seguidores decidió hacer un fork del proyecto para implementar su propias mejoras.  Este fue el nacimiento de Kohana.  Con este nuevo framework estoy desarrollando un proyecto desde hace unos seis meses y su implementación ha sido muy placentera, aunque no se si por las mejoras en el framework o por lo la calidad y lo interesante del proyecto.  Sobra decir que la migración de CodeIgniter a Kohana es un proceso indoloro.  Pero no todo es color de rosa, actualmente la principal ventaja de Kohana es su propio punto débil: su comunidad activa y ávida de mejoras realiza modificaciones al framework frecuentemente haciendo que, según leo en los foros, la próxima versión que saldrá en el presente año no será compatible con versiones anteriores, haciendo que en este momento no sea idónea para desarrollar proyectos a largo plazo.  CodeIgniter por su parte a probado ser bastante estable y a documentar los cambios necesarios para actualizar sus versiones, que de paso no sobra decirlo, siempre es conveniente mantenerse al día con la última versión disponible.

Obtención del framework.

El objetivo de este paso es el de obtener los archivos de la distribución mas reciente de CodeIgniter que se va a instalar.

$ cd /home/www

$ wget http://codeigniter.com/download.php

Instalación del framework en una ubicación privada.

Como se mencionó, el framework se instalará en una ubicación privada y podrá ser compartido por múltiples aplicaciones.  Se crea un enlace dinámico (current) para facilitar la actualización de versiones del framework.

$ unzip CodeIgniter_1.7.1.zip

$ rm CodeIgniter_1.7.1.zip

$ mkdir codeigniter

$ mv CodeIgniter_1.7.1 codeigniter/1.7.1

$ cd codeigniter

$ ln -s 1.7.1/ current

Creación de una aplicación de prueba.

Esta aplicación de prueba deberá mostrar al usuario el controlador (welcome) y la vista (welcome_message) que trae por defecto CodeIgniter.

$ cd /home/www

$ mkdir public/Demo1

$ cp -rf codeigniter/current/system/application/* public/Demo1

$ cp codeigniter/current/index.php public/Demo1

$ rm public/Demo1/index.html

Configuración del controlador frontal de la nueva aplicación.

Es necesario indicarle al controlador frontal de la aplicación donde encontrar a la distribución del framework (system) y donde encontrar los archivos de la aplicación (application).

$ vi public/Demo1/index.php

error_reporting(E_ALL);

$system_folder = "/home/www/codeigniter/current/system";

$application_folder = "/home/www/public/Demo1";

Verificación del funcionamiento inicial del sitio.

Si los pasos anteriores fueron exitosos, si se consulta el sitio web deberá obtenerse un página similar a la siguiente.  Téngase en cuenta que deberá reemplazarse el nombre del servidor (localhost) por el que sea necesario si este no se encuentra en su mismo equipo.

Visitar con un navegador web la siguiente dirección.

http://localhost/Demo1/

Enlaces.

Acerca de los campos IDENTITY en MSSQL

Como insertar un registro con un valor arbitrario en un campo IDENTITY.

Desactivar la revisión de los campos IDENTITY.

SET IDENTITY_INSERT MiTabla ON

Realizar la inserción con valores explícitos.

INSERT INTO MiTabla (llave, campos) values (5, 'Otros valores')

Activar nuevamente la revisión de los campos IDENTITY.

SET IDENTITY_INSERT MiTabla OFF

Como modificar el valor de secuencia de un campo IDENTITY.

dbcc CHECKIDENT(MiTabla, Reseed, valor)

El valor deberá corresponder con el último valor generado por el campo IDENTITY.  Es decir, si se desea que el próximo valor generado sea 10, deberá invocarse la sentencia con 9.

Como desactivar un índice.

ALTER INDEX MiIndice ON MiTabla DISABLE

– Sentencias SQL que requieren del índice desactivado.

ALTER INDEX MiIndice ON MiTabla REBUILD

Como desactivar un trigger.

ALTER TABLE MiTabla DISABLE TRIGGER MiTrigger

– Sentencias SQL que requieren del trigger desactivado.

ALTER TABLE MiTabla ENABLE TRIGGER MiTrigger

Enlaces.

Búsquedas en Google Search desde PHP

Introducción.

Anoche se me ocurrieron algunos experimentos para hacer pero con varios de ellos terminé concluyendo que necesitaba hacer algunas búsquedas a través de Google Search para verificar si mis hipótesis se podían implementar o no.  Pensé que iba a ser muy fácil encontrar ejemplos de esto en PHP, sin embargo sólo pude encontrar un documento realmente interesante al respecto.  Resulta que casi toda la documentación hace referencia a Javascript en AJAX, mientras que los lenguajes no-Javascript como PHP o Flash deben hacerlo a través de REST.  Al final, mis ideas no resultaron; al parecer Google no genera la información que yo necesitaba en formato Google Search, tampoco en XML válido.  Sin embargo aprendí como utilizar Google Search desde PHP y terminé escribiendo una clase muy sencilla para encapsular su uso y una demostración de la misma.

Demostración.

Demostración de GoogleSearch 0.1

Demostración de GoogleSearch 0.1

GoogleSearch.class.php.

De manera muy general estos son los pasos que se deben realizar para ejecutar una búsqueda en GoogleSearch.

Crear una instancia de la clase GoogleSearch.

    $gs = new GoogleSearch();

Establecer la configuración de la búsqueda.

    $gs -> setKey('SU_PROPIA_LLAVE');
    $gs -> setSize('large');
    $gs -> setLang('es');
    $gs -> setReferrer('http://localhost');
    $registro = (isset($_GET['registro'])) ? filter_input(INPUT_GET, 'registro', FILTER_SANITIZE_SPECIAL_CHARS) : 0;
    $palabrasClave = (isset($_GET['palabrasClave'])) ? filter_input(INPUT_GET, 'palabrasClave', FILTER_SANITIZE_SPECIAL_CHARS) : '';

Solicitar la búsqueda.

    $gs -> fetch($palabrasClave, $registro);

Verificar si hubo éxito en la búsqueda.

    if($gs != null && $gs -> getResponseField('responseStatus') == 200) { ... }

Recorrer los registros obtenidos y mostrar su información.

                $length = $gs -> getResultsCount();
                for($i=0; $i<$length; $i++):
                    // Obtiene el iésimo resultado.
                    $result = $gs -> getResult($i);
                    // Muestra su información.
                ?>
                    <tr>
                        <td>
                            <a href='<?= GoogleSearch::getResultField($result, 'url'); ?>'>
                                <?= GoogleSearch::getResultField($result, 'title'); ?>
                            </a>
                            &nbsp;
                            <a href='<?= GoogleSearch::getResultField($result, 'url'); ?>' target='_blank'>
                                [<span style='font-size: 10px;'>Nueva ventana</span>]
                            </a>
                        </td>
                    </tr>
                    <tr>
                        <td class='campo_contenido'>
                            <?= GoogleSearch::getResultField($result, 'content'); ?>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='verde'><?= GoogleSearch::getResultField($result, 'visibleUrl'); ?></span> -
                            <a href='<?= GoogleSearch::getResultField($result, 'cacheUrl'); ?>'>En caché</a>
                        </td>
                    </tr>
                    <tr>
                        <td>&nbsp;</td>
                    </tr>
                <?php endfor; ?>

Enlaces.