jueves, 5 de diciembre de 2013

Symfony 2 avanzado: Ordenando relaciones OneToMany (Doctrine)

En Doctrine, Las relaciones OneToMany son un mecanismo muy potente para acceder a una lista de objetos hijo. El ejemplo más claro de uso de las relaciones OneToMany sería una factura y las líneas de factura o un pedido y el detalle del pedido; y en general cualquier relación maestro-esclavo o padre-hijo en la que la clave foránea se encuentra en la tabla hija.

Así en los proyectos Symfony 2 que usan Doctrine obtener la lista de objetos hijo desde el padre es tan sencillo como acceder a la propiedad del objeto. Internamente Doctrine convierte eso en una query a la base de datos, pero el resultado obtenido por defecto no viene ordenado. Podemos garantizar el orden añadiendo la cláusula OrderBy a la declaración de la propiedad OneToMany, pero esa ordenación es muy limitada. Veamos un ejemplo:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="facturas")
 */
class Factura
{
  /**
   * @var integer
   * 
   * @ORM\Id
   * @ORM\Column(name="id_factura", type="integer", nullable=false)
   */
  private $id;

  /**
   * @var \DateTime
   *
   * @ORM\Column(name="fac_fecha", type="text", nullable=false)
   */
  private $fecha;

  /**
   *
   * @ORM\OneToMany(targetEntity="Lineas", mappedBy="factura", cascade={"all"})
   * @ORM\OrderBy({"id" = "ASC"})
   */
  private $lineas;

  // ...
}

/**
 * @ORM\Entity()
 * @ORM\Table(name="lineas_factura")
 */
class Lineas
{
  /**
   * @var integer
   * 
   * @ORM\Id
   * @ORM\Column(name="id_linea", type="integer", nullable=false)
   */
  private $id;

  /**
   * @var \DateTime
   *
   * @ORM\Column(name="lin_fecha", type="text", nullable=false)
   */
  private $fecha;

  /**
   * @var integer
   * 
   * @ORM\ManyToOne(targetEntity="Factura", inversedBy="lineas")
   * @ORM\JoinColumn(name="id_factura", referencedColumnName="id_factura")
   */
  private $factura;

  /**
   * @var integer
   *
   * @ORM\OneToOne(targetEntity="Producto", cascade={"all"})
   * @ORM\JoinColumn(name="id_producto", referencedColumnName="id_producto")
   */
  private $producto;

  // ...
}

/**
 * @ORM\Entity()
 * @ORM\Table(name="productos")
 */
class Producto
{
  /**
   * @var integer
   * 
   * @ORM\Id
   * @ORM\Column(name="id_producto", type="integer", nullable=false)
   */
  private $id;

  /**
   * @var string
   *
   * @ORM\Column(name="prod_nombre", type="text", nullable=false)
   */
  private $nombre;

  /**
   * @var float
   *
   * @ORM\Column(name="prod_precio", type="float", nullable=false)
   */
  private $precio;

  // ...
}

En este ejemplo la propiedad lineas de la clase Factura tiene una cláusula OrderBy que hace que la lista resultado se obtenga ordenada por id. ¿Pero que ocurriría si quisiéramos que el resultado viniese ordenado por algún dato del producto asociado como el nombre o el precio? ¿No hay forma de hacerlo con Doctrine?

Pues no, no la hay. Pero algo se puede hacer: podríamos ordenar el resultado después de obtenerlo. Al fin y al cabo se trata de un simple array de objetos. ¿Pero como hacerlo para que esté disponible en toda la aplicación y para cualquier tipo de lista? Sencillo: Con un servicio y más concretamente con una extensión Twig.

class MyExtension extends \Twig_Extension
{
  public function getName()
  {
    return 'MyExtension';
  }

  public function getFilters()
  {
    return array(
      'sortCollection' => new \Twig_Filter_Method($this, 'sortCollection'),
    );
  }

  public function sortCollection($collection, $properties) {

    $objects = $collection->getValues();
    if($properties == null) {
      return $objects;
    }

    if(is_string($properties)) {
      $property = $properties;
      $properties = array( );
      $properties[] = $property;
    }

    if(is_array($properties)) {

      usort($objects, function ($a, $b) use ($properties) {

        foreach($properties as $property) {

          $objA = $a;
          $objB = $b;

          if(is_string($property)) {

            $property = explode('.', $property);
            foreach($property as $method) {

              if($objA == null || $objB == null) {
                break;
              }

              $getter = 'get' . $method;

              if(method_exists($objA, $method)) {
                $objA = $objA->$method();
              }
              elseif(method_exists($objA, $getter)) {
                $objA = $objA->$getter();
              }
              else {
                $objA = null;
              }

              if(method_exists($objB, $method)) {
                $objB = $objB->$method();
              }
              elseif(method_exists($objB, $getter)) {
                $objB = $objB->$getter();
              }
              else {
                $objB = null;
              }
            }
          }

          if($objA != null && $objB == null) {
            return -1;
          }
          elseif($objA == null && $objB != null) {
            return 1;
          }
          elseif($objA < $objB) {
            return -1;
          }
          elseif($objA > $objB) {
            return 1;
          }
        }

        return 0;
      });
    }

    return $objects;
  }
}

¿Pero como lo usamos? Pues básicamente en Twig, para obtener una lita de líneas de factura ordenadas por el nombre del producto, haríamos lo siguiente:

<ul>
{% for linea in factura.lineas | sortCollection([ 'producto.nombre' ]) %}
  <li>
    {{ linea.producto.nombre }}
  </li>
{% endfor %}
</ul>

Una extensión Twig, también puede definirse como servicio y por lo tanto, también podríamos ordenar una colección de objetos Doctrine directamente desde el controlador. Por ejemplo podríamos necesitar una lista de líneas de factura ordenadas primero por precio del producto asociado y segundo por el nombre (para productos del mismo precio). Sería como sigue:

$myExtension = $this->get('twig.extension.MyExtension');
$list = $myExtension->sortCollection($factura->getLineas(), array(
  'producto.precio',
  'producto.nombre'
));

jueves, 28 de noviembre de 2013

Crea tu propio repositorio Git usando Gitolite

Git es un software diseñado por Linus Torvalds, el creador de Linux, que sirve para crear repositorios de código fuente permitiendo realizar el control de versiones de cientos de archivos, soportando múltiples usuarios y mantenimiento distribuido. En los proyectos que usan Git cada usuario dispone de una copia local completa del código fuente (repositorio local), incluyendo el historial de cambios, pero a la hora de fusionar cambios es conveniente tener un repositorio central, accesible por todos los usuarios.

En Internet se pueden encontrar sitios como GitHub o Bitbucket que permiten alojar repositorios de código fuente Git. En concreto GitHub se usa sobre todo para proyectos de software libre, pues es gratuito, aunque también tiene planes de pago para proyectos privativos. Por su parte Bitbucket ofrece cuentas gratuitas de hasta 5 usuarios para todo tipo de proyectos y también dispone de planes de pago para proyectos más grandes.

Tanto Github como Bitbucket ofrecen máxima seguridad y privacidad para alojar allí nuestro código fuente, pero si queremos tener un mayor control sobre donde está realmente nuestro código y quien tiene acceso, podemos crear nuestro propio repositorio central de fuentes Git con Gitolite. En realidad hay otras herramientas tanto gratuitas como de pago para crear y mantener repositorios Git, pero Gitolite es bastante sencilla de usar, además de ser de código abierto y gratuita, al igual que el propio Git.


Instalando y configurando Gitolite

Podríamos definir Gitolite como capa de control de acceso para repositorios Git que permite la administración de múltiples repositorios y usuarios indicando en cada caso quién puede hacer qué y dónde. Gitolite crea un usuario llamado gitolite en el servidor que es el que realiza todas las operaciones sobre el repositorio central. La invocación de acciones (clone, push, pull, etc.) se realiza mediante el protocolo ssh, por lo que será necesario que cada usuario disponga de una clave pública. Vamos a verlo todo en detalle.

Supongamos que tenemos un servidor Linux al que llamaremos SERVIDOR y tres usuarios USUARIO1, USUARIO2 y USUARIO3. Necesitamos tener acceso con permisos de root a la consola del SERVIDOR (puede hacerse vía ssh). Lo primero que haremos será instalar y configurar Git si no está ya instalado.

-- Instalación para Debian, Ubuntu, Mint, etc.
$ sudo apt-get install git git-core

-- Instalación para RedHat, Fedora, CentoOS, etc.
$ sudo yum install git git-core

-- Configuración (todos)
$ git config --global user.name "{usuario}"
$ git config --global user.email "{email}"
$ git config --global core.editor "{editor}"

Hay que sustituir {usuario} por el nombre del usuario, {email} por un email válido y {editor} por tu editor preferido (nano, vim, emacs, etc). Una vez configurado Git procederemos a crear una clave RSA para el servidor, ya que la necesitaremos tras instalar Gitolite:

$ ssh-keygen -t rsa -C "{email}"
$ ssh-add ~/.ssh/id_rsa
$ cp ~/.ssh/id_rsa.pub /tmp/administrador.pub

Hay que sustituir {email} por un email válido (generalmente el mismo que se usó en el paso anterior). También hemos copiado la clave pública id_rsa.pub al directorio /tmp con el nombre administrador.pub. A continuación instalamos Gitolite. Hay varias formas de hacerlo.

Esta página explica todas las formas de instalar Gitolite [en inglés]. Yo he elegido la más sencilla: La instalación por paquetes:

-- Instalación para Debian, Ubuntu, Mint, etc.
$ sudo apt-get install gitolite

-- Instalación para RedHat, Fedora, CentoOS, etc.
$ sudo yum install gitolite

-- Configuración de Gitolite (para todos)
$ sudo su - gitolite
$ gl-setup /tmp/administrador.pub

Al ejecutar esta instrucción Gitolite usa el editor por defecto para mostrarnos el archivo de configuración del programa. En cualquier momento podemos volver a editar este archivo de configuración que se llama .gitolite.rc y está en /var/lib/gitolite/. Es conveniente modificar la configuración por defecto poniendo $GL_WILDREPOS = 1; y $REPO_UMASK = 0027;. Esta página explica todo sobre la configuración de .girolite.rc [en inglés]. Una vez finalizada la edición Gitolite habrá dado permisos de administración a la clave pública que creamos anteriormente. También habrá creado varios archivos y carpetas en el usuario gitolite:

  • ~/.gitolite.rc: Archivo de configuración de gitolite.
  • ~/.gitolite/conf/gitolite.conf: Configuración de repositorios.
  • ~/.gitolite/keydir/: Carpeta de claves públicas de los usuarios.
  • ~/.gitolite/keydir/administrador.pub: Clave pública administrador.
  • ~/projects.list: Lista de proyectos.
  • ~/repositories/: Carpeta de repositorios.

Una vez hecho esto podemos salir del usuario gitolite pues hemos acabado con él:

$ exit

La configuración del programa Gitolite está realizada. Ahora veremos como añadir repositorios y como dar permiso a otros usuarios. Esto se hace desde el usuario cuya clave pública hemos indicado que es el administrador. En este caso un usuario de nuestro propio servidor. Gitolite usa un repositorio Git como método de configuración, lo cual nos sirve a la vez como sistema para comprobar que la instalación de Gitolite fue correcta. Así que lo primero que hay que hacer el clonar el repositorio gitolite-admin.git.

$ git clone gitolite@localhost:gitolite-admin.git

Si todo funciona correctamente se habrá creado una carpeta llamada gitolite-admin en la carpeta home de nuestro usuario del servidor. Seguidamente editaremos el archivo ~/gitolite-admin/conf/gitolite.conf que es el que contiene la configuración de repositorios y usuarios. Esta página explica lo necesario sobre la configuración de gitolite.conf [en inglés]. Para añadir un repositorio o un usuario basta con añadir una entrada a ese archivo siguiendo la notación. Por ejemplo:

@developers = usuario1 usuario2 usuario3
repogitolite-admin
RW+=administrador
repotesting
RW+=@all
repomi-proyecto
RW+=@developers

Ya sólo nos queda crear una clave RSA para cada uno de nuestros usuarios y copiar la clave pública a la carpeta ~/gitolite-admin/keydir/ del servidor, poniendo el mismo nombre que le hemos dado a los usuarios en el archivo de configuración. En nuestro caso usuario1.pub, usuario2.pub y usuario3.pub. Por último subiremos los cambios del proyecto usando el propio Git.

$ cd ~/gitolite-admin/
$ git add .
$ git commit -m '{motivo de la modificación}'
$ git push origin master


Copiando un repositorio desde otro servidor

Puede darse el caso de que tengamos nuestro repositorio central en un servidor y queramos moverlo a otro. Este proceso es en realidad es bastante sencillo de realizar: lo primero es instalar Gitolite en el servidor nuevo, tal como se ha explicado anteriormente. Lo siguiente es entrar en el servidor antiguo y seguir los siguientes pasos:

-- Copiamos el repositorio entero del proyecto antiguo
$ cd /var/lib/gitolite/
$ scp -r repositories/mi-proyecto.git/* gitolite@{servidor}:repositories/mi-proyecto.git/

-- Copiamos .gitolite.rc como .gitolite.rc.bak y salimos
$ scp .gitolite.rc gitolite@{servidor}:.gitolite.rc.bak
$ exit

Debes cambiar {servidor} Por la IP o la URL del servidor nuevo. A continuación debemos entrar en el usuario gitolite del servidor nuevo y hacer lo siguiente:

-- Comprobamos las diferencias entre las dos versiones .gitolite.rc
-- y realizamos los cambios que sean necesarios
$ diff .gitolite.rc .gitolite.rc.bak

-- Reconfiguramos gitolite con los nuevos cambios y salimos
$ gl-setup
$ exit

Ya sólo queda abrir el proyecto gitolite-admin, asegurarnos de que mi-proyecto esté en gitolite.conf, asignar los usuarios al proyecto y subir los cambios. Aquí puedes encontrar más información sobre como mover un repositorio Gitolite a otro servidor.

Bunus track: Si queremos desactivar el servidor antiguo para que los usuarios no puedan enviar cambios basta con editar el archivo .gitolite.rc y poner en la primera línea exit 1;.


Referencias

domingo, 20 de octubre de 2013

Arrancando Ubuntu 13.10 desde Grub Rescue

Tras actualizar uno de nuestros PCs a Ubuntu 13.10 Saucy Salamander he visto que quedaba poco espacio en disco y he decidido eliminar el otro sistema operativo que había instalado (que era Windows 7, pero eso da igual). Tras borrar la partición de Windows he intentado hacer más grande la partición de Linux y ahí han empezado los problemas. Para empezar no se puede tocar la partición en uso, así que he arrancado con el Live CD de Ubuntu y lo he intentado de nuevo con GParted...

La partición sobre la que estaba instalado Ubuntu era una partición lógica dentro de una partición extendida y se encontraba al final del disco. Mal asunto. He intentado mover las particiones al principio para hacerlas más grandes pero GParted no me lo ha permitido, así que he hecho una copia de la partición entera, proceso que ha tardado más una hora. He probado de arrancar Ubuntu desde esa partición y todo ha ido bien así que he vuelto arrancar desde el Live CD, he eliminado la partición extendida y he agrandado al máximo la nueva partición.

Todo ha ido aparentemente bien pero al reiniciar el sistema ha salido un error y ha aparecido Grub Rescue que es una especie de intérprete de comandos de Grub que permite reparar una instalación. Entonces me he puesto a investigar en Internet y he encontrado la solución:

  1. Lo primero que hay que hacer es averiguar cual es el disco duro y la partición sobre la que tienes instalado Ubuntu. Eso se hace con el comando ls:
  2. Grub Rescue> ls
    (hd0) (hd0,msdos1) (hd0,msdos2) (hd1) (hd1,msdos2) (hd2,msdos1)
    Grub Rescue> ls (hd0)/
    Error: Unknown filesystem.
    Grub Rescue> ls (hd0,msdos2)/
    Error: Unknown filesystem.
    Grub Rescue> ls (hd0,msdos1)/
    bin/  boot/  cdrom/  dev/  etc/  home/  lib/  lib64/
    media/  mnt/  opc/  proc/  root/  run/  sbin/  selinux/
    srv/  sys/  tmp/  usr/  var/
    

    Se trata de averiguar que partición tiene instalado nuestro Linux. Para ello hay que mirar una a una el contenido de las particiones ls (hdx,y)/ (ojo con la barra final), hasta dar con la adecuada que en mi caso es la (hd0,msdos1)

  3. Una vez sabemos el nombre interno de la partición a iniciar hay que arrancar Ubuntu desde esa partición. Pare ello basta con ejecutar las siguientes instrucciones, cambiando (hd0,msdos1) por el nombre real de la partición:
  4. Grub Rescue> set root=(hd0,msdos1)
    Grub Rescue> set prefix=(hd0,msdos1)/boot/grub
    Grub Rescue> insmod normal
    Grub Rescue> normal
    
  5. Por último una vez arrancado Ubuntu hay que arreglar Grub para que la siguiente vez funcione correctamente. Para ello hay que abrir un terminar y ejecutar las siguientes instrucciones:
  6. $ sudo update-grub2
    $ sudo grub-install /dev/sda
    

    Hay que elegir bien en que dispositivo instalamos Grub: /dev/sda se corresponde con el primer disco duro (hd0) en Grub Rescue. /dev/sdb sería el segundo disco duro (hd1), /dev/sdc sería (hd2), etc.

Y ya está. Con esto debería funcionar. Puedes encontrar más información aquí, aquí y aquí.

jueves, 10 de octubre de 2013

Symfony 2: Primer proyecto

En este segundo capítulo del mini-curso de Symfony 2 explicaré como crear un proyecto Symfony 2 desde cero para entornos Linux. Por supuesto existe la posibilidad de utilizar Symfony 2 en Windows y en Mac OS X, pero yo voy a centrarme en Linux y concretamente en Ubuntu, que es lo que uso habitualmente. La instalación en Mac OS X probablemente sea similar a la de Linux y para Windows seguro que existen otros manuales.

Lo primero y más importante: Vamos a suponer que el usuario dispone de un PC con sistema operativo Linux y que ha instalado tanto el servidor web Apache como el lenguaje PHP. Symfony 2 requiere al menos la versión 5.3.3 de PHP y algunas extensiones específicas. Aquí puede consultar todos los requerimientos de Symfony 2.


Composer

Empezaremos por el principio: Instalando Composer.

Composer es una herramienta imprescindible para desarrollar aplicaciones y sitios web en Symfony 2. Los proyectos Symfony utilizan diversas librerías externas (llamadas dependencias) que a su vez puede que usen otras librerías y Composer es la herramienta que se encarga de mantener actualizadas esas dependencias. Por ejemplo cuando queremos cambiar la versión usada de una librería o del propio Symfony, Composer se encarga de comprobar la compatibilidad de las otras librerías del proyecto, descargando si es necesario las versiones compatibles o avisando de las posibles incompatibilidades. A la hora de crear un proyecto Symfony 2, Composer comprueba la lista de dependencias del proyecto, decide qué librerías hay que instalar, qué versiones concretas se instalan y el orden correcto de instalación. Es una herramienta muy potente.

Para instalar Composer globalmente hay que seguir los siguientes pasos:

  1. Abre una terminal y escribe:
  2. $ curl -s https://getcomposer.org/installer | php
  3. Aparecerá un nuevo archivo llamado composer.phar. Para comprobar que se ha instalado correctamente, ejecuta el siguiente comando que muestra el menú de opciones de Composer:
  4. $ php composer.phar
  5. Por último mueve el archivo composer.phar a un directorio de ejecutables del sistema:
  6. $ sudo mv composer.phar /usr/local/bin/composer
  7. Comprueba que todo funciona como es debido ejecutando el comando composer sin opciones desde cualquier directorio.

Con esto habremos instalado Composer de forma global en el ordenador. De esta forma para actualizar la versión de Composer de todos los proyectos bastará con ejecutar el siguiente comando desde un terminal:

$ sudo composer self-update

Creando un proyecto base

Una vez hemos instalado Composer, podemos usarlo para crear un proyecto Symfony 2 básico:

$ composer create-project symfony/framework-standard-edition
<carpeta> <version>

En este caso <carpeta> es el directorio raíz del proyecto (por ejemplo "/var/www/vhosts/masquecursos/") y <version> es la versión de Symfony 2 a instalar. En el momento de escribir estas líneas la última versión estable de Symfony es la 2.3.5 y otras versiones disponibles serían la anterior 2.2.8 y la siguiente 2.4.0-BETA1. Más información en la página de instalación de Symfony.

El programa de instalación pedirá algunos datos necesarios para la misma:

  • Driver de base de datos: Generalmente será MySQL (pdo_mysql), pero podría ser SQLite (pdo_sqlite), PostgreSQL (pdo_pgsql), Microsoft SQL Server (pdo_sqlsrv), Oracle-PDO (pdo_oci), Oracle-No PDO (oci8), etc.
  • Host de base de datos: Por defecto 127.0.0.1.
  • Puerto de base de datos: Por defecto null.
  • Nombre de base de datos: Depende del proyecto.
  • Nombre del usuario de base de datos: Depende del proyecto.
  • Clave de acceso del usuario de base de datos: Depende del proyecto.
  • Protocolo de transporte para envío de emails: Por defecto smtp.
  • Host para envío de emails: Por defecto 127.0.0.1.
  • Nombre del usuario para envío de emails: Depende del proyecto.
  • Clave de acceso del usuario para envío de emails: Depende del proyecto.
  • Identificador local (locale): Por defecto en.
  • Clave secreta: Para configurar el sistema de seguridad.

Se pueden dejar los valores por defecto pues más adelante podremos cambiarlos. El programa de instalación creará la estructura básica de directorios de un proyecto Symfony 2 que es la siguiente:

  • proyecto/
    • composer.json
    • composer.lock
    • app/
      • check.php
      • console
      • cache/
      • config/
      • logs/
    • bin/
    • src/
    • vendor/
    • web/
      • app.php
      • app_dev.php
      • config.php

Cada una de las subcarpetas contiene a su vez otros archivos y carpetas, pero los que aparecen aquí son los más importantes. Más adelante hablaremos de lo que hay en cada carpeta y para que sirve cada archivo. Por ahora basta con saber que Composer nos crea todo esta estructura de carpetas y archivos.


Comprobaciones post-instalación

Todo proyecto Symfony 2 viene con un programa que permite comprobar si el ordenador cumple todos los requerimientos necesarios para el correcto funcionamiento del framework. Para ejecutarlo basta con abrir el terminal, entrar en el directorio del proyecto y teclear:

$ php app/check.php

Al ejecutar dicha utilidad, obtendremos una lista de requerimientos indicando en cada caso si tenemos la instalación correcta (OK) o si hay algún error (ERROR) o aviso (WARNING). Los errores (mandatory requirements) es necesario corregirlos antes de nada porque sino probablemente el proyecto no funcionará. Los avisos (optional checks) es conveniente corregirlos, pero no obligatorio.

Una vez comprobado que todos los requisitos están soportados por nuestra instalación se debe ejecutar otra utilidad llamada console.

$ app/console

Si todo es correcto se nos mostrará una lista de opciones de la consola Symfony. Más adelante veremos que esta consola es muy útil y se usa mucho para acciones comunes: limpiar la cache, crear la base de datos, crear entidades Doctrine, crear bundles, etc.


El problema de los permisos

Symfony 2 necesita permisos de escritura sobre dos carpetas del proyecto app/cache/ y app/logs/. Todas las demás carpetas pueden ser de sólo lectura, pero esas dos no. El problema es que el usuario Linux de la consola no es el mismo que el del navegador web (Apache) y ambos necesitan acceso a esos directorios, lo que puede provocar diversos problemas tipo "RuntimeException: Could not create cache directory" y otros similares. Para solucionarlo basta dar permisos de escritura a todos los usuarios para esos dos directorios concretos:

$ sudo chmod -R 777 app/cache/ app/logs/

Siendo puristas habría que dar permisos de escritura sólo al usuario www-data (Apache) o arreglar el tema de permisos vía grupo de trabajo que son las opciones recomendadas para entornos de producción, pero para el entorno de desarrollo sirve el chmod 777. Aquí puedes encontrar más información sobre cómo solucionar el problema de los permisos de Symfony 2.


Configurando el entorno

Para que el entorno de desarrollo sea lo más parecido posible al entorno de producción y aprovechando las características del servidor web Apache, vamos a crear un virtual host para este proyecto. Para ello en Ubuntu crearemos un archivo en la carpeta /etc/apache2/sites-available/ (ojo se necesitan permisos de root) y lo llamaremos como el proyecto (por ejemplo masquecursos). El contenido será el siguiente:

<VirtualHost *:80>
  ServerName masquecursos.me
  ServerAdmin webmaster@masquecursos.me
  DocumentRoot /var/www/vhosts/masquecursos/web
  DirectoryIndex app.php
  <Directory /var/www/vhosts/masquecursos/web>
    AllowOverride All
    Allow from All
  </Directory>
</VirtualHost>

Cada distribución de Linux es distinta y dicho archivo puede ser necesario crearlo en otra carpeta, aunque el contenido será el mismo. En Ubuntu posteriormente a la creación del archivo en /etc/apache2/sites-available/ es necesario crear un enlace simbólico en /etc/apache2/sites-enabled/. También habrá que editar el archivo /etc/hosts y asociar el nombre del virtual host con la IP 127.0.0.1. Posteriormente será necesario reiniciar el servidor Apache. La secuencia completa sería la siguiente:

$ sudo gedit /etc/apache2/sites-available/masquecursos
$ cd /etc/apache2/sites-enabled/
$ ln -s /etc/apache2/sites-available/masquecursos
$ sudo gedit /etc/hosts
$ sudo service apache2 restart

Con esto habremos configurado el entorno de ejecución y podremos acceder a nuestro sitio web desde http://masquecursos.me/, pero no lo pruebes todavía pues aun no funcionará. Por ahora para ver el contenido del proyecto es necesario usar el controlador de desarrollo http://masquecursos.me/app_dev.php. Más adelante veremos que es eso y porque aun no funciona con el controlador frontal app.php.


Configuraciones finales

Si entramos en nuestro navegador preferido y escribimos http://masquecursos.me/config.php veremos una página web con una bienvenida de Symfony. En caso de que la instalación no cumpla los requerimientos técnicos se mostrará una pantalla de error con la misma información que nos daba el archivo app/check.php. A estas alturas esos errores ya deberían estar corregidos. Desde la pantalla de bienvenida podemos acceder a otra de configuración del entorno desde la que se pueden configurar los mismos parámetros que cuando creamos el proyecto con Composer. En cualquier caso esos parámetros de configuración del entorno están en el archivo app/config/parameters.yml por lo que pueden modificarse a mano de forma sencilla.

¡Y ya está! Ya hemos creado un primer proyecto Symfony 2 vacío. En el siguiente capítulo veremos como crear el primer bundle y haremos el típico Hola Mundo con Symfony.


Más información


Mini-curso de Symfony 2

  • Primeros pasos: Conceptos y definiciones sobre Symfony 2.
  • Primer proyecto: Como empezar un proyecto Symfony 2.

sábado, 5 de octubre de 2013

Symfony 2: Primeros pasos

Llevo algún tiempo trabajando con Symfony 2 y, aunque aun no soy un experto, voy a intentar explicar cual es la estructura global de una aplicación Symfony y cuales son los primeros pasos para desarrollar una página web este popular framework PHP. Voy a dar por supuesto que ya sabéis qué es Symfony. Empezaré por algunos conceptos:


Bundles

Toda aplicación Symfony 2 está formada por bundles. Básicamente un bundle es una carpeta que contiene tu código fuente PHP, archivos de configuración y otros recursos como imágenes, hojas de estilos CSS, archivos HTML, javascripts, etc. Todo ello dentro de una estructura predeterminada de subcarpetas jerarquizadas.

Una aplicación Symfony 2 debe contener al menos un bundle, pero no hay límite en el número de bundles que se pueden crear. Algunos programadores ponen todo el código en un único bundle gigantesco mientras que otros prefieren crear un bundle por cada división lógica de la aplicación. Por ejemplo se puede crear un MainBundle para la parte principal de la web y un AdminBundle para la parte de administración.


Entidades (Doctrine)

Symfony es un framework PHP que implementa el patrón MVC (Modelo-Vista-Controlador), en el cual toda aplicación de divide en tres capas: modelo, vista y controlador. La primera capa es el modelo y se encarga del manejo y persistencia de los datos de la aplicación. En Symfony la capa del modelo está controlada por una herramienta llamada Doctrine que se encarga precisamente del acceso a los datos y su persistencia. Doctrine hace que nuestra aplicación sea independiente del motor de bases de datos, de forma que no será necesario escribir ni una sola sentencia SQL sino que tendremos que definir una serie de objetos PHP llamados entidades y Doctrine se encargará de lo demás.

A priori puede parece complicado pero es justo lo contrario. Las entidades se guardan como archivos PHP en una carpeta llamada Entity dentro de cada bundle.


Vistas (Twig)

En el patrón MVC, la capa vista es la que se encarga de la presentación en pantalla y de la interacción con el usuario. En symfony se utiliza un motor de plantillas llamado Twig que simplifica la creación de las vistas. Aquí puedes consultar más información sobre Twig en Español. Las vistas se guardan como archivos Twig en una carpeta llamada Resources/views dentro de cada bundle.


Controladores

En el patrón MVC, la capa controlador se encarga de procesar las peticiones, obtener los datos a través del modelo y lanzar las vistas. En symfony 2 los controladores son clases PHP que se derivan de la clase Controller y que se guardan como archivos PHP en una carpeta llamada Controller dentro de cada bundle.


Enrutamiento

Symfony permite controlar todas las rutas que acepta un sitio web. Cada ruta puede ser estática de tipo /seccion/accion/ o tener parámetros, que se encierran entre corchetes, como /seccion/ver/{param}. Al final cada ruta se corresponde a un método de uno de los controladores y los parámetros serán los argumentos del método. Por ejemplo el sitio MasQueCursos.org podría configurar las siguientes rutas:

  • "/" Página principal.
  • "/cursos" Lista de cursos.
  • "/cursos/buscar" Buscador avanzado de cursos.
  • "/cursos/{nombre}" Detalle de un curso.
  • "/centros" Lista de centros de formación.
  • "/centros/{nombre}" Detalle de un centro de formación.
  • "/temas" Lista de temas disponibles.
  • "/temas/{nombre}" Lista de cursos de un tema.
  • Etc.

Además en Symfony cada ruta debe tener un nombre único que lo identifique y estar asociada a un controlador y a una acción (método de la clase). Por ejemplo:

  • Página principal:
    • Nombre="indice", Ruta="/"
    • Controlador="@MasQueCursosBundle/Controller/DefaultController"
    • Accion="indexAction"
  • Lista de cursos:
    • Nombre="lista_cursos", Ruta="/cursos"
    • Controlador="@MasQueCursosBundle/Controller/CursosController"
    • Accion="listaAction"
  • Buscardor de cursos:
    • Nombre="buscar_cursos", Ruta="/cursos/buscar"
    • Controlador="@MasQueCursosBundle/Controller/CursosController"
    • Accion="buscarAction"
  • Detalle de un curso:
    • Nombre="ver_curso", Ruta="/cursos/{nombre}"
    • Controlador="@MasQueCursosBundle/Controller/CursosController"
    • Accion="verAction"
  • Etc.

Todo el sistema de rutas se puede configurar en Symfony de dos formas: a través de los archivos de configuración o a través de anotaciones, un sistema directamente heredado de Java, que consiste en poner datos de configuración directamente en los comentarios. Por ejemplo la siguiente clase es un controlador con anotaciones: Hay una anotación @Route a nivel del controlador y otra para cada método de la clase.

namespace Ifraktal\MasQuecursosBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * @Route("/cursos")
 */
class CursosController extends Controller {

    /**
     * @Route("/", name="lista_cursos")
     */
    public function listaAction()
    {
        // ...
    }

    /**
     * @Route("/buscar", name="buscar_cursos")
     */
    public function buscarAction()
    {
        // ...
    }

    /**
     * @Route("/{nombre}", name="ver_curso")
     */
    public function verAction($nombre)
    {
        // ...
    }

    // ...
}

Hasta aquí la primera entrada. En próximas entradas explicaré la estructura de carpetas de un proyecto symfony; cómo crear un proyecto Symfony 2 desde cero; etc.

jueves, 3 de octubre de 2013

devs.info - una web de atajos para programadores

Navegando por ahí me he encontrado con devs.info, una web de atajos para programadores. Se trata de una sencilla página web que contiene accesos directos a los más importantes recursos que puede necesitar un programador: documentación, libros, trucos, FAQ, etc. Ha sido creada por Miquel Camps Orteza y me ha parecido muy útil y completa.

Además proporciona una forma muy sencilla de recordar estos atajos. Por ejemplo si queremos acceder a la documentación oficial de Symfony basta que escribamos http://devs.info/symfony.doc en el navegador. Si queremos consultar una página de preguntas frecuentes sobre css sólo tenemos que poner http://devs.info/css.faq. Si necesitamos comprar un libro de programación Android, http://devs.info/android.book. Y así con todo.

La cantidad de recursos disponibles en devs.info es enorme: lenguajes de programación (PHP, Java, Javascript, Pyton, Ruby, HTML, ...), CMS's (Wordpress, Drupal, Joomla, ...), frameworks (Symfony, Codeigniter, Rails, Spring, Bootstrap, jQuery, ...), bases de datos (MySQL, MariaDB, ProtgreSQL, mongoDB, ...), motores de plantillas (Twig, Smarty, ...), servidores web (Apache, ...), desarrollo de juegos, servicios y otras herramientas variadas.

sábado, 28 de septiembre de 2013

Publicidad en Android: primer pago

Contacts Backup

Nuestra aplicación Android Contacts Backup lleva en activo casi un año y acabo de recibir la confirmación de AdMob, la red de publicidad para móviles propiedad de Google, de que han efectuado un pago en concepto de ganancias de publicidad móvil. El primer pago hasta la fecha. Y el importe total ha sido de:

75.67$

75.67$, que al cambio son unos 56€, por un año de publicidad no es un bagaje muy elevado. Ahí tenemos el eterno dilema de los programadores independientes: ¿Pongo mi app. gratuita con publicidad o la hago de pago? Y si la hago de pago, ¿A que precio? En un momento u otro todo aquel que haya publicado una aplicación o juego en Google Play o la App Store se ha hecho esta pregunta. En el año que lleva en Google Play (la primera versión fue publicada a primeros de octubre del año pasado), Contacts Backup ha sido descargada por 26.702 personas. Si la hubiéramos puesto de pago aunque sólo fuera por 10 cts, ¿Cuanto habríamos ganado? ¿2.600€? No porque entonces se la habrían bajado muchas menos personas. ¿Pero cuantas?

Creamos Contacts Backup como un experimento. Nunca pensamos en ponerle un precio pero queríamos saber si se podía ganar algo con la publicidad. El experimento no ha funcionado muy bien. Quizás sería el momento de sacar otra aplicación, ponerla de pago y ver que ocurre, pero tenemos más bien poca confianza.


Estadísticas

En un año en Google Play y con publicidad de AdMob hemos obtenido las siguientes estadísticas:

Instalaciones totales (1) 26.702
Instalaciones actuales (2) 5.115
Valoraciones totales 56
Valoración media 4,1/5
Publicidad: impresiones (3) 443.164
Publicidad: clics (4) 1.963
Publicidad: ganancia total (5) 95,05$
Publicidad: ganancia media por clic (6) 0,05$

(1) Número total de usuarios únicos que han instalado la aplicación en alguno de sus dispositivos. (2) Número de dispositivos activos únicos en los que está instalada la aplicación. (3) Número de veces que se ha mostrado un anuncio en la aplicación. No se cobra nada por mostrar anuncios. (4) Número de veces que un usuario ha hecho clic en un anuncio de la aplicación. Este es el único concepto importante, porque es lo que nos permite acumular ganancias. Cada vez que alguien hace clic en un anuncio, nosotros ganamos algo. ¿Cuanto? Muy poco. (5) 95,05$ son las ganancias acumuladas en total. 75,67$ es el primer pago que nos han enviado. AdMob paga una vez al mes siempre que se alcance el importe mínimo que es de 75$. Por lo tanto los 75.67 se corresponden a las ganancias entre OCT-2012 y AGO-2013. Y luego realmente se cobra un mes más tarde de el momento en que cierran un pago. Es un poco confuso pero por lo visto en EE.UU. es lo normal. (6) Es lo que hemos ganado realmente por cada clic (de media).

Contacts Backup

Valoraciones y comentarios

Un año, 56 valoraciones, 20 comentarios (en diversos idiomas) y algunos emails de usuarios dan para mucho. Desde aquí quiero dar las gracias a todos aquellos que han votado positivamente la aplicación, que la han comentado o que han enviado emails. Creo que hemos respondido todos los emails que hemos recibido, pero por si acaso: ¡Gracias a todos!

Dicho esto no puedo evitar hacer un comentario sobre una valoración hecha por un tal Vasilis K. que puso una estrella y de comentario "ADS!!!". Se ve que hay gente que lo quiere todo gratis y sin anuncios. Pero entonces, ¿Que aliciente tenemos para seguir creando aplicaciones Android? Hubo un francés que nos envió un email diciendo que le había gustado mucho y sugiriendo varias mejoras al programa para que fuera perfecto. La verdad es que sus sugerencias estaban muy bien. Algunas ya las habíamos pensado nosotros y se quedaron fuera por las prisas de sacar la app cuanto antes, pero otras eran nuevas y realmente interesantes. Sin embargo, ¿Para que íbamos a hacer esas mejoras? ¿Que ganamos con ello? ¿Satisfacción personal? Sí... pero la satisfacción no paga las facturas.


Conclusiones

75$ por un año en el mercado es ridículo Tardamos tres meses aproximadamente en desarrollar la aplicación. ¿Mucho tiempo? ¡Quizás! Pero teníamos poca experiencia en Java y debíamos aprender a usar bien las herramientas. Así que al fin y al cabo no fue tanto. Ahora un año después me planteo dos opciones sobre que hacer con Contacts Backup:

  1. Lo dejo todo como está. Total para lo que íbamos a ganar...
  2. Le hago un lavado de cara, le añado nuevas funcionalidades y entonces:
    • Lo pongo de pago como un Contacts Backup Pro.
    • Actualizo la versión actual añadiendo más anuncios.

¿Qué creéis que debemos hacer? Se aceptan sugerencias...

lunes, 23 de septiembre de 2013

¿Qué es Symfony?

Es difícil explicar qué es Symfony. Sería correcto decir que Symfony es un framework basado en lenguaje PHP, diseñado para optimizar el desarrollo de las aplicaciones web usando en el patrón Modelo Vista Controlador (MVC). Algo así pone en la Wikipedia en su entrada Symfony. Pero eso es quedarse terriblemente corto. Esa misma definición encaja por ejemplo con Codeigniter y en realidad son dos cosas totalmente distintas, aunque persigan el mismo fin.

En la página web oficial de Symfony lo describen como un framework PHP, una filosofía y una comunidad; todos trabajando juntos en armonía. Esa es una definición "de libro", pero tampoco explica bien que es Symfony.

En realidad Symfony es más bien un conjunto de herramientas y servicios heterogéneos que, trabajando juntos, permiten desarrollar páginas y aplicaciones web complejas de forma eficiente, reduciendo el tiempo de desarrollo y automatizando las tareas comunes. Entre las herramientas que proporciona Symfony se encuentra un framework PHP, un gestor de plantillas (Twig) y un gestor ORM (Doctrine) y mucho más. Además es sumamente sencillo incorporar herramientas y aplicaciones de terceros.

La diferencia principal entre Symfony y otros frameworks PHP como Codeigniter es que mientras Codeigniter es un framework PHP puro (y ya está), Symfony es mucho más. Symfony proporciona toda una nueva filosofía de trabajo, incorporando multitud de herramientas que ayudan al desarrollo web y dirigen el proyecto, pero también lo limitan. Una ver has adoptado Symfony no puedes hacer las cosas como quieras: tienes que adaptarte a su filosofía. También es cierto que la la curva de aprendizaje de Symfony es mucho más pronunciada que Codeigniter. Empezar de cero con Symfony no es fácil, por mucha experiencia que tengas en PHP y en otros frameworks.


Un poco de historia

Symfony es un proyecto de software libre creado en 2005 por Fabien Potencier, actual CEO de Sensio Labs. La versión 1.0 fue liberada en 2007 y actualmente va por la versión 2.3, estando en preparación la 2.4. Cada nueva versión de Symfony incorpora mejoras y nuevas herramientas. Por desgracia las nuevas versiones no siempre son retrocompatibles, siendo necesario realizar cambios en el código fuente de los proyectos para adaptarse, aunque el salto más grande se produjo entre la versión 1.4 y la 2.0 (Symfony 2).


Un vistazo rápido

El framework Symfony obliga desarrollar usando el patrón Modelo-Vista-Controlador (MVC). Dicho patrón divide el desarrollo del proyecto en tres partes: el Modelo que gestiona todo lo relacionado con los datos que maneja la aplicación, la Vista que gestiona todas las interacciones con el usuario y el Controlador que gestiona todo lo que ocurre en la aplicación. El controlador procesa las peticiones, recupera los datos usando el modelo y lanza las vistas que interaccionan con el usuario. En Symfony cada una de estas partes está regulada por un componente diferente:

  • Modelo: En Symfony la parte del modelo viene gestionada por Doctrine que es una una biblioteca de clases cuyo objetivo es dotar al proyecto de poderosas herramientas para facilitar la lectura/escritura de información desde/hacia una base de datos. Doctrine es compatible con la mayoría de gestores de bases de datos, como MySQL, PostgreSQL, Oracle, etc.

    Una de las características más importantes es que el código en Doctine es independiente del gestor de base de datos. En teoría se podría cambiar el gestor en cualquier momento sin tener que modificar una línea de código. Para ello en Doctrine las queries se escriben usando DQL (Doctrine Query Language) que es una especie de SQL orientado a objetos.

  • Vistas: La parte de las vistas en symfony se gestiona con el motor de plantillas Twig del que ya hablamos hace tiempo.

    Al igual que otros motores de plantillas, Twig ayuda a separar de forma sencilla la lógica de la aplicación (código PHP) de la presentación (HTML/CSS). Es una herramienta muy potente pero a la vez muy flexible que permite diseñar plantillas de presentación muy complejas sin usar instrucciones PHP, haciendo que el código HTML/CSS final sea mucho más legible. En Twig se pueden usar variables, filtros, funciones, estructuras de control (if, for, ...), macros, expresiones, comentarios y más.

  • Controlador: En el patrón MVC el controlador se encarga de recoger las peticiones HTML, procesarlas, recuperar los datos, generar nuevas peticiones y/o lanzar las vistas correspondientes. En Symfony la parte del controlador está gestionada por clases propias del framework. Se pueden definir múltiples controladores y dentro de cada controlador varias acciones.

  • Arquitectura: Toda aplicación Symfony se divide en paquetes (bundles). Cada bundle puede contener: controladores, entidades (modelo), plantillas (vistas), archivos de configuración y otros recursos (formularios, menús, traducciones, etc.). Todo ello se controla a través de de namespaces, una característica de PHP 5.3.

  • Configuración: Symfony es un producto altamente configurable que soporta además diversos métodos de configuración, de forma que en cada proyecto se puede escoger la que mejor se adapte a las necesidades, pudiendo incluso mezclarse. Symfony puede usar indistintamente configuración a través de archivos YAML, XML o PHP. También soporta Annotations para configurar por ejemplo las rutas de los controladores.

Referencias

jueves, 5 de septiembre de 2013

Relojes inteligentes, ¿Para qué?

Con la presentación ayer de los nuevos relojes inteligente Samsung Galaxy Gear y Qualcomm Toq, que se vienen a unir a los Sony Smartwatch y a las sospechas y filtraciones de que Apple y Google están desarrollando sus propias versiones, parece que todos los fabricantes tecnológicos han encontrado un nuevo filón y nadie quiere quedarse atrás. Pero, ¿Cual es la realidad? ¿Existe realmente mercado para este tipo de dispositivos? El smartwatch de Sony lleva algún tiempo en el mercado y las ventas parecen contradecir las prisas de los fabricantes.

El mi opinión mercado hay, pero el planteamiento actual de estos relojes inteligentes está equivocado. Porque como el propio nombre indica, además de ser "inteligentes", son relojes y no puede ser que un reloj necesite recargar su batería todas las noches. Samsung ha anunciado 25 horas de autonomía de su nuevo super-reloj. Y eso será si no lo usas mucho, claro, lo cual es totalmente insuficiente. ¿Realmente quiero un reloj cuya batería no se si me va a llegar a la noche? ¿Y de verdad necesito un reloj con cámara de fotos? ¿Para qué, si ya tengo el móvil? Porque no olvidemos que esos smartwatches se quedan en simples relojes si no tienen un smartphone al lado. Luego está el precio: 300€ de vellón. Nada menos. Algo totalmente desorbitado. Y me he dejado lo peor para lo último: El Samsung Galaxy Gear por ahora sólo es compatible con los nuevos Galaxy Note 3 y Note 10.1 (2014). Eso sí: Anuncian compatibilidad futura con el S3, S4 y Note 2. Así que si eres el feliz dueño de uno de estos teléfonos y te sobran 300€ para gastar en un gadget inútil, estás de enhorabuena

En este sentido, y a falta de ver que harán Google y Apple, probablemente la apuesta de Qualcomm sea la más acertada hasta el momento: Un reloj con pantalla de bajo consumo, autonomía de entre 3 y 5 días, conexión por Bluetooth y carga inalámbrica. La autonomía aun es muy poca en mi opinión, pero algo es algo. Una ventaja de este reloj es que la pantalla no se apaga, a diferencia de los otros comentados. Aunque el precio, que según parece estará alrededor de los 300€ como sus competidores, lo hacen poco apetecible.

Mucho tienen que cambiar las cosas para que siquiera me plantee comprarme un smartwatch. Un reloj que aparte de darte la hora y permitirte programar las alarmas, se conecte al teléfono por NFC o Bluetooth para enseñarte las notificaciones pendientes, te permita leer un mensaje, mail o Whatsapp (que no escribirlo), que tenga una autonomía decente (2 semanas al menos) y alguna funcioncilla más como permitirte cambiar de canción sin sacar el smartphone del bolsillo puede ser interesante. Todo lo demás sobra. O eso o reducen drásticamente el precio y "crean" una necesidad.

Referencias

Diseño web: Slideshows como ejemplo de ineficiencia

Navegando por ahí me he encontrado con un artículo que pone los slideshows como ejemplo de ineficiencia en el diseño web. El artículo me ha parecido un tanto alarmista, pero aun así bastante interesante para compartirlo. Recordemos que un slideshow es una forma de presentar el contenido mostrando imágenes una detrás de otra en intervalos regulares. El artículo viene a decir que según las estadísticas los usuarios sólo hacen click en la primera de las imágenes entre un 1% y un 3% de las veces, mientras que las demás imágenes apenas reciben ningún click.

Como decía arriba la conclusión del artículo, que es la de dejar de utilizar slideshows totalmente, me ha parecido demasiado alarmista. Como en todo lo demás, usar o no usar este tipo de estructuras dependerá de la página que estemos diseñando. A unas páginas se adaptarán mejor y a otras peor. Nosotros mismos hemos usado slideshows en numerosas ocasiones con buenos resultados. Por ejemplo en la home de nuestra página web.

lunes, 26 de agosto de 2013

Como funciona el protocolo HTTPS

Revisando mis feeds RSS (a través de Feedly, por supuesto) me acabo de encontrar con un fantástico artículo de Genbeta sobre como funciona el protocolo HTTPS. Precisamente en los últimos días he tenido que investigar sobre el protocolo HTTPS (Hyper Text Transfer Protocol Secure) y me ha parecido un artículo muy completo. Sólo hecho de menos algunos enlaces de interés.


Enlaces de Interés

martes, 6 de agosto de 2013

Esto es lo que ocurre cuando no cuidas a tus usuarios

A HTC no le salen las cuentas. Ya lo habíamos predicho allá por febrero cuando escribimos el artículo HTC One, el fracaso de un gran smartphone: La otrora líder en la fabricación de smartphones está en crisis. Su teléfono estrella de este año, el HTC One, pese a ser un gran terminal (el mejor smartphone del momento, dicen algunos análisis), no se está vendiendo como esperaban en HTC, una vez pasados los primeros meses. No lo decimos nosotros sino muchas de las publicaciones especializadas (ver referencias).

HTC One

Los motivos

Los motivos de por qué HTC está fracasando son en mi opinión variados y diversos. Por un lado el HTC One es caro, pero sus competidores (Samsung Galaxy S4, Sony Xperia Z, etc.) también lo son y se están vendiendo mejor. Y en cuanto a prestaciones en HTC está a la altura e incluso supera a sus rivales. Así que no debe ser ese el problema.

La falta de alternativas interesantes en las gamas medias y baja de HTC también pueden tener parte de culpa en el descenso de ingresos de HTC. Para arreglar un poco ese problema HTC ha presentado hace unos días el HTC One Mini, pero Samsung también tiene su S4 mini y en la gama media hay bastante competencia de Sony, LG y otros. De todas formas, aunque el HTC One Mini se venda bien no parece probable que vaya a sacar a HTC de los números rojos.

Entonces, ¿Cual es el problema de HTC? Yo lo tengo claro: el maltrato reiterado a los usuarios.

HTC siempre se ha caracterizado por la falta de evolución de sus teléfonos una vez pasados pocos meses de su salida al mercado. Los antiguos poseedores de un HTC Desire o Sensation (magníficos teléfonos por otro lado) que vieron como sus teléfonos se quedaban estancados en versiones de Android obsoletas cuando por hardware eran perfectamente capaces de evolucionar difícilmente se comprarán ahora un HTC One, por bueno que éste sea. Ni tampoco recomendarán un HTC a sus conocidos.

¿Y la solución? Pues es difícil. Una vez te has labrado tan mala reputación, cambiarlo no es fácil. Pero todo depende de la propia HTC. Desde luego saben hacer buenos smartphones. Si hacen un giro de 180º en su política de actualización de terminales, quizás dentro de unos años las cosas cambien. Quizás...


Referencias

jueves, 20 de junio de 2013

Javascript: use strict

Muchas librerías Javascript contienen un extraño código en sus entrañas: 'use strict'. No se trata de una palabra clave de Javascript pues va escrita entre comillas, pero su uso en muy importante ya que le indica al motor de ejecución de scripts que use el modo estricto. Dicho modo es más restrictivo y un poco más seguro, ya que da errores de ejecución en sentencias que normalmente pasaría. El "modo estricto" viene promovido desde la 5ª edición de la especificación del lenguaje ECMAScript, pero no todos los motores de Javascript lo usan. Para los programadores es importante su uso a la hora de desarrollar librerías Javascript y depurar errores ya que, entre otras cosas, obliga a declarar las variables. Los desarrolladores deben programar "mejor" (con más cuidado), prestando más atención a los errores que normalmente se pasan por alto debido a la flexibilidad de JavaScript en modo no estricto, con lo que el código resultante es "mejor".

El modo estricto puede definirse a nivel de módulo o restringido a un ámbito concreto. Por ejemplo puede hacerse que sólo esté activo dentro del contexto de una función. En el siguiente ejemplo 'use strict' se restringe al interior de la función:

(function(){
    'use strict';
})();

Referencias

sábado, 8 de junio de 2013

Como crear un disco de reparación de Windows en un USB

Recientemente he necesitado crear un disco de reparación de Windows para arreglar la instalación de un portátil con arranque dual (Windows 7 y Ubuntu 12.04 LTS) en el que estuve moviendo las particiones. El problema es que ese portátil tiene estropeado el lector DVD hace años. Por suerte, aunque ya tiene unos añitos, es lo bastante moderno como para que sea capaz de arrancar desde una unidad USB (pendrive). Así que me puse a investigar como crear un disco de arranque en una unidad USB y la verdad es que es bastante sencillo: Windows incorpora una utilidad e línea de comandos llamada DISKPART que es perfecta para eso.


Paso 1: Crear un disco de reparación de Windows

Lo primero es lo primero y en este caso habrá que crear un disco de reparación de Windows. Para ello sólo hay que abrir el Panel de control >> Sistema y seguridad >> Copias de seguridad y restauración >> Crear un disco de reparación del sistema. Por desgracia Windows 7 sólo permite grabar un disco de reparación en un medio físico: es decir un CD o un DVD. Así que no hya más remedio que crear el disco y luego ya lo pasaremos al pendrive.

Reparación Windows

PASO 2: Preparar el pendrive

Una vez hemos creado el disco de arranque en un CD o DVD hay que iniciar la utilidad DISKPART. Para ello basta con escribir DISKPART en el cuadro de búsqueda del menú de inicio de Windows. Una vez arrancado el programa, la secuencia de comandos para crear un disco USB arrancable es la siguiente:

list disk
select disk n
clean
create partition primary
select partition 1
active
format fs=fat32
assign
exit

En lugar de la "n" en el segundo comando hay que escribir el número del disco USB, según la lista que aparece tras escribir el primer comando. En nuestro caso era el 5, pero en cada ordenador será diferente. Ten en cuenta que la partición primaria del disco seleccionado se perderá para siempre, borrándose todos los datos allí almacenados y sin posibilidad de recuperación. Asegúrate de que no te importa perder esos datos antes de ejecutar DISKPART. Ojo: Si se selecciona un número de disco erróneo, el resultado puede ser catastrófico. Podría borrarse toda la información del disco duro principal. No nos hacemos responsables de los posibles errores cometidos tras leer este artículo.

DISKPART

PASO 3: Copiar los archivos del disco de arranque al pendrive

Ya tenemos un disco de arranque USB. Ahora sólo falta copiar todos los archivos del CD o DVD de arranque que creamos antes sobre el disco USB. Pero antes hay que hacer que los archivos de sistema sean visibles desde el explorador de archivos. Para ello hay que abrir una ventana del explorador y acceder a las opciones de carpeta. Por ejemplo Inicio >> Equipo >> Organizar >> Opciones de carpeta y búsqueda >> Ver. Luego hay que activar la opción Mostrar archivos, carpetas y unidades ocultos y desactivar la opción Ocultar archivos protegidos del sistema operativo. Ya podrás realizar la copia de la forma habitual y ya tendrás un disco de arranque USB con las utilidades de reparación de Windows. Te recomendamos que al finalizar restaures las opciones de carpeta a su estado anterior.


Bonus track: Otros comandos de DISKPART

Algunos de los comandos de DISKPART son los siguientes: (la lista detallada se encuentra aquí)

  • list disk
    Muestra la lista de discos del equipo.

  • list partition
    Muestra la lista de particiones del disco seleccionado.

  • list volume
    Muestra la lista de volúmenes del equipo.

  • select disk[=n]
    Selecciona un disco por número o bien muestra el disco seleccionado.

  • select partition[=n/l]
    Selecciona una partición por número, letra de unidad o punto de montaje o bien muestra la partición seleccionada.

  • select volume[=n/l]
    Selecciona un volumen por número, letra de unidad, punto de montaje o ruta de acceso o bien muestra el volumen seleccionado.

  • detail disk
    Muestra información detallada del disco seleccionado.

  • detail partition
    Muestra información detallada de la partición seleccionada.

  • detail volume
    Muestra información detallada del volumen seleccionado.

  • create partition primary [size=n][offset=n][id=byte/guid][noerr]
    Crea una partición primaria.

  • create partition extended [size=n][offset=n][noerr]
    Crea una partición extendida.

  • create partition logical [size=n][offset=n][noerr]
    Crea una partición lógica sobre una partición extendida.

  • delete partition [noerr][override]
    borra la partición seleccionada.

  • create volume simple [size=n][disk=n][noerr]
    Crea un volumen simple.

  • delete volume [noerr]
    Borra el volumen seleccionado.

  • assign [[letter=l]/[mount=ruta de acceso]][noerr]
    Asigna una letra de unidad o un punto de montaje a la partición seleccionada.

  • active
    Establece la partición seleccionada como activa.

  • extend [size=n][noerr]
    Extiende el volumen seleccionado con el espacio contiguo no asignado.

  • remove [[letter=l]/[mount=ruta de acceso]/[all]][noerr]
    Quita una letra de unidad o un punto de montaje de la partición seleccionada o quita todas las letras de unidad y puntos de montaje actuales.

  • help
    Muestra la ayuda.

  • exit
    Detiene el programa.

Bonus track x2: Instalar Ubuntu desde un disco USB

Curiosamente existe un método muy sencillo para preparar un disco de instalación de Ubuntu en una unidad USB. Consiste en utilizar una utilidad para Windows llamada Universal USB Installer. Podéis encontrar un tutorial Aquí. Básicamente hay que descargar la versión de Ubuntu deseada desde la página oficial que vendrá en formato ISO listo para grabar en un DVD y usar la utilidad Universal USB Installer para grabarlo en un DVD. Sencillo... ¿Ehh?

lunes, 3 de junio de 2013

Herramientas de programación web: Twig

Hoy voy a hablar un poco de Twig, una herramienta más enfocada al diseño web que a la programación que viene integrada en el framework Symfony2, pero que puede utilizarse también por separado.

Twig es un motor de plantillas para PHP similar a Smarty. Es un proyecto de código abierto (open source) ofrecido bajo licencia BSD y desarrollado por Fabien Potencier, el creador de Symfony. Por ello es lógico que Twig sea el motor de plantillas por defecto de Symfony2.

Al igual que otros motores de plantillas, Twig ayuda a separar de forma sencilla la lógica de la aplicación (código PHP) de la presentación (HTML/CSS). Es una herramienta muy potente pero a la vez muy flexible que permite diseñar plantillas de presentación muy complejas sin usar instrucciones PHP, haciendo que el código HTML/CSS final sea mucho más legible.


Ejemplo

El siguiente es un ejemplo básico de plantilla Twig:

<!DOCTYPE html>
<html>
  <head>
    <title>Client List</title>
  </head>
  <body>
    <h1>Client List</h1>
    <ul>
    {# Recorrido por la lista de clientes #}
    {% for client in clients %}
      <li>
        <a> href="/client/{{ client.id }}">
          {{ client.name }}
        </a>
      </li>
    {% else %}
      No se han encontrado clientes.
    {% endfor %}
    </ul>
  </body>
</html>

Variables, filtros y funciones

Uando Twig podemos acceder al contenido de una variable simplemente poniendo su nombre entre llaves dobles: {{ var }}. Además podemos acceder a las propiedades de un objeto usando la sintaxis {{ obj.attr }}. Este mecanismo es tan potente y flexible en Twig que buscará primero como elemento (obj['attr']); si no existe buscará como atributo (obj.attr); y por último si no existe buscará como método (obj.getAttr()). Otra característica de Twig es que podemos aplicar filtros a las variables para modificar su comportamiento. Por ejemplo para formatear una fecha antes de imprimirla en pantalla: {{ date | date('d/m/Y H:i') }}. Los filtros además pueden encadenarse de forma que se ejecuten uno detras de otro. Así {{ text | striptags | upper }} eliminaría los tags HTML del texto y lo escribiría en mayúsculas.


Estructuras de control

En Twig hay una serie de instrucciones que se escriben entre {% ... %}.

  • {% if cond1 %}...{% elseif cond2 %}...{% else %}...{% endif %}
  • {% for item in array %}...{% else %}...{% endfor %}
  • {% set var = value %}
  • Etc.

Comentarios

Los comentarios se escriben entre {# ... #}:


Referencias

Adroid Studio

Android Studio

Como la mayoría sabréis, en el pasado Google I/O se presentó un nuevo entorno de desarrollo (IDE) para programar aplicaciones para el sistema operativo Android llamado Android Studio. Se trata de una nueva herramienta de programación que sustituye al problemático Eclipse. El nuevo IDE, que tiene versiones para Windows, Linux y Mac, está basado en IntelliJ IDEA y según parece está siendo muy bien valorado por los desarrolladores a pesar de que aun no tiene una versión definitiva.

Algunas de sus características son:

  • Herramientas de construcción extensible.
  • Potente editor de código.
  • Interfaz gráfica de usuario mejorada.
  • Fácil acceso a los servicios de Google.
  • Herramientas específicas para Android.
  • Desarrollo de código abierto.

Personalmente aun no he tenido la oportunidad de probarlo pero los chicos de El Androide Libre si que lo han hecho y han publicado una mini guía en tres artículos sobre el nuevo Android Studio:


Otras referencias

miércoles, 24 de abril de 2013

Herramientas de programación web: LESS

Cualquier programador o diseñador de páginas web sabe que el lenguaje que se usa para dar estilo a las páginas web HTML es el CSS (Cascading Style Sheets). Se trata de lenguaje de marcas muy potente que permite separar el contenido de la presentación, aplicando estilos a los elementos HTML de forma individual o global, pero que tiene una deficiencia enorme: no se puede parametrizar. Es decir CSS no permite definir variables, operaciones o funciones.

LESS es una extensión del lenguaje CSS que permite usar variables, aplicar operaciones aritméticas (sumas, restas, etc.) y definir funciones para código repetitivo. Desgraciadamente los navegadores no entienden LESS, por lo que será necesario compilar el código convirtiéndolo en CSS. Sin embargo para usar LESS en un proyecto web no se requiere usar plug-ins ni nada parecido. Hay varias formas de compilar las plantillas LESS:

  • La primera es hacerlo de forma estática a través de un compilador. Se trata de compilar las plantillas LESS convirtiéndolas en hojas de estilo CSS normales que se usarán de la forma habitual. Hay varias aplicaciones que convierten plantillas LESS en archivos CSS como Simpless o Less.app y existe un compilador oficial llamado lessc (para Linux):
  • $ lessc styles.less > styles.css
    
  • La segunda forma consiste en usar la librería javascript node.js en el lado del servidor para compilar de forma dinámica las plantillas LESS. Esta es la forma más habitual.
  • La tercera y última forma de usar LESS es a través de javascript del lado del cliente usando less.js. Esta sólo se recomienda para proyectos muy pequeños o para entornos de desarrollo, ya que es necesario compilar la hoja de estilos en cada ejecución, lo que puede ralentizar mucho la ejecución.

Origen y desarrollo

LESS fue desarrollado por Alexis Sellier, conocido como cloudhead, como un proyecto de código abierto que actualmente está mantenido por the LESS core team. Su uso es libre y gratuito.


Sintaxis de LESS

No voy a extenderme en la sintaxis de LESS, aunque voy a poner un ejemplo de algunas de las estructuras más importantes. Para más información sobre la sintaxis consultar los enlaces al final del artículo.

Variables: Podemos definir variables y darles cualquier valor. Los nombres de variable empiezan siempre con @ y podemos usarlas a lo largo del código siempre que las necesitemos.

@rojo: #C00000;
@verde: #008000;
@azul: #0000FF;

h1 { color: @rojo; }
a { color: @verde; }
a:hover { color: @azul; }

Operaciones aritméticas: LESS permite aplicar operaciones como sumas, restas o multiplicaciones. Por ejemplo se pueden sumar dos colores o multiplicar pixels.

@ancho: 100px;
@azul: #000080;
@azul-claro: (@azul + #111);

.azul-claro {
    background-color: @azul-claro;
    width: (@ancho * 2);
}

Mixings: Esta construcción permite aplicar las propiedades de un conjunto de reglas a otro conjunto de reglas, permitiendo parametrizaciones e incluso el uso de valores por defecto.


.borde-simple(@color-borde: black) { border: solid 1px @color-borde; } #container { .borde-simple; } #error { .borde-simple(#FF0000); }

Reglas Anidadas: LESS soporta una sintaxis alternativa a CSS con respecto a jerarquía de clases en forma de clases anidadas. Por ejemplo:

#header {
    width: 30px;
    h1 { float: left; color: red; }
    h2 { float: right; color: blue; }    
}

...se convertirá en:

#header { width: 30px; }
#header h1 { float: left; color: red; }
#header h2 { float: right; color: blue; }

Funciones de Color LESS soporta una gran variedad de funciones para transformar colores y obtener información de un color.

  • lighten(@color, 10%): Devuelve un color un 10% mas claro.
  • darken(@color, 10%): Devuelve un color un 10% mas oscuro.
  • saturate(@color, 10%): Devuelve un color un 10% más saturado
  • desaturate(@color, 10%): Devuelve un color un 10% menos saturado
  • fadein(@color, 10%): Devuelve un color un 10% menos transparente
  • fadeout(@color, 10%): Devuelve un color un 10% más transparente
  • spin(@color, 10): Devuelve un color con 10 grados de tono mayor.
  • spin(@color, -10): Devuelve un color con 10 grados de tono menor
  • hue(@color): Devuelve el valor del matiz del color.
  • saturation(@color): Devuelve el valor de la saturación del color.
  • lightness(@color): Devuelve el valor de la luminosidad del color.

Conclusiones

LESS es una herramienta muy potente para el desarrollo web que eleva CSS al nivel de lenguaje de programación con lo que la creación de hojas de estilo se convierte en una parte más del proceso de desarrollo de software.


Enlaces