druplicon

Instalar y configurar xhprof para que funcione en Drupal.

El modulo Devel nos proporciona una buena forma de integrar xhprof en nuestra instalación de drupal, y vamos a aprovecharla.

Xhprof para quien no lo conozca aun, es un profiler. Principalmente nos permite saber de forma detallada cuanta ram, cpu y tiempo han consumido cada una de las funciones que se utilizan en un request.
De esta forma podemos centrarnos en las funciones mas conflictivas y resolver sus cuellos de botella.

Si se van a la configuración de Devel podemos ver que la opción esta deshabilitada

Y es solo porque no tenemos xhprof  instalado, asi que manos a la obra:

NOTA: Los pasos de instalación los hice en D7 sobre Ubuntu, pero son compatibles con cualquier *nix siempre que se adapten las rutas de las carpetas a las que utilicé el SO sobre el que quieras instalarlo.

Primero instalemos xhprof desde su código fuente. con la consola en mano te vas a tu home (por decir algún lado) y lanzamos:

wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar xvf xhprof-0.9.2.tgz
cd ./xhprof-0.9.2/extension/
phpize
./configure --with-php-config=/usr/bin/php-config
make
make install

Configuremos PHP para que use xhprof:

nano /etc/php5/conf.d/xhprof.ini

Y pegar esto dentro:

extension=xhprof.so
xhprof.output_dir="/var/tmp/xhprof"

Listo, ya tenemos instalado xhprof.
Ahora creemos el directorio en el que se van a generar los dump (cada request genera un archivo de dump con toda la informacion registrada):

mkdir -p /var/tmp/xhprof
chown www-data. /var/tmp/xhprof

Bien, ahora dentro de la carpeta que contiene el codigo fuente que usamos hace un momento para hacer la instalacion, tenemos que copiar las carpetas “xhprof_html” y “xhprof_lib” en “/usr/share/php/“:

cp -Pr xhprof_html/* /usr/share/php/xhprof_html/
cp -Pr xhprof_lib/* /usr/share/php/xhprof_lib/

Xhprof genera graficos que son de mucha ayuda a la hora de identificar cuellos de botella y para crearlos utiliza las capacidades del programa graphviz. si no lo tenés instalado poder hacerlo lanzando:

apt-get install graphviz

Ok terminamos con la configuracion de xhprof. configuremos el resto del entorno para que pueda hacer uso de el.
Lo siguiente es crear un vhost para poder acceder a la informacion que genere xhprof:

nano /etc/apache2/sites-available/xhprof

Y pegas esto:

<virtualhost localhost:9999>
   DocumentRoot /usr/share/php/xhprof_html
   DirectoryIndex index.php
   <directory /usr/share/php/xhprof_html>
     AllowOverRide all
     Options FollowSymLinks
   </directory>
</virtualhost>

Nuestro vhost corre en el puerto 9999 asi que tenemos que agregarlo a apache:

nano /etc/apache2/ports.conf

debajo de “Listen 80” agrega:

Listen 9999

Estamos por teninar. Habilita el vhost que hemos creado con el comando “a2ensite xhprof“, reinicia apache con “service apache2 restart” y en nuestra instalación de Drupal 7 vayamos a “admin/config/development/devel” para configurarlo:

Ahora ves que ya podes marcar la opcion “Enable profiling of all page views and drush requests.


Cuando la marques vas a tener que rellenar:
xhprof directory:” ponele “/usr/share/php” (sin comillas)
XHProf URL:” ponele “http://localhost:9999” (sin comillas)

Y listo. ya lo tenes integrado en drupal. si miras en la parte inferior izquierda de cualquier pagina de la instalacion de tu drupal vas a ver que aparece un link llamado “XHProf output que te va a llevar a la pagina informativa del perfilado que se hiso.

 

 

Bonus!:

Nota: solo por cuestiones de mantenimiento te comento que los dump que genera xhprof en la carpeta “/var/tmp/xhprof” tienden a comerse el disco en cuestion de dias. la solucion que uso es lanzar un cron que limpia todos los dump que tengan mas de un dia.

El cron es un archivo con permisos de ejecucion y el siguiente contenido

#!/bin/bash
#Elimina todos los perfilados que tengan mas de 1 día
find /var/tmp/xhprof -type f -mtime +1 -exec rm -f {} \;

Guardalo en /etc/cron.daily/xhprof_cleaner.sh y listo.

Una nota final. La configuracion que explique no tiene en cuenta la seguridad. esto quiere decir que no deberias utilizarla en produccion salvo que sepas lo que haces.

PHP

Xampp icuuc46.dll intl

Si habilitan el modulo intl en Xampp puede que les de error al no encontrar la librería ”icuuc46.dll“.  La solución en este caso nos la da Cyn Wong:

  1. Ir a [xampp_path]/php/ y copiar estos tres archivos:
    1. icudt46.dll
    2. icuin46.dll
    3. icuuc46.dll
  2. Pegalos en [xampp_path]/apache/bin y reinicia, y vas a ver como ya no hay problemas.

Chau!

Centrar la burbuja informativa de una localización en un mapa embebido de google maps

Es una tontería pero puede que te ahorre un dolor de cabeza.

Cuando buscas una localización en google maps y te copias el código para embeberlo en un site

 

Al insertar ese código vas a ver que la burbuja informativa está cortada:

Y eso molesta!. La solución es acceder a la configuración del mapa que se va a embeber y centrar el mapa a mano:

 

Y en esa misma ventana ya podes copiar el código que se genera.

 

druplicon

Drupal 7: Obtener el valor del field de una entidad

Como ya sabemos de sobra, en Drupal 7 todo es una entity (aka entidad). Los nodos son entidades, los comentarios son entidades, las taxonomias, los usuarios, todo es una entidad, y las entidades usan fields, y obtener el valor de un field de una entidad programaticamente es algo que no suele estar muy claro.

Hoy vamos a ver dos formas de obtener el valor de un field en una entidad.

Nuestro conejillo de indias: una entidad User que tiene un field llamado “field_apellidos“.

La primer forma de obtener el valor que guarda “field_apellido” es usando la API de drupal directamente:

<?php
$user = user_load(1);
$apellidos = field_get_items('user', $user, 'field_apellidos');
echo $apellidos[0]["value"];
?>

Y en el caso de que sea de múltiples valores:

<?php
$user = user_load(1);
$muchos_apellidos = field_get_items('user', $user, 'field_apellidos');

foreach($muchos_apellidos as $apellido){
    $apellidos[] = $apellido["value"];
}

$apellidos = trim(implode(" ", $apellidos));
?>

La segunda forma es usando Entity API (y para quien no lo conozca créanme que es tan necesario como ctools, views o panels si te dedicas a la programación en Drupal 7):

<?php
$user = user_load(1);
$entidadUsuario = entity_metadata_wrapper('user', $user);
$apellidos = $entidadUsuario->field_apellidos->value();
echo $apellidos;
?>

Y en el caso de que sea de múltiples valores:

<?php
$user = user_load(1);
$muchos_apellidos = $entidadUsuario->field_apellidos->value();
$apellidos = trim(implode(" ", $muchos_apellidos));
?>

Nota final: Solo con hacer user_load() ya tenes disponibles el field_apellidos, pero no es una practica recomendada accederlo directamente.

Chau!

js-icon

Olvídate de Powerpoint y comenza a usar impress.js

La primera vez que vi un slide parecido a impress.js fue en la DrupalCamp del año pasado (2011). En ese caso lo que vi era Prezi.

Tanto impress.js como Prezi son aplicaciones que nos permiten hacer slides pero de una forma mucho mas atractiva haciendo uso de zoom, rotación, perspectiva y alguna que otra cosita mas.

Es solo verlo para entender el potencial de este tipo de herramientas:
En Chrome o Safari abran este link y usen las flechas izquierda y derecha o simplemente la barra espaciadora para avanzar.

A que esta bueno!?

Para poder implementar esta libreria tenemos dos opciones. La fácil y la divertida.

La fácil es usar una app llamada “Impressionist”  que ha desarrollado Harish Sivaramakrishnan y que es la mar de simple. Solo tenes que ir agregando slides y en cada una de ellas vas colocando el texto o imagenes y finalmente podes descargar el slide terminado.

Link: http://hsivaram.com/impressionist/0.1/

La forma divertida: Hagamoslo nosotros :D

Vamos a hacer una implementación bien simple:

<div id="impress">

    <div class="step slide" data-x="1000" data-y="">
        Comenzamos con un tipico y aburrido slide
    </div>

    <div class="step slide" data-x="2000" data-y="">
        Hasta el siguiente mismo tipo de aburrido slide...
    </div>

    <div class="step" data-x="3000" data-y="" data-scale="20">
        Pero la cosa pueda cambiar a mejor cuando hacemos zoom
    </div>

    <div class="step" data-x="4000" data-y="3000" data-rotate="90" data-scale="5">
        <p>O cuando nos desplazamos haciendo giros</p>
    </div>

    <div class="step" data-x="5500" data-y="2100" data-rotate="180" data-scale="10">
        <p>Y si encima aplicamos un buen zoom, podemos obtener cosas muy locas</p>
    </div>

    <div class="step" data-x="9000" data-y="5000" data-scale="1" data-z="-500" data-rotate="190"
         data-rotate-x="" data-rotate-y="0">
        Ah y tambien se puede hacer cosas en 3D
    </div>

    <div class="step" data-x="9000" data-y="5000" data-scale="1" data-z="-3000" data-rotate="190"
         data-rotate-x="" data-rotate-y="90">
        <img src="http://ecapy.com/Archivos/impress.js/logo-capy-morado.png"/>
    </div>

</div>

<script src="impress.js"></script>
<script>impress().init();</script>

Pueden verlo en funcionamiento pinchando acá.

Del código anterior no hay que explicar mucho, pero aclaro que:

  • Los “step” deben estar dentro del id #impress y a su vez este id es obligatorio.
  • Cada step es un div que utiliza propiedades para configurar la posición en la que esta colocado, el tamaño, la rotación, etc. las propiedades disponibles al día de hoy son:
    • data-x, data-y, data-z para el posicionamiento;
    • data-rotate-x, data-rotate-y, data-rotate-z, data-rotate para manipular la rotación.
    • data-scale para el escalado/tamaño.
  • Ya por ultimo solo estamos incluyendo impress.js e inicializandolo.

Chau!

BD

Cómo recuperar la clave root en MySQL [Solución]. A veces pasa :D

Paramos el servidor:

sudo service mysql stop

Arrancamos “mysqld_safe”:

sudo mysqld_safe --skip-grant-tables

Dejamos esa consola con “mysqld_safe” corriendo. Abramos otra consola y hagamos lo siguiente:

sudo mysql -u root

Una vez adentro de mysql tiramos los siguientes comandos:

use mysql;
update user set password=PASSWORD("NUEVACLAVE") where User='root';
flush privileges;
quit

Ahora que hemos vuelto a la consola de linux, paramos mysql:

sudo service mysql stop

El anterior comando va a terminar el proceso “mysqld_safe” que habíamos arrancado en la primer consola, por lo que podemos cerrarla.
Listo, arrancamos mysql normalmente y ya podemos usar la nueva clave.

druplicon

Como hacer formularios multistep (wizard) con Ctools

Chaos tools para muchos no es mas que una dependencia de Panels, Views, Features y muchos otros y fabulosos módulos mas. Pero (Gran pero), Ctools per se es un modulo increíblemente útil para nosotros mismos.

Bueno vamos a lo que vamos. Acá les dejo la idea de lo que vamos a hacer:

Tengo un formulario que necesita recoger tres datos de un usuario, y me parece que es mucha información para pedirla toda junta así que vamos a hacerlo en tres pasos distintos.

Para hacer este wizard vamos a usar un formulario normal pero separado en 3 funciones, y dos de las herramientas (plugins) que tiene Ctools. La primera es obviamente “Wizard” y para la persistencia de los datos entre steps usaremos “object-cache“.

Antes la estructura:

  • Necesitamos hacer un item de menú con hook_menu() que nos lleve a una función que es la que va a manejar la batuta.
  • 3 mini funciones para manejar “object-cache
  • 3 formularios/funciones para declarar el contenido de cada uno de los step.

Hagamos lo:

Primero: el menú y el callback del menú:

<?php
function ctools_multistep_menu() {

  $items['ctools_multistep/example_multistep_form'] = array(
    'title' => 'Ejemplo de un wizard con ctools',
    'page callback' => 'wizard_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

  return $items;
}

function wizard_callback($step = NULL) {
 $form_info = array(
    'id' => 'example_multistep_form',

    'path' => "ctools_multistep/example_multistep_form/%step",
    'return path' => "",

    'show trail' => TRUE,
    'show back' => TRUE,

    'next callback' => 'callback_paso_siguiente',
    'finish callback' => 'callback_paso_final',

    'forms' => array(
      'primer_formulario' => array(
        'form id' => 'primer_formulario',
        'title' => 'Primer paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
      'segundo_formulario' => array(
        'form id' => 'segundo_formulario',
        'title' => 'Segundo paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
      'tercer_formulario' => array(
        'form id' => 'tercer_formulario',
        'title' => 'Tercer paso',
        'include' => drupal_get_path("module", "ctools_multistep") . '/formularios.inc',
      ),
    ),
  );

  global $user;
  $object_id = "ctools_multistep_de_ejemplo_" . $user->uid;

  if (empty($step)) {
    clean_datos($object_id);
    $step = 'primer_formulario';
  }

  $object = get_datos($object_id);

  $form_state = array(
    'object_id' => $object_id,
    'object' => &$object,
  );

  ctools_include('wizard');
  $form = ctools_wizard_multistep_form($form_info, $step, $form_state);
  return drupal_render($form);
}

Como pueden ver, el item de menú no es mas que una URL normal.

Ahora bien. En la función principal podemos ver como definimos inicialmente un array normalito, y es en el en donde definimos las características del wizard:

‘id’ => ‘example_multistep_form’
id (string) es el nombre que va a tener el wizard y es obligatorio poner uno

‘path’ => “ctools_multistep/example_multistep_form/%step”,
path (url) es la URL que definimos en el hook_menu() mas “%step”. y es la URL que va a usar Ctools para ir poniendo el step actual en la arra de direcciones de nuestro navegador.

‘return path’ => “<front>”
return path (url) es la URL a la que queremos enviar al usuario cuando este haya completado el formulario. en mi caso lo quiero mandar a la home

‘show trail’ => TRUE
show trail (bool) indica a wizard que queremos que se muestre el breadcrumb de cada uno de los pasos.

‘show back’ => TRUE
show back (bool) indica si queremos dejar que un usuario vuelva a pantallas anteriores. si está en TRUE muestra el botón con dicho fin.

‘next callback’ => ‘callback_paso_siguiente’
next callback (function name) indica cual es la función que se debe ejecutar cada vez que pasemos de un formulario al siguiente. y es en esta funcion en la que vamos a ir guardando el estado actual del usuario.

‘finish callback’ => ‘callback_paso_final’
finish callback (function name) indica cual es la función que se debe ejecutar una vez que el usuario haya completado el formulario. Aquí es donde vamos a guardar de forma permanente los datos del formulario y a limpiar los datos temporales.

‘forms’ => array(
‘primer_formulario’ => array(
‘form id’ => ‘primer_formulario’,
‘title’ => ‘Primer paso’,
‘include’ => drupal_get_path(“module”, “ctools_multistep”) . ‘/formularios.inc’,
),
‘segundo_formulario’ => array(
‘form id’ => ‘segundo_formulario’,
‘title’ => ‘Segundo paso’,
‘include’ => drupal_get_path(“module”, “ctools_multistep”) . ‘/formularios.inc’,
),
)

Por ultimo en forms (array) indicaremos cuales son los formularios que se van a usar en cada paso, el titulo que van a mostrar en el breadcrumb y si tuviéramos esta función en otro archivo, la ruta en la que se aloja.

Nos quedan dos cosas en el formulario. La primera es definir el nombre del objeto que va a almacenar de forma temporal los datos del usuario, ver si ver si vamos a reiniciar el formulario (en el caso de que el usuario acceda nuevamente al formulario) e inicializar los datos del usuario (ahora lo explico).

<?php
global $user;
$object_id = "ctools_multistep_de_ejemplo_" . $user->uid;

if (empty($step)) {
  clean_datos($object_id);
  $step = 'primer_formulario';
}

  $object = get_datos($object_id);

La segunda cosa que nos queda en esta función es claramente generar el wizard:

<?php
$form_state = array( 'object_id' => $object_id, 'object' => &$object );

ctools_include('wizard');
$form = ctools_wizard_multistep_form($form_info, $step, $form_state);
return drupal_render($form);

mmmbueeeeno, tenemos declarado el formulario, un par de funciones para el avance y finalización y hacemos uso de clean_datos() y get_datos(). pues eso es lo que sigue. definir estas funciones:

set_datos(), get_datos() y clean_datos() no son mas que unos wrappers que guardan recuperan y eliminan la información que el usuario va rellenando:

<?php
function set_datos($id, $object) {
  ctools_include('object-cache');
  ctools_object_cache_set('ctools_multistep', $id, $object);
}

function get_datos($id) {
  ctools_include('object-cache');
  $object = ctools_object_cache_get('ctools_multistep', $id);

  //creamos un objeto vacío para empezar
  if (!$object) {
    $object = new stdClass;
    $object->dia = NULL;
    $object->nombre = "";
    $object->apellido = "";
  }

  return $object;
}

function clean_datos($id) {
  ctools_include('object-cache');
  ctools_object_cache_clear('ctools_multistep', $id);
}

Con las pequeñas funciones de object-cache vamos metiendo la información que el usuario complete cada vez que se le de a “Continuar” dentro del objeto:

<?php
function callback_paso_siguiente(&$form_state) {
  set_datos($form_state['object_id'], $form_state['object']);
}

Y cuando el usuario complete el formulario vamos a usar la función que definimos en “finish callback” para dejarle un mensaje en pantalla al usuario (lo mas lógico seria guardarlos de forma permanente pero esta es una demo XD) y limpiar los datos;

<?php
function callback_paso_final(&$form_state) {
  $obj = $form_state["object"];
  drupal_set_message($obj->nombre . " " . $obj->apellido . " gracias por seleccionar el día " . $obj->dia);
  clean_datos($form_state["object_id"]);
}

Y eso es básicamente todo lo que necesitamos. Faltan como es lógico, las funciones que contienen los formularios junto a su respectivo _validate() y _submit(). Les pongo uno de ejemplo para que vean que no tiene nada del otro mundo:

<?php
function segundo_formulario($form, &$form_state) {
  $form['nombre'] = array(
    '#type' => 'textfield',
    '#title' => t('Dime tu nombre'),
    '#default_value' => $form_state['object']->nombre,
    '#required' => TRUE,
  );

  return $form;
}

function segundo_formulario_validate($form, &$form_state) {
}

function segundo_formulario_submit($form, &$form_state) {
  $form_state['object']->nombre = $form_state['values']['nombre'];
}

Aunque ahora que me doy cuenta, quiero comentar que en el _submit() (que siempre se ejecuta antes que la función datos callback_paso_siguiente() que almacena los datos), es el punto en el que seteamos el valor que el usuario acaba de rellenar en la correspondiente propiedad del objeto que esta por ser almacenado.

Todo lo anterior nos va a generar un formulario como el siguiente:

y cuando el wizard nos mande a la home vamos a ver:

Les dejo un descargable con este wizard de ejemplo para que puedan verlo en detalle.

Descargar

Chau!

tux

Habilitar .bashrc al iniciar sesión

Problema: querés usar .bashrc para poner un alias por ejemplo, pero .bashrc no existe.

Solución: te vas a la home de tu usuario y tipeas lo siguiente:

cd ~
nano .bashrc

Y dentro del archivo pongamos un alias por ejemplo:

alias ll='ls -l'

Guardamos los cambios y pasamos a lo siguiete que es:

nano .bash_profile

Pegamos esta condición para que .bashrc se cargue al iniciar sesión.

if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

All done, ya podes reiniciar la sesión que vas a ver que el alias “ll” funciona sin problemas. ;)

tomcat-logo

Acceder a “manager webapp” en Tomcat 7

Aparentemente a la gente de tomcat se les ha olvidado actualizar la documentacion que muestra en la página index que ofrece por defecto:

Por lo que si las seguís, va a ser imposible que accedas al “manager webapp”. Aprovecho para felicitar a los maestros de Tomcat, que un error así no es nada a comparación del pedazo de soft que nos dan sin pedir ni una moneda :D

Vamos a solucionar este problemita:

Edita el archivo /etc/tomcat7/tomcat-users.xml y agrega estas lineas dentro del tag <tomcat-users></tomcat-users>:

<role rolename="manager-gui"></role>
<user username="miusuario" password="mipassword" roles="manager-gui"></user>

No olvides de poner el usuario y clave que quieras.
Listo, saludos.