El patrón Observer y su implementación en PHP

Volvemos con el tema de los patrones de diseño y PHP, que estaba abandonado (y ahora tengo más tiempo para escribir con el parón temporal del podcast). Esta tarde vamos a hablar del patrón Observer, que en castellano es conocido como el patrón publicación-inscripción.

La idea de este patrón es que nos permita definir una dependencia uno-a-muchos entre varios objetos, provocando que cuando uno cambie de estado se lo notifique a sus objetos dependientes. El objetivo de este patrón es reducir el acoplamiento entre clases que requieren mantener una gran consistencia en sus relaciones, siendo clave para la implementación del patrón MVC. Dentro de esta relación denominamos Sujeto al objeto que emite la información sobre el cambio de estado, y Observador al que la recibe para realizar la acción que sea necesaria.

Os dejo esta imagen con un diagrama cargado desde la Wikipedia para ilustrar su funcionamiento:

Diagrama Estructura Patrón Observer
Un diagrama de estructura del patrón Observer (publicación-inscripción).

En PHP 5, a partir de la revisión 5.1 contamos con las interfaces SplSubject y SplObserver para implementar respectivamente el sujeto y el observador.

Vamos con un ejemplo clásico: una tienda on-line que notifica la compra y la venta de un artículo.

<?php
class Articulo implements \SplSubject /*Empezamos importando la interfaz del sujeto*/
{
    protected $storage;

    public function __construct(\SplObjectStorage $storage)
    {
        $this->storage = $storage;
    }

    public function compra()
    {
        // compra
        $this->notify('comprado');
    }

    public function vende()
    {
        // vende
        $this->notify('vendido');
    }

    public function attach(\SplObserver $observer)
    {
        $this->storage->attach($observer);
    }

    public function detach(\SplObserver $observer)
    {
        $this->storage->detach($observer);
    }

    public function notify($event = '')
    {
        foreach ($this->storage as $observer)
            $observer->update($this, $event);
    }
}

class Notify implements \SplObserver /*seguimos con lai implementacion del observer*/
{
    public function update(\SplSubject $subject, $event = '')
    {
        if ($event == 'comprado')
            echo 'El artículo se ha comprado' . PHP_EOL;
        else if ($event == 'vendido')
            echo 'El artículo se ha vendido' . PHP_EOL;
    }
}

/*¿Cómo luciría llevado a la práctica?*/

/*Creamos el objeto*/
$articulo = new Articulo(new \SplObjectStorage());
/*vinculamos el artículo al observer*/
$articulo->attach(new Notify()); 
/*imprimiría en pantalla que se ha comprado*/
$articulo->compra();
/*imprimiría que se ha vendido*/ 
$articulo->vende(); 
?>

Es una idea básica donde simplemente se imprime en pantalla el resultado de una acción, pero ya os hacéis una idea de las posibilidades de este patrón.

Fernando Martin Basket Master

Hoy se cumplen 25 años del triste fallecimiento de Fernando Martín, pivot cuya carrera se repartió entre Estudiantes, Real Madrid y Portland Trail Blazers. Se convirtió, en 1986, en el primer español y segundo europeo sin formación universitaria en pisar la NBA, tras el búlgaro Georgi Glouchkov. Pivot extremadamente fuerte y atlético aunque con pocos centímetros, podría comparársele con jugadores actuales del corte del veterano Batiste, Kyle Hines, Stephane Lasme o el madridista Marcus Slaughter, lo que ahora llaman un pivot «undersized«.

Hoy serán muchos los medios que recuerden sus épicas batallas en la zona en sus años ACB (y también pre-ACB, cuando la máxima categoría era organizada por la FEB), sobre todo con el que fue su gran rival, el barcelonista Audie Norris, aunque también con otros grandes pivots de la década de los 80 como John Pinone o Anicet Lavodrama. Pero como este es un blog donde el basket y la informática van de la mano aprovecharemos para recordar que también tuvo un videojuego, creado por la extinta y legendaria compañía Dinamic.

En el vídeo podéis echar un ojo a este Fernando Martín Basket Master, juego de 1987 que en principio iba a ser «Fernando Martín vs Epi«, pero el alero barcelonista finalmente no quiso ceder su imagen. La idea era hacer un juego de basket 1 vs 1 al estilo del Dr J vs Larry Bird que EA había publicado en 1983, y logró bastante éxito en su época incluso fuera de España, donde se vendió simplemente como Basket Master. Un año después la propia EA recuperaría el concepto publicando Michael Jordan vs Larry Bird. Recuperamos esta clásico de la edad de oro de la producción española de los juegos 8-bits (cuando España era potencia europea en un campo de tecnología punta, quién lo diría a día de hoy con el empresaurio campando a sus anchas) como recuerdo de aquel gran pivot.

Centrando verticalmente elementos de bloque en CSS

Si bien centrar elementos horizontalmente no suele suponer un problema cuando trabajamos con CSS, el hacerlo verticalmente es mucho más puñetero. Desde que se jubilaron las engorrosas tablas, que todo hay que decirlo para el tema del centrado eran bastante cómodas, son muchos los que llevan buscando una solución. Con los elementos inline la cosa no es tan pesada, pero con los elementos de bloque puede tonarse desquiciante.

Si trabajamos con navegadores modernos, con total soporte de CSS3, la solución nos llega de la mano de Flexbox con unas pocas líneas. Basta con definir la alineación usando esta propiedad en el elemento contenedor como podéis ver en este fiddle:

.contenedor {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

Con flexbox la alineación vertical es tan simple como en las viejas tablas. Pero ¿y si no podemos contar con flexbox?… el horror, el horror… Bueno, no tanto, también hay una solución. En este caso lo primero será definir la posición del contenedor como relativa, y el elemento a centrar de forma absoluta, situado en la mitad de la altura del padre y a su vez desplazando su eje Y otro 50% (suena más rollo de lo que es, la idea es poner el borde superior en la mitad del contenedor y luego desplazarlo la mitad de su propia altura de forma que el centro del elemento queda en el centro del contenedor, viendo el código a continuación se entiende, y podéis ver el resultado en un fiddle)

.contenerdor {
  position: relative;
}
.elementoACentrar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

Listo, dos métodos para alinear verticalmente un elemento de bloque en CSS que te pueden ahorrar mucho tiempo.

Ver qué IP’s están libres en una red

Por la mañana me preguntaba un compañero «¿hay forma de ver qué Ip’s están libres en una red?», ya que estaba configurando una red que requiere que las dichas IP estén fijas.

¿Hay forma de hacerlo? Sí, la hay. Y es muy sencillo. Desde tu terminal linuxero (testeado en Ubuntu) la útil herramienta nMap te puede dar esa información:

#Con el siguiente comando 
# nmap -v -sP seguido del rango donde buscaremos
#podemos ver todas 
#las ip's que hay dentro de una subred local 
#y su estado:
#

nmap -v -sP 192.168.1.*

#como queremos ver las libres
#recurriremos a una expresión regular
#sacando sólo las que estén "down":

nmap -v -sP 192.168.1.* | grep down

En vuestro caso cambiáis los datos por el rango de ip que os corresponda según la configuración de la red y la máscara de subred. Podéis conocer esos datos utilizando el comando ifconfig, y si no sabes calcular el rango de direcciones de la red siempre puedes recurrir a esta herramienta.

La herramienta nMap es sumamente útil para auditorías de seguridad, aunque también puede usarse para pequeñas consultillas como esta.

Cinco generadores de Lorem Ipsum muy curiosos

Todo el que esté en los mundillos de la programación o el diseño sabe lo que es el lorem ipsum, un texto de prueba de impresión que se supone que procede del siglo XVI. Pululando por la red hay muchos generadores de texto aleatorio curiosos y divertidos y aquí me he decidido a recopilar los cinco mejores (bueno, realmente son los cinco que más gracia me han hecho):

  • Cthuvian Ipsum Generator: Para fanáticos de H.P. Lovecraft y su saga de Cthulhu, este generador os dará unas líneas que os acercarán a las simas de la locura primigenia.
  • Zombie Ipsum: Para los amantes de los no muertos también hay un generador cargado de referencias al género zombie, tanto al cine como a la televisión o los comics.
  • Doctor Ipsum: El Doctor Who también tiene un generador, en este caso además nos permitirá elegir qué encarnación del personaje queremos que hable.
  • Samuel L. Ipsum: El más badass de los generadores, homenajeando a grandes personajes de Samuel L. Jackson. No es muy variado, la verdad, pero tiene su gracia
  • Trollem Ipsum: Elige entre fanboy de Apple, Microsoft, Blackberry o de Android y consigue un texto con sus tópicos «argumentos» fanáticos. Ojo, saca textos cortitos.

En su momento había encontrado un Dalek Generator perfecto para aquellos enganchados al Dr. Who, pero parece que han retirado la web, que antes estaba alojada en esta dirección. Una pena, porque era claramente top. Había originalmente también un generador de conversaciones aleatorias de El Gran Lebowski pero al repasar el artículo me encontré con que ya no existía.

En fin, ahí os queda esta pequeña lista de recursos, para hacer los prototipados un poco menos tediosos.

Función para convertir valores NaN en 0 en Javascript

Vamos como una minientrada sobre Javascript. Hoy trabajaba con varios sumatorios y en algún momento me «rompía» la cuenta porque intentaba acceder al valor de un campo vacío, recibía un valor NaN… El resultado es que toda la cuenta se iba al carajo.

Javascript nativamente nos ofrece una función llamada isNaN() para comprobar si una variable tiene ese valor (en caso de que lo tenga devolverá un true), por lo que sirviéndonos de ella podemos crear una función que nos devuelva un 0 cuando el valor sea NaN. Tal que así:

function NaN2Zero(n){
    return isNaN( n ) ? 0 : n; 
}

Dicha función llama a isNaN para comprobar el valor. En caso de respuesta afirmativa devuelve un 0, en caso contrario devuelve el valor de la variable recibida.

Crear un elemento arrastrable (drag and drop) con jQuery, sin jQuery UI

jQuery UI nos permite definir un elemento como «draggable» para que podamos «agarrarlo» con el ratón para arrastrarlo por la pantalla y situarlo donde mejor nos convenga. Hoy en el trabajo me veía con la limitación de no poder recurrir a jQuery UI, sólo podía utilizar jQuery 1.11 y tenía que lograr el mismo efecto.

Mentiría si dijera que lo hice yo, básicamente cogí este código de CSS-Tricks que os dejo a continuación y le hice un par de pequeños cambios para que funcionara de la forma deseada en la aplicación.

(function($) {
    $.fn.drags = function(opt) {

        opt = $.extend({handle:"",cursor:"move"}, opt);

        if(opt.handle === "") {
            var $el = this;
        } else {
            var $el = this.find(opt.handle);
        }

        return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
            if(opt.handle === "") {
                var $drag = $(this).addClass('draggable');
            } else {
                var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
            }
            var z_idx = $drag.css('z-index'),
                drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;
            $drag.css('z-index', 1000).parents().on("mousemove", function(e) {
                $('.draggable').offset({
                    top:e.pageY + pos_y - drg_h,
                    left:e.pageX + pos_x - drg_w
                }).on("mouseup", function() {
                    $(this).removeClass('draggable').css('z-index', z_idx);
                });
            });
            e.preventDefault(); // disable selection
        }).on("mouseup", function() {
            if(opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle').parent().removeClass('draggable');
            }
        });

    }
})(jQuery);

Tras esto me bastó aplicar esa función sobre los elementos deseados, en ese caso por medio de una clase:

$('.ElementoMovil').drags();

En este caso dad gracias a esa excelente web que es CSSTricks cargada de trucos para mejorar el diseño y la experiencia del usuario, ya que el trabajo es suyo. En el artículo original podéis probar el funcionamiento de dicha función. Añado que en versiones muy antiguas de jQuery no funciona, al menos con 1.5.2 que fue con la que lo probé en principio. En cualquier caso, es recomendable tener siempre esta librería actualizada.

Error 502 Bad Gateway en Nginx. Posibles soluciones

Me han preguntado varios lectores sobre el mismo problema: se encuentran con un error 502, Bad Gateway o puerta de enlace, devuelto por un servidor Nginx. ¿Dónde se produce este error? Pues en el punto en que el servidor Nginx se comunica con otra aplicación o servicio ¿Y por qué se da? Por muchos motivos: que uno de los dos esté caído, que no se «aclaren» con el protocolo (mala configuración), etc. Puede darse cuando Nginx funciona como proxy de Apache, con problemas derivados de la configuración del buffering o del tiempo de espera de respuesta, cuando Nginx funciona como puerta de enlace con otra aplicación o cuando Nginx funciona con el daemon PHP-FPM.

Lo primero, tanto en el caso del daemon de PHP-FPM, como en el de usarlo como proxy de Apache o como puerta de enlace para otro servicio es reiniciar dichos servicios. En la mayoría de los casos el error surge porque el servicio se ha detenido por algún motivo, y con el reinicio se soluciona. En caso de que ocurra reiteradamente entonces investigad por qué ese servicio «casca» de forma tan habitual. Seguramente en los logs del servidor esté mucha de la información que necesitaréis para encontrar la solución.

Aunque la caída del servicio es lo más habitual no es la única opción. En otro artículo ya hablamos de configurar los valores del tiempo para timeout de FastCGI en IIS, en Nngix podemos hacer esto editando el archivo nginx.conf, dentro del bloque http (esto es un ejemplo copiado de la documentación oficial de Nginx, cada caso deberá adaptarse a sus necesidades):

http {
...
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
...
}

En caso de que estéis usando Nginx como proxy deberéis añadir unas líneas como estas en el archivo nginx.conf:

proxy_connect_timeout       600;
proxy_send_timeout          600;
proxy_read_timeout          600;
send_timeout                600;

Para el caso de PHP-FPM debes asegurarte, revisando el fichero http://www.conf de configración de Nginx, de que está bien configurado el puerto en que el servicio debe estar «a la escucha». Generalmente es una de estas dos opciones:

listen = /var/run/php5-fpm.sock
#o si no
listen = 127.0.0.1:9000

Si no está configurado así probad una de esas dos opciones y reiniciad el servicio.

Otra causa de este problema venía derivado del uso de APC Cache, y se solucionaba dejando de usarlo y pasándose a Xcache. De esto hará cosa de un año, puede que a día de hoy ya no genere problemas, pero a saber.

Y a más de uno le ha comenzado el problema tras actualizar algunos paquetes de PHP en su servidor. El problema viene porque en esa actualización los permisos de lectura-escritura-ejecución del socket han sido modificados, y el servidor no puede acceder a ellos porque no está en el mismo grupo. Para solucionar esto tienes que tocar varios archivos. El primero nginx.conf, donde comprobaremos que esto esté tal cual:

user nginx;

Luego nos vamos a /etc/php-fpm.d/www.conf y lo configuramos así

listen = /tmp/php5-fpm.sock
listen.owner = nginx
listen.group = nginx

Y tras esto reiniciamos tanto el servicio de nginx como el de php-fpm.

Estos son los principales problemas y soluciones que he ido encontrando por la red, espero que os sirvan de ayuda.

Netflix disponible oficialmente en Ubuntu

Si bien creo recordar que existían ya algunos programas y extensiones no oficiales que permitía reproducir series y películas desde este popular servicio de streaming, desde ayer es posible hacerlo ya de forma simple y oficial en equipos con Ubuntu (y supongo que también Mint y Debian, pero la verdad es que no he podido comprobarlo ya que no tengo cuenta, entre otras cosas porque la compañía no opera todavía en España).

En cualquier caso, los subscriptores de Netflix sólo tendrán que instalar Chrome 37 (compatible con Ubuntu a partir de 12.04 LTS) desde el paquete .deb oficial de google.

A pesar de ser un servicio que ofrece materiales protegidos por DRM, bajo las draconianas restricciones de derechos de autor habituales, la llegada de Netflix a Ubuntu era esperada por muchos usuarios que se veían condenados a tener una partición con Windows, o a recurrir a la virtualización.

Filosóficamente, como con la llegada de Steam hace unos meses, nos vemos en una encrucijada y un fuerte debate sobre la conveniencia o no de la llegada de plataformas de contenidos privativos a un sistema libre. Por una lado suena a rendirse y a hacer concesiones a la industria del copyright, por otro lado es una forma de lograr que los usuarios pierdan el miedo a dar el salto.

20 años de W3C

El World Wide Web Consortium (o W3C para los amigos) cumple hoy 20 años. Dicho consorcio se encarga de elaborar las recomendaciones para los estándares en el mundo de la web.

Fue fundado, y todavía es dirigido, por Tim Berners-Lee en el MIT tal día como hoy en 1994, con colaboración de la Comisión Europea y el conglomerado militar estadounidense DARPA (lo cual siempre ha generado bastante recelo por los orwellianos proyectos de esta agencia). Desde entonces han trabajado por mantener una versión standar de HTML y otras tecnologías web, a pesar de los intentos de varios compañías de intentar imponer su modelo (principalmente Microsoft). El lenguaje HTML fue desarrollado por Berners-Lee en el CERN, organismo que también decidió que la World Wide Web debía ser libre para todo el mundo, por lo que se le ofreció ser el anfitrión europeo de la W3C, invitación que declinaron por decidir centrarse más en la física que en las tecnologías de la información.

Primer Servidor WEB CERN
El equipo que Berners-Lee usó como primer servidor web de la historia

Tal día como hoy toca felicitar a esta organización por sus 20 años de trabajo pero también, en estos tiempos oscuros en que los lobbies presionan a los gobiernos para acabar con la libertad y neutralidad de la red, es un buen momento para recordarles que las tecnologías web deben seguir siendo libres, que no queremos ningún DRM en HTML5 y que pueden mandar a todos los lobbistas que presionan para que así sea a la EME (perdón por el chiste malo). Porque más que nunca necesitamos una web que sea libre y neutral, y eso pasa porque la tecnologías para desarrollarla también lo sean.