El primero de ellos es la modularización del código en base a plugins. El otro es la introducción del unit-testing y del desarrollo dirigido por tests.
Hoy voy a escribir sobre los plugins, por qué me he decidido a replantear mis aplicaciones con ellos y qué detalles he descubierto que hay que tener en cuenta para hacerlos funcionar bien.
Modularizar con plugins
Una queja habitual de la estructura de CakePHP es que no se pueden organizar los modelos, controladores y vistas de forma significativa, pues todos los modelos tienen que ir juntos en su carpeta, al igual que todos los controladores, etc.
Los plugins nos permiten abordar ese problema ya que con ellos agrupamos los modelos, controladores y vistas (y sus extensiones) que guarden alguna relación. Cada plugin es como una mini-aplicación CakePHP y en su interior reproduce su estructura general.
Los plugins pueden ser bastante autocontenidos, de modo que es sencillo reutilizarlos en nuevos proyectos. Supongamos, por ejemplo, que hemos creado un sistema de gestión de usuarios y grupos con el que nos encontramos muy a gusto. Si lo tenemos como plugin, tan sólo debemos copiar la carpeta que lo contiene en la nueva aplicación para disponer de toda la funcionalidad.
En cambio, si no está en forma de plugin, es más fácil perder la pista de algún archivo a la hora de copiarlo, en especial si se manejan varios modelos, etc.
Mi objetivo al usar plugins
Pues mi objetivo es muy sencillo. Se trata de tener "piezas" de código relativamente independientes que puedan servir para montar una diversidad de aplicaciones. De este modo dispondré de una especie de "superframework" con módulos reutilizables. Cada aplicación o proyecto tendría partes propias, y partes comunes. De este modo, al avanzar en uno, estoy contribuyendo a otros. Y, por otro lado, me puedo concentrar en el núcleo de una aplicación específica.
Y en caso de trabajar en equipo, es fácil distribuir el trabajo.
Por otra parte, los plugins son también una buena manera de crear bibliotecas de behaviors, components o helpers, que puedan reutilizarse en varios proyectos. Lo bueno, es que puedes agruparlos por algún criterio útil. Por, ejemplo, una biblioteca de helpers relacionados con la interfaz de usuario. O un módulo con un behavior para añadir comentarios a cualquier otro objeto, que incluye la gestión de los mismos.
Creando un plugin
Lo mejor es utilizar cake bake para crear la estructura básica del plugin.
cake bake plugin nombre_del_plugin
Lo más importante a tener en cuenta es que los modelos y controladores dentro de un plugin no deberían descender de AppModel o de AppController, sino indirectamente, a través de AppPluginModel o AppPluginController. Cake Bake se ocupa de eso por nosotros.
También podemos generar modelos y controladores básicos mediante cake bake
cake bake plugin NombreDelPlugin model NombreDelModelo
Accediendo a las acciones de un plugin
Las URL que nos llevan a un plugin son las típicas de cake prefijadas con el nombre del plugin:
/plugin/controller/action/param
Como, por ejemplo:
/content/posts/edit/first_post
/admin/tickets/tickets/edit/123
Como puedes ver, también es posible usar el admin routing con plugins.
Por otra parte, es perfectamente posible llamar a las acciones de los plugins con RequestAction.
Creando URL
En el caso de que crees las URL para link o redirect con el formato array, debes incluir la clave 'plugin' con valor true.
array('admin' => true, 'plugin' => true, 'action' => 'index')
Asociaciones con modelos dentro de un plugin
Cuando necesitamos asociar un modelo con otro que está en un plugin, tenemos que indicárselo. Puede ser en la forma simple:
var $hasMany = array('Plugin.Modelo');
O si tienes que especificar parámetros de la asociación, incluyendo la clave
'className' = 'Plugin.Modelo',
Recuerda que ésta, y las demás indicaciones, se aplican incluso cuando los modelos asociados están en el mismo plugin.
Usando behaviors, components o helper de un plugin
Decláralos como siempre, añadiendo antes el nombre del plugin, como en este ejemplo:
var $actsAs = array('Comments.Commentable);
Usando elementos de un plugin
Entre los parámetros que pasamos al elemento, hay que indicar la clave 'plugin' y el nombre del plugin.
element('ejemplo', array('plugin' => 'el_plugin')); ?>
Importando modelos o controladores
Hay que indicar el nombre del plugin, para que importe el objeto correcto.
App::import('Model', 'Plugin.Model');
App::import('Controller', 'Plugin.Controller');
Testing con plugins
Algunas cosas que he observado que es necesario tener en cuenta son:
Los controladores que usamos para testar deben incluir el parámetro plugin (gracias a Mark Story)
class TestPostsController extends PostsController {
var $plugin = 'Content';
}
Y hay que tener en cuenta el apartado anterior para importar los objetos que estén en plugins.
La declaración de las fixtures, también lo tiene en cuenta:
var $fixtures = array('plugin.content.post);
El test suite de CakePHP trata cada plugin aisladamente, lo que resulta muy cómodo y casi te evita tener que hacer grupos de tests por funcionalidad u otro criterio.
Shells
Puedes empaquetar shells en plugins. Crea la ruta vendors/shell dentro de la carpeta del plugin que se trate y pon ahí los shells que desees. La utilidad de línea de comandos cake sabrá acceder a ellos.
Por supuesto, hay más información en el Cookbook.