Español

Custom Find DRY

Una de las cosas que más me gusta de los custom find en CakePHP es la flexibilidad que pueden proporcionar a partir de una sintaxis única y sencilla.Recientemente me he dado cuenta de cómo usarlos para evitar duplicaciones innecesarias de código.Como ya sabrás, un método para custom find tiene esta signatura básica:function _findCustom($state, $query, $results = array())Este método se llamaría públicamente así$model->find('custom' [, $options]);La llamada $model->find('custom') hace, a grandes rasgos, lo siguiente:

PHP bug ?

<?php
$price = 125.99;
$dec = ($price - intval($price)) * 100;
$dec = (int) $dec;
echo $dec; // WTF?!

Custom find en Behaviors

Trabajando en un Behavior me surgió la pregunta de si es posible definir Custom Finds en un Behavior para que sean usados por el modelo.El caso es que encontré este código de Nick Baker, en el cual se encuentra una técnica para lograrlo. Una vez vista es obvia (pero había que verla, claro). Copio el código de Nick para explicarlo. En este caso, define una búsqueda que será find('range'), para lo cual hay que crear un método _findRange() en el Behavior.La técnica tiene dos pasos:El primero es mapear el método del behavior con un método para el modelo, lo cual se hace con la siguiente línea en las propiedades del Behavior:var $mapMethods = array('/^_findRange$/' => '_findRange');En el método setup hay que añadir la una clave al array de _findMethods del modelo que se pasa:

Parámetros de URL y paginator

Debo decir que odio tener que comenzar esta entrada con el típico: "siento haber estado tanto tiempo sin escribir", pero razones de todo tipo me han mantenido alejado del blog, no siempre de manera muy justificada. Quiero decir, que probablemente mejor me hubiera ido escribiendo aquí que dejando pasar el tiempo sin hacerlo y sin tener la oportunidad de compartir aunque sólo fuesen pequeños trozos de código como el que traigo hoy.En fin, para volver a la buena senda, he aquí cómo me las apaño para resolver un problema típico:Tenemos una vista de registros paginada, con la más o menos típica tabla, con sus cabeceras "clicables" para ordenar los registros y sus botones para cambiar de página.También tenemos un problema: ¿cómo conservar todos los parámetros que vienen en la URL en los enlaces relacionados con la paginación? Pues, la verdad es que es bastante sencillo:$options = array(

Campos LONGTEXT de MySQL y las Schema Migrations de CakePHP

Ultimamente ando un poco vago para escribir en este Blog, pero hoy me encontré con un caso/problema/solución que me parece que vale la pena compartir con uds.

Estaba trabajando con las migraciones de esquemas de CakePHP y me encontré con que el shell "schema" no distingue los tipos de columna LONGTEXT de MySQL, omitiendo las variantes de este tipo de columna y unificandolos a todos como 'text'.

He desarrollado una solución, más o menos elegante, para que los comandos "create" y "update" del schema shell reconozcan este tipo de dato. Todavía no encuentro una forma "no-intrusiva" de hacerlo para el comando "generate".

Básicamente, se trata de hacer un nuevo Data Source de CakePHP, pero en vez de extender la clase base, extender del DboMysql y solo implementar el array de tipos de datos del motor.

CakePHP y Javascript

En principio, no necesitas hacer nada especial para incorporar código javascript en las vistas de tu aplicación CakePHP, aparte de escribir el código, naturalmente. Simplemente has de insertarlo tal y como lo harías en cualquier documento HTML: utilizando la etiqueta script. // CódigoPor supuesto, en algún momento necesitarás utilizar scripts que se encuentren en archivos .js, convenientemente guardados en la carpeta js del webroot de tu aplicación. Para esta tarea es buena idea recurrir a HtmlHelper en CakePHP 1.3 (o a JavascriptHelper en la versión 1.2), ya que lo enlazará correctamente incluso si tu instalación de Cake está muy personalizada.Por ejemplo:<?php echo $this->Html->script('jquery.form', array('inline' => false)); ?>o bien

Javascript y Ajax para torpes (como yo)

Tengo que confesar que tengo un problema con Javascript. Me cuesta mucho entender este lenguaje y, por tanto, utilizarlo. Claro que, a día de hoy, es ya una herramienta imprescindible.Gracias a una parte del proyecto en el que estoy ahora mismo trabajando he tenido que empezar a plantearme en serio el uso de javascript en la aplicación y como parte de ese aprendizaje voy a dejar caer por aquí algunas anotaciones al respecto.Esta primera anotación no es un tutorial, sino más bien una clarificación de conceptos sobre el lenguaje en sí, Ajax y otros temas relacionadas. Así que vamos allá:JavascriptPara más información consulta la entrada Javascript en Wikipedia.

HTML5 reset

Se trata de todo un paquete completo de archivos html, css y javascript con los cuales iniciar un proyecto desarrollado en HTML 5, compatible con Internet Explorer.Tiene muy buena pinta para empezar y no parece muy difícil de integrar en CakePHP.HTML5 Reset

Hacer tests de un método que crea un objeto que debemos simular (una alternativa a los partial Mock)

Supongamos que tenemos un método en una clase y que dentro de ese método se crea un objeto, el cual debemos simular para hacer el test. Algo así como esto:public function getFeed($url) {    $Socket = ClassRegistry::init('HttpSocket');    $Socket->reset(false);    $response = $Socket->get($url);    ...}

Simulando objetos con Mock Objects

Entre otras facilidades, la Test Suite de CakePHP utiliza la capacidad de SimpleTest de crear Mock Objects, o lo que es lo mismo, simulaciones de objetos que no hacen nada, pero que reproducen todos los métodos de los objetos simulados y que puedes programar para que tengan un comportamiento determinado que te interese.Esto es útil cuando quieres probar una clase que usa otras clases. En lugar de emplear las clases reales, utilizamos sus simulaciones. De este modo, nos evitamos las posibles interferencias de su funcionamiento sobre los resultados del test y garantizamos que sólo probamos el código de la clase en cuestión.Un ejemplo sencillo típico sería tratar de probar un Controller que usa un Component.Lo que tenemos que hacer son básicamente dos cosas:

  • Crear una simulación o Mock del Component
  • Asociar el Component simulado al Controller

BeforeRedirect

Un recordatorio por si usas el callback beforeRedirect en un Component: recuerda que debe devolver una URL, de otro modo los resultados pueden ser absolutamente desquiciantes.

Model->displayField en plugins

Al menos en CakePHP 1.3 (me imagino que puede pasar en 1.2) la propiedad displayField de los modelos puede tener un comportamiento un poco errático si te has olvidado de especificar correctamente las relaciones con modelos que están en plugins.En otras palabras. Si tienes un modelo relacionado con otro que se encuentra en un plugin, no olvides indicarlo "prefijándolo" con el nombre del plugin. Por ejemplo, si tienes un modelo que tiene una relación hasMany con el modelo Item que está en el plugin Contents debes expresarlo así:var $hasMany = array('Item' => array('className' => 'Contents.Item'));Si no lo haces, métodos como find('list') no serán capaces de usar correctamente la propiedad displayField del modelo relacionado.

Yo, la autorización y Cake (II): Entendiendo los sistemas de autorización

Sistemas de permisos "a la Unix"Una forma de afrontar al problema de la autorización es partir del sistema de permisos Unix. En este sistema, cada recurso tiene asociados varios permisos (lectura, escritura, ejecución) que se asignan a un usuario, a un grupo y al resto del mundo. Es bastante fácil empaquetar estos permisos en un sólo atributos y chequearlos usando operaciones binarias (and, or...).Puedes incorporar esta información de permisos en la propia tabla del modelo que quieres controlar, o normalizarlo y guardar la información en una tabla de permisos, lo que te permite hacerlo más flexible.La dificultad puede estar en cómo relacionar esta información de permisos con las acciones de los controladores de tu sistema. Una opción es a través de un mapeado acción-tipo de permiso, o bien creando un permiso específico para cada acción.

Yo, la autorización y Cake (I)

Una de las bases de una aplicación corporativa es un buen sistema de autentificación y de autorización. Este último es uno de los aspectos que me resulta más complicado resolver al desarrollar una aplicación. Hasta ahora mis soluciones en este campo han sido funcionales, pero difíciles de mantener y de escalar.Conceptualmente son procesos bastante sencillos de entender:Autentificación es el proceso por el que el sistema determina que un usuario es quien dice ser, o por lo menos que presenta las credenciales correctas. Un sistema de autentificación básicamente toma las credenciales aportadas (habitualmente un usuario y contraseña) y las contrasta con alguna fuente de referencia, que puede ser una tabla de una base de datos, un servidor de autentificación, etc.

Forzar la actualización de un registro de un Model

Mi vida como desarrollador es un poco caótica, ya que no me dedico a tiempo completo y últimamente otras demandas me quitan montones de tiempo y toneladas de concentración. Por eso, a pesar de llevar trabajando con CakePHP desde hace ya un par de años, tengo dudas en conceptos básicos o tengo que empezar desde cero con algunos proyectos ya que "pierdo el hilo".Un ejemplo de estos conceptos básicos que tenía dudosos es lo que pasa cuando creas registros en un modelo y cuando manipulas sus id.Cuando haces un Model->save() sin indicar un id para el modelo, se crea un nuevo registro. Por tanto, para actualizar un registro existente debes indicar un id.Esto lo puedes hacer tanto en la propiedad Model->id, como en el array de datos que pases a create o a save. Por ejemplo:array('Model' => array('id' => 12));Además, se siguen unas cuantas reglas más:

Pregunta abierta: ¿conoces alternativas a getID3?

Funciona bien y td eso, ¿pero conoces alguna alternativa para extraer metadatos de archivos multimedia?

Obtener la extensión de un archivo

Esta línea nos proporciona la extensión de un archivo conociendo su nombre o su path$extension = substr($filename, strrpos($filename, '.') + 1);

Valores por defecto para parámetros de un Element

Esta es una técnica sencilla que nos servirá para definir valores por defecto (y también documentarlos) para los parámetros que pasamos a un element.Como sabrás, los parámetros pasados a los element, están disponibles como variables en el mismo. La idea es definir un array asociativo con los valores por defecto y luego extraer las claves a variables.El quid de la cuestión es usar el parámetro EXTR_SKIP para que extract no extraiga del array los parámetros que han sido pasados. Es decir, en caso de conflicto, el Element debe quedarse con el parámetro pasado y si no ha sido pasado, toma el valor por defecto.Esto nos evita una serie de if(isset(...)), y hace muy legible el código y muy fácil documentar los parámetros del Element.$defaults = array(    'channel' => false,    'count' => 1,    'mode' => 'public',    'type' => 'full'    );  

CakePHP, MAMP y el socket de Mysql (actualizado)

ActualizaciónComo comenta Nigeon, basta con poner el path al socket en el parámetro port de la configuración de la conexión.Al que, por cierto, viene documentado en el manual.'connect' => 'mysql_connect','host' => 'localhost','port' => '/Applications/MAMP/tmp/mysql/mysql.sock',Dejo la entrada anterior porque puede ser útil en algunos casos.En una entrada anterior ya he comentado el tema de como ajustar las cosas para que CakePHP pueda comunicarse con Mysql. Para ello, hay que crear un enlace simbólico del socket /Applications/MAMP/tmp/mysql/mysql.sock en el lugar adecuado, que en el artículo señalado era /var/mysql/mysql.sock.

Validación: comparar con otro campo

En la validación de datos de formularios, muchas veces nos gustaría comprobar que dos campos coinciden, como pueden ser los casos de contraseñas, emails, etc.Para ello, en los formularios ponemos un segundo campo similar al que queremos comparar a fin de que el usuario introduzca dos veces el valor. Así, por ejemplo, tendríamos el campo User.password y el campo User.confirm_password, o bien User.emal y User.confirm_email.Yo recomendaría que en el formulario usaras los campos de confirmación como si fuesen campos del modelo. A la hora de guardar (save), CakePHP los va a ignorar pues no están en el schema del modelo y nos resulta bastante fácil manipularlos.No hay una regla de validación por defecto para esto, así que me he escrito mi propio método match para hacerlo.La comparación de contraseñas

Syndicate content