Implementación de un carrusel de imágenes con Drupal 6

Julio 21, 2009

Hola en esta ocasión voy a explicar como se implementó un efecto carrusel de imágenes y/o videos para un proyecto en Drupal, lo que se hizo es utilizar el plugin de jquery llamado jscrollable.min.js el cual me da una apariencia de carrusel (elegante), para ello se debe de instalar previamente Drupal, de forma correcta.

Cuando me refiero de forma correcta es saber ubicar donde se van a agregar temas, módulos, files, etc; para ordenarnos desde un principio, luego instalar los módulos necesarios para nuestro site.

Para poder implementar es prerrequisito tener instalado los módulos jquery_update, jquery_plugin para extender los plugins jquery que trae por defecto Drupal, además el CCK y el image upload para la gestión de subida de archivos, y si uno quiere un módulo para miniaturizar imágenes recomiendo Image Api  + Image Cache, y por supuesto pero no necesario un módulo personalizado.

Para más detalle visita este línk donde podrás descargar un ejemplo.


Implementación de un listado de categorías con Drupal 6 usando Taxonomy

Julio 20, 2009

Hola ahora vengo a compartir con ustedes una experiencia que tuve con Drupal para un determinado proyecto, pues bien si no saben que es Drupal en líneas generales le puedo decir que es un CMS + Framework de desarrollo de webs estaticas y dinamicas, para mas información aquí.

Bueno comienzo …. para poder realizar este desarrollo voy a utilizar el modulo Taxonomy del core de Drupal, ayudándome de un módulo personalizado llamado projecto, lo primero que voy hacer es crear vocabularios en la interfaz del administrador de la plataforma previamente instalada.

vocabularios

Ahora comenzamos a crear los términos a los cuales vamos a enlazar a nuestros vocabularios, con los respectivos parentescos.

terminos

Seguidamente nos dirijimos  a nuestro modulo creado y usamos los hooks, para mas informacion aquí; usamos el hook_menu()para crearnos un menu y hook_block para posicionar nuestro listado en un bloque.

Nos creamos una función que se encargará de dibujar (con los estilos que quieras) el listado de cursos, productos, etc.

Y finalmente creamos otra función que imprime el array u objeto (depende), así:

function cies_show_categories() {
// The categories listed
$tree_category = cies_build_categories(); //función que contiene el listado de categorias
$data = ”;
if (!empty($tree_category)) {
foreach ($tree_category as $value) { // lo recorrp
$data .= $value;
}
}
return $data;
}

Espero haber ayudado, gracias y les dejo el link para que puedan acceder a mi presentación.


Subir archivos usando AKelos Framework + validaciones respectivas

Mayo 6, 2009

En este post el objetivo es conocer un poco más sobre este poderoso Framework y todas sus bondades, para ello en esta sección voy a compartir con ustedes como subir archivos al servidor y las validaciones respectivas (tamaño, tipo, extension, etc).

Primero como todos sabemos interactuamos con la vista para cargar el archivo a subir, en formato Akelos:

<p><label for=”screenshot_file”>_{Image}</label><br />
<?= $form_tag_helper->file_field_tag(‘screenshot[file]‘); ?> <i>_{Only accepts JPG, JPEG, PNG or GIF (no animation)}</i>
</p>
<p><label for=”screenshot_title”>_{Image description}</label><br />
<?php  echo $active_record_helper->input(’screenshot’, ‘title’,array(‘maxlength’=>50))?>
</p>

Luego interactúa el controlador primero guardando el nombre del archivo en BD y enviando los datos del archivo en un array a una función dentro del modelo, recojemos los valores POST:

@$fileuploaded = $this->params['screenshot']['file'];
@$this->params['screenshot']['file'] = $this->params['screenshot']['file']['name'];

Enviamos lo datos a la funció setUploadedFile:

$this->Screenshot->setUploadedFile($fileuploaded);

Seteamos la variable para realizar el save() en Akelos:

$this->Screenshot->setAttributes($this->params['screenshot']);

Finalmente ahora el trabajo depende del modelo screenshot.php:

function setUploadedFile($var) {
$this->uploadedfile = $var;
}

Ahora validamos:

function validateOnCreate() {
if ($this->getErrorsOn(‘file’) === false) {
try{
$safe_extension = array(‘png’,'jpeg’,'jpg’,'gif’,'JPG’,'GIF’);  // solo acepta estas extensiones (bueno para imagenes)

if ($this->uploadedfile['error'])
throw new Exception($this->t(‘Error while uploading file!’));

@$path_parts = pathinfo($this->uploadedfile['name']);
if (!empty($path_parts['extension'])) {
if (!in_array($path_parts['extension'],$safe_extension))
throw new Exception($this->t(‘Invalid file type in pictures.’));  // validamos la extension del file
}

} catch (Exception $e) {
$this->addError(‘file’,'<span style=”color:red”>’.$e->getMessage().’</span>’);
}
}
if ($this->hasErrors()) return false;
else return true;
}

Ahora creamos una funcion para parsee el nombre del archivo y lo guarde en el campo file (por ejempo) de la BD:

function beforeCreate(){
@$path_parts = pathinfo($this->uploadedfile['name']);
if (!empty($path_parts['basename'])) {
$name_length = 31 – strlen($path_parts['extension']);
$this->uploadedfile['name'] = AK::randomString($name_length).’.’.$path_parts['extension'];
$this->set(‘file’, $this->uploadedfile['name']);
}
return true;
}

Ahora usamos una función para guardar el file en nuestro servidor.

function afterCreate(){
$root = ‘ruta_path’;
$target_path_root = $root;
AK::make_dir(substr($target_path_root,0,-1)); // crea el directorio si no existe

$target_path = $target_path_root.basename($this->uploadedfile['name']);
move_uploaded_file($this->uploadedfile['tmp_name'], $target_path); // lo copia
return true;
}

Y por últomo una función para elimianr en caso de hacer un destroy():

function beforeDestroy(){
$path = ‘ruta_path’;
@unlink($path.$this->get(‘file’));
return true;
}

Ojo: no cambiar el nombre de las funciones (son propias de Akelos), y si quiero actualizar mi imagen uso en vez de Create -> Update.

Espero que sea de ayuda para aquellos que quieren iniciarse con Akelos, luego explicaré como convertir una imagen a thumbnail.


Instalar Phing y Xinc en Ubuntu

Marzo 22, 2009

Instalar Phing

$ sudo pear channel-discover pear.phing.info

$ sudo pear install phing/phing

Esto debería crear un /var/www/phing dentro del cual se puede editar el build.xml para customisarlo. Un ejemplo de build.xml:

<?xml version=”1.0″?>
<project name=”dokeos186″ default=”clean” basedir=”.”>

<target name=”empty”>
<echo msg=”Cleaning working space…” />
<delete file=”dokeos*.tgz” />
</target>

<target name=”prepare” depends=”empty”>
<echo msg=”Preparing build…” />
<mkdir dir=”./dokeos-1.8.6″ />
</target>

<target name=”copy” depends=”prepare”>
<echo>Copying…</echo>
<copy todir=”./dokeos-1.8.6/”>
<fileset dir=”/var/www/dokeossvn”>
<exclude name=”**/.svn” />
</fileset>
</copy>
<delete file=”**/.svn” />
</target>

<target name=”syntax-check” depends=”copy”>
<phplint>
<fileset dir=”./dokeos-1.8.6″>
<include name=”**/*.php”/>
</fileset>
</phplint>
<!–simpletest printsummary=”true”>
<formatter todir=”reports” type=”plain” />
<fileset dir=”./dokeos-1.8.6/tests”>
<include name=”dummy.test.php” />
</fileset>
</simpletest–>
</target>

<target name=”documentation” depends=”syntax-check”>
<phpdoc title=”Dokeos API” destdir=”doc” output=”HTML:Smarty:PHP”>
<fileset dir=”./dokeos-1.8.6″>
<include name=”**/*.php” />
</fileset>
</phpdoc>
</target>

<target name=”dist” depends=”documentation”>
<echo message=”Creating archive…” />
<tar destfile=”dokeos-1.8.6.tgz” compression=”gzip”>
<fileset dir=”./dokeos-1.8.6″>
<exclude name=”**/*.bak” />
</fileset>
</tar>
</target>

<target name=”clean” depends=”dist”>
<echo msg=”Cleaning up…” />
<delete dir=”./dokeos-1.8.6″ includeemptydirs=”true” verbose=”true” failonerror=”true” />
</target>
</project>

Una vez el proyecto Phing listo (dentro del build.xml), basta lanzar, en línea de comando, un “phing” para iniciar el proceso.

Phing executing in a terminal

Phing executing in a terminal

La documentación (en Inglés) de Phing esta disponible acá: http://phing.info/docs/guide/2.2.0/

Instalar Xinc

Xinc's first screen

Xinc's first screen

$ sudo pear channel-discovery pear.xinc.eu

$ sudo pear install xinc/Xinc

El último comando ejecuta montones de cosas.

La configuración de Xinc en sí se hace dentro de /etc/xinc/conf.d, donde se encuentra un fichero simpleproject.xml que se puede modificar. Sino quiere tener un proyecto “simpleproject” fantasma, entonces mejor mover este fichero de otro lado y hacer una copia ahí, renombrar el archivo y editar sus detalles *antes* de iniciar Xinc por primera vez (después es bastante complicado de quitar este proyecto fantasma).

Al fin de la instalación, es necesario reconfigurar y pasar el virtual host ubicado en /etc/xinc/www.conf dentro de /etc/apache2/sites-available/ y activarlo con

$sudo cp /etc/xinc/www.conf /etc/apache2/sites-available/xinc.host.ext

$ sudo a2ensite xinc.host.ext

$sudo /etc/init.d/apache2 reload

Para tener un resultado interesante en Xinc, es necesario tener unos scripts de prueba en SimpleXML o PHPUnit, y Phing instalado (más sobre las pruebas más tarde).

Para iniciar Xinc:

$ sudo /etc/init.d/xinc start

La documentación (en Inglés) de Xinc esta disponible acá: http://www.xinc.eu/api/documentation/get/file/xinc/latest-successful/Enduser/index.html

Por alguna razón, cuando inicio Xinc ahora, me consume 100% de un CPU de manera continua. Estaré analizando este detalle más tarde…

Para parar Xinc:

$ sudo /etc/init.d/xinc stop


Retornar arrays con NuSOAP

Marzo 22, 2009

Christian escribió un artículo hace unos días sobre la manera de usar NuSOAP para crear un servicio web. El artículo describe en detalles el procedimiento. No obstante, probar de retornar un arreglo es un trabajo bastante complejo en NuSOAP, o por lo menos esta mal documentado. Una excelente referencia (en Inglés) sobre el tema se puede encontrar en el blog de Lyingonthecovers, pero el artículo faltaba (he puesto un comentario ahí) una noción importante que es que NuSOAP debe tener un ‘return’ => ‘xsd:Array’ en su método register() para retornar el formato correcto.

En este artículo, revisaremos como retornar arreglos.

Retornar arreglos simples

Primero, imaginamos, como en el artículo en Inglés de Lyingonthecovers, que queremos hacer un servicio web que retorna, en el caso de Dokeos, detalles sobre un curso.

La función que se encargar de recojer la información se llamará getCourseDetails(), tomará solo un parámetro  tipo string en entrada (para parametros complejos, ver el ejemplo de Christian) y retornará un arreglo del tipo siguiente:

Array(

['code'] => ‘ABC’,

['title'] => ‘English alphabet’,

['url'] => ‘http://www.example.com/ABC’,

['teacher'] => ‘Yannick Warnier’,

['language'] => ‘english’

)

Hemos definido nuestras necesidades, ahora vamos más adelante y registramos el servicio mismo y sus tipos de datos:

$server = new soap_server();

$server->configureWSDL(‘WSCourse’, ‘urn:WSCourse’);

// definimos el tipo complejo (arreglo asociativo, =’struct’) de detalles de curso

$server->wsdl->addComplexType(
‘courseDetails’,
‘complexType’,
’struct’,
‘all’,
”,
array(
‘name’=>’code’  , ‘type’=>’xsd:string’,
‘name’=>’title’  , ‘type’=>’xsd:string’,
‘name’=>’url’    , ‘type’=>’xsd:string’,
‘name’=>’teacher’, ‘type’=>’xsd:string’,
‘name’=>’language’,'type’=>’xsd:string’,
)
);

Por favor apunten que declaramos un tipo, pero no hay ninguna relación, al nivél de esta declaración, entre el tipo y un método. Este tipo podrá ser reutilizado para otros métodos también.

// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’,           // nombre método
array(‘username’ => ‘xsd:string’),            //  parametros entrantes al servicio
array(‘return’ => ‘tns:courseDetails’),     // valor(es) retornado(s)
‘urn:WSCourse’,                                            // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’,         // acción SOAP
‘rpc’,                                                                 // estílo
‘encoded’,                                                       // tipo de uso
‘This service returns a list of courses’    // documentación
);

En este caso, usamos directamente un ’struct’ como valor de retorno. Usamos el marcador ‘tns:’ (probablemente Type NameSpace o algo así) para decir que es un tipo complejo definido por otro lado, y definimos que tipo exactamente queremos usar.

Esto es lo que debería ocurir y, para este caso (no verificado), tal vez funcionaría. Si no funciona, prueben remplazar tns:courseDetails por xsd:Array, simplemente (vemos más abajo casos probados).

En el caso un poco más complejo en que tenga que devolver un arreglo de estos courseDetails, como hago?

Arreglos de arreglos

Una estructura a dos niveles no se puede definir en solo una definición de ComplexType. En sí, se tiene que definir cada nivel como un ComplexType:

$server->wsdl->addComplexType(
‘courseDetails’,
‘complexType’,
’struct’,
‘all’,
”,
array(
‘name’=>’code’  , ‘type’=>’xsd:string’,
‘name’=>’title’  , ‘type’=>’xsd:string’,
‘name’=>’url’    , ‘type’=>’xsd:string’,
‘name’=>’teacher’, ‘type’=>’xsd:string’,
‘name’=>’language’,'type’=>’xsd:string’,
)
);

Nada cambia para esta primera parte. Ahora definimos el arreglo que va a contener estos structs:

$server->wsdl->addComplexType(
‘courseList’,
‘complexType’,
‘array’,
”,
‘SOAP-ENC:Array’,
array(),
array(
array(‘ref’=>’SOAP:ENC:arrayType’,
‘wsdl:arrayType’=>’tns:courseDetails[]‘)
),
‘tns:courseDetails’
);

Bueno, hay mucho que todavía no hemos detallado ahí, pero no es directamente el objetivo de este artículo. Una cosa es importante: esto es la forma de declarar un arreglo (no asociativo, es decir con indices numéricos unicamente) del ComplexType courseDetails.

Una vez que tenemos esto listo, la lógica nos haría pensar que simplemente debería registrar este tipo complejo en mi servicio web:

// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’,           // nombre método
array(‘username’ => ‘xsd:string’),            //  parametros entrantes al servicio
array(‘return’ => ‘tns:courseList’),          // valor(es) retornado(s)
‘urn:WSCourse’,                                            // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’,         // acción SOAP
‘rpc’,                                                                 // estílo
‘encoded’,                                                       // tipo de uso
‘This service returns a list of courses’    // documentación
);

… y ahí es donde perdimos horas buscando. En realidad, parece que hay algo malo ahí, en la forma en que NuSOAP (a lo menos versión de Agosto de 2008) retorna este valor, que es incorrecto. Resulta que el cliente SOAP de PHP5 no entiende el valor retornado. Ni para este arreglo de structs, ni para el struct mismo.

Abandonar la definición de tipos complejos

La solución es de abandonar la idea de definir el tipo de valor retornado, y simplemente usar xsd:Array como valor de retorno:

// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’,           // nombre método
array(‘username’ => ‘xsd:string’),            //  parametros entrantes al servicio
array(‘return’ => ‘xsd:Array’),          // valor(es) retornado(s)
‘urn:WSCourse’,                                            // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’,         // acción SOAP
‘rpc’,                                                                 // estílo
‘encoded’,                                                       // tipo de uso
‘This service returns a list of courses’    // documentación
);

No hay lógica ahí, es cierto, pero a lo menos espero que les ayudarán. Me estoy comunicando con los desarrolladores de NuSOAP para averiguar el tema.


Instalar Kcachegrind en Ubuntu 8.04

Septiembre 17, 2008

Kcachegrind es una aplicación que nos muestra gráficamente el consumo de tiempo y memoria que un proceso php (función, comando) provoca a un servidor Apache. Aqui una manera facil de instalarlo:

En un terminal ejecutar:

sudo apt-get install kcachegrind
sudo apt-get install php5-xdebug

Configurar estos parametros en el php.ini o en la carpeta /etc/apache2/site-available/sitename

php_admin_value xdebug.profiler_enable 1
php_admin_value xdebug.profiler_output_dir /tmp/kcache

Donde /tmp/kcache es la carpeta donde se guardarán los archivos generados, para luego poder verlos con en Aplicaciones->Programación->Kcachegrind

es necesario que la carpeta /tmp/kcache tenga permisos de escritura

sudo chmod 777 -R /tmp/kcache

Estoy suponiendo que tenemos ya instalado el apache2 y php5 correctamente instalados.


Class ‘imagick’ not found

Septiembre 11, 2008

Este articulo explica (en Inglés) como arreglar el problema del paquete Imagick para PHP5 en Ubuntu Feisty. Traducción sigue:

“He probado usar Image Magick con PHP hace poco por una Ubuntu Feisty, y mientras pensaba que tenía el paquete requisito: ‘php5-imagick’ instalado, y actualizé mi php.ini con imagick.so, me seguía dando el error Class ‘Imagick’ not found. Aquí explico como lo arregle finalmente.

La idea es de regresar a la buena y antigua instalación de PECL:

sudo aptitude install make php5-dev php-pear
sudo aptitude remove php5-imagick
sudo aptitude install libmagick9-dev
sudo pecl install imagick
sudo /etc/init.d/apache2 restart

No se olvide poner el imagick.so en su php.ini!
Bueno, esto funcionó para mi. No necesidad para un largo artículo esta vez, pero esto podría ayudar otros teniendo el mismo problema.

Gracias a Kevin para su artículo. Si nos ayudó! Cabe mencionar que el error sigue ocurriendo en una Ubuntu Hardy Heron (8.04).