Archivo de la etiqueta: Programación

Druplicon

Drupal: Migrate

Migrate es genial, a resumidas cuentas te permite importar información desde varias fuentes. Así de simple.
En este post voy tocar dos cosas muy por encima. Qué puede importar y como implementar Migrate (este modulo no importa nada por si mismo)

Primero lo primero:

¿Desde donde te deja importar información?

  • SQL (Cualquier DB que Drupal sea capaz de leer)
  • XML
  • List
  • CSV
  • JSON
  • MSSQL (Microsoft SQL Server)
  • Oracle
  • Multi items

Y esas son las fuentes que provee Migrate, pero cualquier módulo puede añadir nuevas fuentes sin mayor problema. pueden ver en detalle cada una de las clases que implementa los sources en https://drupal.org/node/1006986

¿Que puede crear con la información que importa?

  • Nodos
  • Comentarios
  • Archivos
  • Menus
  • Items de menu
  • Roles
  • Tablas en la DB
  • Terminos
  • Usuarios

Y una vez mas esas son las fuentes que provee Migrate, pero cualquier módulo puede añadir nuevos destinos. por ejemplo algun modulo puede proveer la implementación para crear profiles de Profile2. La información en detalle de cada una de las clases que implementan estos “destinos” la pueden ver en https://drupal.org/node/1006988

Ok ahora vamos a implementar Migrate en un módulo. Para hacerlo no puede ser más fácil. Solo necesitas 2 cosas: un hook y extender de una clase
Nuestro módulo de ejemplo se llama “migrate_posts” que va a copiar todos los posts que hay en mi blog (WordPress) usando como fuente la DB (El source es SQL en este caso)

La onda en la siguiente:
Primero tenemos que crear un archivo migrate_posts.migrate.inc y dentro de él definir el hook_migrate_api() que es el que le da la información necesaria a Migrate sobre nuestra implementación:

<?php
/**
 * Implements hook_migrate_api().
 */
function migrate_posts_migrate_api() {
  $api = array(
    'api' => 2,
    'groups' => array(
      'wordpress' => array(
        'title' => t('Importación de posts desde WordPress'),
      ),
    ),
    'migrations' => array(
      'WPFromDB' => array(
        'class_name' => 'WPMigrationFromDB',
        'group_name' => 'wordpress',
      ),
    ),
  );
  return $api;
}

El HOOK necesita 3 cosas:
Que le digas que API vas a usar (Siempre es la 2 salvo que cuando leas este artículo hayan sacado la versión 3.x del módulo). Que le indiques un grupo y por ultimo que le indiques cual es tu migrator

Desglosemos esto:
Un grupo es simplemente un “tag” donde vas a agrupar todos los migrators que vos créas conveniente. Por ejemplo, si quisieras crear un importador de posts y otro importador a parte para los comentarios, entonces meterías los dos migrators dentro del grupo de “wordpress”.
En “migrations” definimos el nombre máquina de nuestro importador (WPFromDB), el nombre de la clase que va a realizar la acción (WPMigrationFromDB) y el grupo al que pertenece.

Lo último que queda por aclarar es que “migrate_posts.migrate.inc” es la convención que usa Migrate, por lo que no hace falta hacer un require/include en tu .module

Ya hemos terminado con el primer paso, vamos al segundo. La clase de importacion.
Creamos un archivo .inc que es el que va a contener la clase. por ejemplo “posts-migrator-from-db.inc” y en el .info de tu modulo lo agregas (files[] = posts-migrator-from-db.inc)
Y dentro de él ponemos la clase:

<?php
class WPMigrationFromDB extends Migration {
  public function __construct($arguments) {
    parent::__construct($arguments);
    // #############################################
    // Definición del source (desde donde vamos a obtener la información)
    Database::addConnectionInfo('temporal', 'MI_DB', array(
      'driver' => 'mysql',
      'database' => 'MI_DB',
      'username' => 'USUARIO',
      'password' => 'CONTRASEÑA',
      'host' => 'localhost',
    ));
    $query = Database::getConnection('MI_DB', 'temporal')
      ->select('wp_posts', 'posts')
      ->fields('posts', array(
        'id',
        'post_date',
        'post_modified',
        'post_title',
        'post_content',
      ))
      ->condition("post_type", "post", "=")
      ->condition("post_status", "publish", "=");
    $this->source = new MigrateSourceSQL($query);
    // #############################################
    // Definición del destino (lo que se va a crear con los datos conseguidos)
    $this->destination = new MigrateDestinationNode('page');
    // #############################################
    // Indicamos cual es el identificador UNICO de cada elemento que se consiga desde la fuente
    $this->map = new MigrateSQLMap($this->machineName,
      array(
        'id' => array(
          'type' => 'int',
          'unsigned' => TRUE,
          'not null' => TRUE,
        )
      ),
      MigrateDestinationNode::getKeySchema()
    );
    // #############################################
    // Mapeo de los valores del origen y destino
    $this->addFieldMapping('uid')->defaultValue(1);
    $this->addFieldMapping('created', 'post_date');
    $this->addFieldMapping('changed', 'post_modified');
    $this->addFieldMapping('title', 'post_title');
    $this->addFieldMapping('body', 'post_content');
  }
}

No voy a profundizar en la implementación de la clase porque este post es solo para demostrar lo fácil que es implementar Migrate. Ya vendrán post hablando de las clases.

Y básicamente te eso es todo lo que necesitas para implementar Migrate.

Bueno, ahora usamos drush
Limpiamos el cache para que Drupal lea el .info de nuestro módulo y sepa que “posts-migrator-from-db.inc” existe

drush cc all

Registramos nuestro migrator:

drush migrate-register

Revisamos que el migrator se haya registrado:

drush migrate-status

Que deberia devolver:

Group: wordpress  Total  Imported  Unprocessed  Status  Last imported
 WPFromDB          169    0         169          Idle    2013-06-12 17:59:17

Y si todo está ok, podemos importar nuestros posts:

drush migrate-import WPFromDB

Y para deshacer la importación:

drush migrate-rollback WPFromDB

Chau!

CSS & maquetación

Crear selectores dinámicos con scss/sass

Esta característica me encanta. SCSS/SASS (aka SCSS) nos permite crear selectores de forma dinámica.
Esto quiere decir que podemos reutilizar de una forma mucho mas eficiente y elegante nuestras estructuras CSS.

Por ejemplo, imagina que con CSS maquetas un menú que tiene esta estructura:

<div class="menu-principal">
    <ul>
        <li>
            <a href="/home">Inicio</a>
        </li>
    </ul>
</div>
#menu-principal {
    border-bottom: 5px solid #0062A0;
}
#menu-principal ul {
    border-bottom: 2px solid #F5E742;
}
#menu-principal ul li {
    background: none repeat scroll 0 0 #ADFF2F;
}
#menu-principal ul li a {
    color: #8B0000;
}

Ok, el problema con CSS es que reutilizar código imposible, simplemente no existe la encapsulación en el, y de ahí que hayan nacido compiladores CSS como SCSS (SASS).

En nuestro ejemplo vamos a crear una versión de nuestro CSS en SCSS para poder reutilizar las reglas CSS sin importar como se llame el contenedor (en este caso vemos que se llama “menu-principal”):

@mixin dinamico($selector) {
  #{$selector} {
  }
}
@include dinamico("#primary-menu");

Lo que hice acá es un mixin (una funcion) y luego la invoqué.
El resultado será:

#primary-menu {
}

La ventaja es obvia, podemos crear un mixin que genere estructuras comunes de menú (verticales, horizontales) sin importar el nombre del selector, siempre que el markup sea el mismo (ideal para Drupal, WordPress y cualquier programa que tenga un output estándar para sus estructuras HTML).

Hagamos el ejemplo inicial en SCSS:

@mixin menu-vertical($menu-selector) {
  #{$menu-selector} {
    border-bottom: 5px solid #0062A0;
    ul {
      border-bottom: 2px solid #f5e742;
      li {
        background: #adff2f;
        a {
          color: #8b0000;
        }
      }
    }
  }
}
@include menu-vertical("#menu-principal");

Listo, una vez declarado solo hemos usado ‘@include menu-vertical(“#menu-principal”);’ para generar todo el CSS usando “#menu-principal” como selector base, aunque nada nos impide usar ‘@include menu-vertical(“.otro-menu-de-otro-proyecto”);’ para aprovecharlo en otros proyectos.

Chau!

git-logo

Montar un servidor de git

La configuración que vamos a usar para configurar el servidor de git es de las mas básicas y no repara en la configuración de usuarios -cualquier usuario con acceso SSH nos sirve-. Mas bien esta configuración es para montar un servidor que podamos usar en nuestra casa o en un grupo de usuarios de confianza.

SERVIDOR:

Primero lo primero, instalar git y la gui de git (es opcional la gui, pero si estas usando una distro con interfaz gráfica te va a venir bien tenerla).

sudo apt-get install git-core git-gui

Bien, ahora que tenemos git instalado, necesitamos decidir donde vamos a almacenar todos los repositorios que creemos. En mi caso me hice una carpeta llamada git en mi home:

cd /home/capy
mkdir git

Listo, de momento terminamos con el servidor. Vamos al cliente:

CLIENTE:

Mi cliente es un Windows, pero los pasos de la configuración son igualmente validos sobre cualquier linux o mac.

primero te vas a crear una carpeta donde vas a tener tu proyecto., o si ya la tenes partimos de ahí. En mi caso es una pagina web y voy a crear en mi windows la carpeta “ecapy.com

Cuando tengas la carpeta creada o localizada entramos, hacemos clic derecho y seleccionamos del menú contextual “Git Bash”. Con la consola ya abierta vamos a tirar el siguiente comando para indicarle a git que cree un repositorio con estos archivos (los de tu proyecto):

git init && git add * && git commit -m "Primer commit"

Ya tenemos un repositorio de git en nuestro cliente y vamos a copiarlo al servidor en dos pasos.

Paso 1: le decimos a git que haga una copia limpia de nuestro repositorio:

git clone --bare ecapy.com ecapy.com.git

lo anterior habrá creado una carpeta nueva llamada “ecapy.com.git” en nuestro repositorio local.

Paso 2: copiemos nuestro repositorio al servidor:

scp -r ecapy.com.git [email protected]:/home/capy/git/

Hemos terminado con esta parte. Ya podemos borrar la carpeta “ecapy.com.git“.

 

SERVIDOR:

Vamos al servidor que tenemos que configurar un par de cosas mas.

Entramos en la carpeta que copiamos hace un instante y aplicamos un poco de configuración:

cd /home/capy/git/ecapy.com
git config core.sharedrepository 1 && git config receive.denyNonFastforwards true && find objects -type d -exec chmod 02770 {} \;

Volvamos al cliente:

Ya tenes un repositorio remoto que funciona correctamente. ya podes clonarte de el.

 

NOTA 1: la carpeta que usaste en el cliente para crear el repositorio en el servidor no tiene configurado cual es su origin, por lo que deberías lanzar por consola:

git remote add origin [email protected]:/home/capy/git/ecapy.com.git

O simplemente borra esa carpeta y clonate una nueva que ya tiene configurado el origin:

git clone [email protected]:/home/capy/git/ecapy.com.git

 

NOTA 2: Muchísimo cuidado con lo siguiente: después de seguir estas instrucciones vas a ver que estas trabajando en la rama principal de tu repositorio… crea urgente una rama y cámbiate a ella.

Druplicon

Como ver las variables disponibles en una plantilla .tpl.php (PHPTemplate)

Otro de esos TIP que nos vienen sorprendente mente bien :).

Si estas haciendo debug sobre una plantilla y necesitas saber cuales son las variables de las que dispones sobre la misma, te habras dado con el problema de que no se pueden ver. Osea, las variables existen, y si las mandas a imprimir con un echo() seguro que ahi está, pero hasta que no lo haces no podes saber siquiera que existe.

Bueno basta de intro, vamos a un ejemplo rapido y claro:

Si pones esta función en la plantilla que querés investigar, vas a poder ver un array ($variablesDisponibles para este ejemplo) de los nombres de todas las variables de las que dispone (y de sus contenidos también):

$variablesDisponibles = get_defined_vars();

Chau!

Druplicon

Drupal 6: Módulos y templates con acentos, “¿” y “ñ” mal codificados [solución]

Un problema con el que me suelo dar de tanto en tanto son las codificaciones de caracteres. En especial la de acentos, la ñ y el signo de pregunta de apertura (¿).

El problema mas común que me encontré en mis primeros tiempos como desarrollador de módulos de Drupal fue que de tanto en tanto abría un modulo, y este tenia los caracteres especiales hechos pedazos, mal codificados.

Probé con todo tipo de yerbas raras. Desde usar funciones de todo tipo de encoding de PHP hasta cambiar la collation de la DB…

Pero la solución estaba tan al alcance de la mano que me llegue a sentir un autentico boludo cuando me cayeron las fichas: ¡La codificación de los archivos!. Si señor/a, no me había fijado en la codificación de los archivos (*.module, *.php, *.install, *.inc, etc).

Lo único que hay que hacer para que todo funcione como la seda son unas pocas cosas:

Que el archivo esté codificado en UTF-8. Podés saber que codificación tiene abriéndolo con Notepad++ y yendo al menú “Formato” como se ve en la imagen:

Y si ven que no está seteado en “UTF-8 sin BOM” o “UTF-8”, pueden convertirlo a cualquiera de estos formatos en el mismo menú:
(Para nosotros usar “UTF-8 sin BOM” o “UTF-8” nos es indistinto :) )

En el caso de los IDE deben saber que Netbeans y Zend Studio de serie vienen configurados para crear y tratar a los archivos bajo UTF-8, mientras que Eclipse NO.

Entonces, si usas Eclipse solo tenes que tocar un detalle en la configuración general para despreocuparte de este asunto:
Vayan al menú “Window -> preferences” y en el menú de preferencias deben ir a “General -> Workspace”. Cambien la codificación que haya puesta por la de UTF-8 como se ve en la imagen.


Otra cosa mas. Si trabajan con GIT sepan que tampoco codifica los archivos en UTF-8, y se soluciona yendo a sus opciones y cambiándolo.

Con lo anterior podes olvidarte de tener problemas de codificación De hecho podes dejar de usar entidades HTML y demases, y solo con usar t(“áéíóúñ”) que no vas a tener mas problemas.

Lo ultimo que quiero comentar es que si trabajan con mas gente sobre estos módulos, asegurate que todos tengan bien configurado su IDE o editor para evitar que los codifique mal (con solo abrir un archivo UTF-8 con un editor que no esté en ese formato es muy posible que al editarle una letra y guardarlo lo haga pedazos!).

1263055237_start-here-ubuntuoriginal

Cambié los permisos de un directorio y Git me muestra “old mode 100644 new mode 100755″

Me pasó que me cloné de un repo y como no tenía los permisos adecuados fui con sudo y le metí un 777 a todo el repositorio. Que boludo que fui. Por no leer un poco antes de hacer esa perrada, me di con que a la hora de comitear todos los archivos presentaban cambios, puntualmente todos decían:

old mode 100644
new mode 100755

Solucionando el problema:
primero reviertan la situación cambiándole nuevamente los permisos a todos los archivos con:

sudo chmod 644 -R ./mi-proyecto/

En el paso anterior estoy asumiendo que los permisos originales eran 644 para todos lo archivos del proyecto.

Lo segundo es hacer las cosas bien. Para ello basta con cambiar el owner y grupo al directorio:

sudo chown nobody:nogroup mi-proyecto

y listo. Ahora cualquier usuario tiene privilegios sobre este proyecto por lo que no hace falta cambiarle permisos :)

internet-explorer-logo

El botón de Facebook connect Internet Explorer no aparece (Solución)

Justamente ese fue el problema que tuve hoy. Integré Facebook Connect en una pagina que tengo hecha en Drupal y no había forma de hacer que el botoncito de login se vea en Internet Explorer 7 u 8…

Después de un kilo y medio de I+D descubro que resulta ser que es porque IE no sabe que hacer con los tag <fb>, y dicho problema se soluciona de la forma mas tonta del mundo:
Metiendo el siguiente trozo de código en la etiqueta <html>:

xmlns:fb="http://www.facebook.com/2008/fbml"

Y como nota quiero aclarar que no hace falta reemplazar el atributo existente ya que pueden coexistir ambos:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml" xml:lang="es_ES" lang="es_ES">

Y listo. el fukin botoncito ya aparece en IE 7 y 8 (en el 6 ni me gasté en probarlo).

Notas rápidas de strpos() (PHP)

Strpos() devuelve la posición del primer caracter de la palabra que estamos buscando.

Ejemplos:

<?php
//en la posición 0
if ($posicion = strpos("hola mundo", "hola") !== FALSE) {
    echo "Palabra encontrada en la posición $posicion";
}
?>
<?php
//en la posición 9
if ($posicion = strpos("he dicho hola mundo!", "hola") !== FALSE) {
    echo "Palabra encontrada en la posición $posicion";
}
?>

Nunca hay que olvidar de hacer la comparación del resultado con comparaciones estrictas (“===”, “!==”) para evitar falsos positivos o negativos.

PHP

Snippet: Verificar si una fecha está dentro de un rango de fechas en PHP.

La saqué de la documentación de PHP creo recordar, y a alguien le puede ser útil ;)

<?php
/**
 * Verifica que una fecha esté dentro del rango de fechas establecidas
 * @param $start_date fecha de inicio
 * @param $end_date fecha final
 * @param $evaluame fecha a comparar
 * @return true si esta en el rango, false si no lo está
 */
function check_in_range($start_date, $end_date, $evaluame) {
    $start_ts = strtotime($start_date);
    $end_ts = strtotime($end_date);
    $user_ts = strtotime($evaluame);
    return (($user_ts >= $start_ts) && ($user_ts <= $end_ts));
}

Ejemplo de uso:

<?php
$start_date = '2010-06-01';
$end_date = '2010-06-30';
$fecha_a_evaluar = '2010-06-15';
if (check_in_range($start_date, $end_date, $fecha_a_evaluar)) {
    echo "estas en rango";
} else {
    echo "fuera de rango";
}