miércoles, 26 de septiembre de 2012

Mosaico de imágenes


Hay muchas maneras de optimizar tu página haciendo un tratamiento de las imágenes, una de ellas es la de reducir un grupo de imágenes en una sola creando así un mosaico.


Por medio de css podremos mostrar dichas imágenes de la forma en que lo necesitemos.

Una posible práctica sería la de una lista de enlaces (con imagen) que al pasar el ratón sobre ellos cambien a otra imagen.

Como ejemplo usaremos una plantilla con las siguientes dimensiones:















Para ello dispondremos de un mosaico con parejas opuestas.
En la fila inferior la lista de imágenes en blanco y negro.
Y en la fila superior la misma lista de imágenes, esta vez a color.
Es importante que las dos filas mantengan las mismas proporciones.

<div id="mosaico">
  <div class="enlace1">
    <a href="#">
      <span class="enlace1"></span>
    </a>
  </div>
  <div class="enlace2">
    <a href="#">
      <span class="enlace2"></span>
    </a>
  </div>
  <div class="enlace3">
    <a href="#">
      <span class="enlace3"></span>
    </a>
  </div>
</div>

En el código html anterior hay una lista de elementos "span" encapsulados en "div", ambos compartiendo una misma clase ("enlace1", "enlace2", "enlace3").
Y todo el conjunto anterior a la vez contenido en un div con un identificador ("mosaico").

.enlace1, .enlace2, .enlace3 {
  background-image: url('../img/mosaico.png');
  background-repeat: no-repeat;
  height: 100px;
  float: left;
}
#mosaico div {
  background-position-y: -100px;
}
#mosaico span:hover {
  opacity: 1;
}
#mosaico span {
  opacity: 0;
  -webkit-transition: opacity 0.5s ease-in-out;
  -moz-transition: opacity 0.5s ease-in-out;
  -o-transition: opacity 0.5s ease-in-out;
  transition: opacity 0.5s ease-in-out;
}
#mosaico span:hover {
  opacity: 1;
}
.enlace1 {
  background-position-x: 0px;
  width: 100px;
}
.enlace2 {
  background-position-x: -100px;
  width: 120px;
}
.enlace3 {
  background-position-x: -220px;
  width: 80px;
}

En el css anterior comenzamos aplicando el mismo fondo para cada una de las clases, es decir, los elementos "div" y "span" dentro del contenedor principal.
Además especificamos la altura de la imagen y flotamos el contenido (derecha o izquierda).

Asignamos una posición vertical a los elementos "div" cuyo valor será la altura de la imagen con valor negativo (en este caso -100px).

Los "span" por defecto están ocultos y solamente los mostramos cuando pasamos el ratón sobre las imágenes (con una transición de css3).

Por último asignamos un ancho para cada una de las imágenes a través de sus clases (.enlace1, .enlace2, ... ) y variamos su posición horizontal acumulando en valor negativo el ancho de las imágenes que están a su izquierda en el mosaico.

lunes, 24 de septiembre de 2012

La CheatSheet de PHP

Hoy @Manz nos comparte una de sus obras, ni más ni menos que una cheatsheet de PHP.


¿Es posible hacer una cheatsheet completa de algo tan amplio? Comprobadlo vosotros mismos:
http://www.emezeta.com/weblog/emezeta-php-card-v0.2.png

lunes, 10 de septiembre de 2012

dataProviders en PHPUnit

Hoy vamos a hablar de dataProviders en PHPUnit .

Un dataProvider es una función que permite definir un conjunto de casos para un mismo test. Son perfectos para hacer pruebas unitarias de valores límite. Veamos un ejemplo en código:


    /**

    * @dataProvider sum_samples
    */
    public function test_sum(
      $number1,
      $number2,
      $expectedSum
    ) {
      $this->assertEquals(
        $expectedSum,
        $number1 + $number2
      );
    }

    public static function sum_samples(
    ) {
      return array(
        array( 0, 0, 0 ),
        array( 0, 1, 1 ),
        array( 1, 0, 1 ),
        array( 1, 1, 2 ),
        array( 3, 4, 8 )
      );
    }


Observemos ciertas reglas a cumplir:

  • Un test se asocia con un dataProvider mediante la anotación @dataProvider
  • El método provider debe ser público y estático 
  • El método provider debe devolver un array de arrays o un Iterator sobre arrays; cada subarray es un caso de test y debe contener tantos elementos como parámetros tenga el test 

Nombrar los casos de test

Si al array que devuelve el provider se le ponen claves, éstas son utilizadas en los mensajes de error en caso de que el test falle, por lo que puede ser útil “nombrar” los casos en estas claves. Por ejemplo, si el anterior provider lo escribimos así: 


    public static function sum_samples( 

    ) { 

      return array( 
        "Null values" => array( 0, 0, 0 ), 
        "Null & not null" => array( 0, 1, 1 ), 
        "Not null & null" => array( 1, 0, 1 ), 
        "Not null values (a)" => array( 1, 1, 2 ), 
        "Not null values (b)" => array( 3, 4, 8 ) 
      ); 
    }


El resultado de pasar los tests será:


    There was 1 failure: 
    1) SampleProviderTest::test_sum with data set "Not null values (b)" (3, 4, 8) 
    Failed asserting that <integer:7> matches expected <integer:8>. 


Fijémonos que en este ejemplo he distinguido dos casos “Not null values (a)” y “Not null values (b)”. Es importante darse cuenta de que estamos usando las claves de un array asociativo para nombrar los casos, y que si escribimos dos claves iguales estaremos sobrescribiendo un caso (y lo peor, no nos daríamos cuenta, ya que el código funcionaría, pero ejecutaría 4 tests en lugar de 5).


¿Cuándo se ejecutan los providers?

Aquí va un consejo de esos que es mejor no tener que aprender de la propia experiencia: los dataProviders se ejecutan una sola vez, antes incluso que el setUpBeforeClass(). Puede parecer una tontería de consejo y de hecho lo es para casos tan sencillos como el ejemplo que hemos mostrado, pero aquí va un ejemplo algo más real:

    class AppUserTest extends PHPUnit_Framework_TestCase {

      private $app = null; 

      public static function setUpBeforeClass( 
      ) { 
        self::$app = new App(); 
      

      /** 
      * @dataProvider validData
      */ 
      public function testUserCanLogin( 
        $validName, 
        $validPass 
      ) { 
        $anUser = new AppUser($validName, $validPass); 
  
        $this->assertTrue($anUser->login()); 
      

      public static function validData( 
      ) { 
        $validData = array(); 
        foreach (self::$app->getSampleValidUsers() as $user) { 
          $validData []= array( 
            $anUser->getName(), 
            $anUser->getPass() 
          ); 
        
        return $validData; 
      

    } 


¿Veis el problema?

Efectivamente, tenemos un provider con una dependencia inválida. Dicho provider necesita leer ciertos datos de una cierta entidad ‘global’ (self:$app), pero esta necesita ser inicializada en setUpBeforeClass(). Estamos ante una situación imposible: un provider no puede depender de nada inicializado en setUpBeforeClass(), porque se ejecuta antes que dicha función. Tenedlo en cuenta ;-)

Lo más ‘escalofriante’ es que en un conjunto de tests los providers se ejecutan antes que cualquier setUpBeforeClass(), aunque sea de otro test!

La siguiente prueba lo ilustra:

    <?php

    # File: PhpUnitOrderTest.php 

    class PhpUnitOrderTest extends PHPUnit_Framework_TestCase { 

      public static function setUpBeforeClass( 
      ) { 
        echo "TestCase #1 - setUpBeforeClass()\n"; 
      } 

      public static function tearDownAfterClass( 
      ) { 
        echo "TestCase #1 - tearDownAfterClass()\n"; 
      } 

      public function setUp( 
      ) { 
        echo "TestCase #1 - setUp()\n"; 
      } 

      public function tearDown( 
      ) { 
        echo "TestCase #1 - tearDown()\n"; 
      } 

      /** 
      * @dataProvider sampleProvider 
      */ 
      public function testSample( 
        $param
      ) { 
        echo "TestCase #1 - testSample()\n"; 
        $this->assertTrue($param); 
      

      public static function sampleProvider( 
      ) { 
        echo "TestCase #1 - sampleProvider()\n"; 
        return array( 
          "#1" => array( 1 == 1 ), 
          "#2" => array( 2 != 1 ), 
        ); 
      

    } 


    <?php 

    # File: OtherTest.php

    class OtherTest extends PHPUnit_Framework_TestCase { 

      public static function setUpBeforeClass( 
      ) { 
        echo "TestCase #2 - setUpBeforeClass()\n"; 
      

      public static function tearDownAfterClass( 
      ) { 
        echo "TestCase #2 - tearDownAfterClass()\n"; 
      

      public function setUp( 
      ) { 
        echo "TestCase #2 - setUp()\n"; 
      

      public function tearDown( 
      ) { 
        echo "TestCase #2 - tearDown()\n"; 
      

      /** 
      * @dataProvider sampleProvider 
      */ 
      public function testSample( 
        $param
      ) { 
        echo "TestCase #2 - testSample()\n"; 
        $this->assertTrue($param); 
      

      public static function sampleProvider( 
      ) { 
        echo "TestCase #2 - sampleProvider()\n"; 
        return array( 
          "#1" => array( 1 == 1 ), 
          "#2" => array( 2 != 1 ), 
        ); 
      

    } 


La salida de PHPUnit:

    TestCase #2 - sampleProvider() 
    TestCase #1 - sampleProvider() 
    PHPUnit 3.5.15 by Sebastian Bergmann
    .TestCase #2 - setUpBeforeClass() 
    TestCase #2 - setUp() 
    TestCase #2 - testSample() 
    TestCase #2 - tearDown() 
    .TestCase #2 - setUp() 
    TestCase #2 - testSample() 
    TestCase #2 - tearDown() 
    .TestCase #2 - tearDownAfterClass() 
    TestCase #1 - setUpBeforeClass() 
    TestCase #1 - setUp() 
    TestCase #1 - testSample() 
    TestCase #1 - tearDown() 
    .TestCase #1 - setUp() 
    TestCase #1 - testSample() 
    TestCase #1 - tearDown() 
    .TestCase #1 - tearDownAfterClass() 

 Time: 0 seconds, Memory: 3.50Mb OK (4 tests, 4 assertions) 



¿Os fijáis en los providers apareciendo antes incluso del mensaje inicial de PHPUnit? ;-)


viernes, 7 de septiembre de 2012

¿Cuál es el mejor editor de PHP?

Una tema de debate casi siempre polémico entre programadores es el tema de los IDEs, especialmente si lo que es pone en cuestión es la siempre ambigua pregunta "¿Cuál es mejor?".

Hace poco en Php Flow veíamos un artículo que analizaba los que según ellos son los 8 mejores editores de PHP disponibles, que son:

  • Dreamweaver
  • Netbeans
  • Eclipse
  • Notepad++
  • Zend Studio
  • PHP Edit
  • Bluefish

Aquí os dejo un link al artículo por si queréis leer una breve descripción de cada editor.

Como este es un artículo de opinión, no quiero dejar la cosa así sin dar mi opinión.

Francamente, me sorprende ver en la lista una mezcla de IDEs específicos de PHP con otros más de propósito general (como Notepad++ o Bluefish) o incluso con otros típicamente diseñados para otras tecnologías (como Eclipse o Netbeans). Históricamente PHP, por sus características (me atrevería a afirmar que concretamente por el hecho de ser un lenguaje interpretado y por el hecho de ser casi siempre utilizado "en mezcla" con otros lenguajes), ha quedado siempre rezagado en el tema de los IDEs. Mientras cada vez aparecían IDEs más potentes para lenguajes como Java o C++, los de PHP se quedaban en el propósito general o potenciaban temas (de diseño web, por ejemplo) no específicos de programación. Cada lenguaje tiene unas características y necesidades diferentes, y comparar IDEs de Java con IDEs de PHP me parece absurdo, igual que me parece absurdo utilizar Eclipse para programar en PHP (cosa que he probado a hacer, como todos).

Yo no sabría dar una respuesta a la pregunta "¿Cuál es el mejor IDE para PHP?". Sinceramente, en mi opinión, para ti será aquel en el que tú y tu equipo estéis más cómodos trabajando. En mi caso, por ejemplo, soy de los que para lenguajes interpretados prefiere IDEs de propósito general, y tal es así que para PHP utilizo vim, editor que por cierto no aparece en la lista, pese a ser "el mejor" ;-)

jueves, 6 de septiembre de 2012

La función mktime()


Todos hemos utilizado la función date() en muchas ocasiones para formatear la fecha actual. Ahora bien, cuando se trata de formatear otra fecha, sabemos que tenemos que pasarle como segundo argumento un timestamp:

        echo date("Y-m-d");             // 2012-09-06
        echo date("Y-m-d", 0);          // 1970-01-01
        echo date("Y-m-d", 9945250000); // 2012-12-12

Pero ¿cómo podemos generar dicho timestamp a partir de una fecha conocida?


Como podemos ver en la documentación oficial, dicha función acepta hasta 7 parámetros opcionales.

En este post de PHP Flow nos dan una buena lección al respecto con muchos ejemplos.

miércoles, 5 de septiembre de 2012

Tip: prueba CodeIgniter

El consejo de esta semana viene de la mano de Roshan Bhattarai, programador PHP cuyo blog recomiendo, que nos explica 4 razones por las que recomienda usar CodeIgniter "incluso en lugar de Zend":

  1. Su rendimiento supera al de la mayoría de frameworks MVC PHP.
  2. Tiene una curva de aprendizaje muy suave, por lo que es recomendable para principiantes.
  3. Las convenciones de código son simples y flexibles (a diferencia de CakePHP, por ejemplo, donde tienes que preocuparte por el uso de las mayúsculas mientras programas).
  4. Incluso si prefieres beneficiarte de las muchas librerías de clases de Zend, las puedes utilizar con CodeIgniter (como el link que deja Roshan al respecto está roto, yo os sugiero este otro).
Si queréis ver la "versión larga" de este consejo os recomiendo el artículo original en el blog de Roshan.

martes, 4 de septiembre de 2012

1st Moodle Research Conference

Los próximos días 14 y 15 de septiembre tendrá lugar en Creta la Primera Conferencia de Investigación en Moodle, un gran evento que reunirá a educadores, investigadores, expertos y profesionales, con la intención de compartir experiencias, logros y desarrollos innovadores con Moodle.

El programa del evento incluye multitud de sesiones breves y un panel de debate, que cubren tópicos como modelos de aprendizaje, casos de aplicación de Moodle, análisis de estadísticas o accesibilidad.

Aunque ya no están disponibles las entradas "early bird" desde el 17 de Julio, todavía se puede uno registrar en el evento.

Mas información en la página del evento.