Module Structure

From IHRIS Wiki

Este tutorial describe la Estructura del Módulo de iHRIS. Un módulo de iHRIS es una colección de varios tipos de "código" por las características que proporcionan al sistema. Estos módulos pueden ser parte del sistema core I2CE y manejar cosas como la autenticación de usuarios o el acceso a bases de datos, también pueden brindar nueva funcionalidad a iHRIS como por ejemplo el manejo de permisos.


¿Qué es un Módulo?

La Suite iHRIS está basada en el Intrahealth Informatics Core Engine (I2CE) que utiliza una estructura de modulo para encapsular y mantener el "código" en piezas manejables organizadas de acuerdo a la funcionalidad que proporcionan. Al decir "código" nos referimos a la colección entera de php, html, javascript, xml, archivos de imágen, css, flash, etc, que proporcionan la funcionalidad de una aplicación de red.


Un modulo está versionado para llevar un registro de los cambios a la funcionalidad y el API que tiene un módulo.

¿Por qué los módulos?

  • La razón más importante para utilizar un sistema de módulos es la de aumentar la facilidad de manejo del código. Los muchos components de la Suite iHRIS (Qualify, Manage, y Plan) se utilizan en una variedad de escenarios que requieren sus propias personalizaciones.
  • Cada uno de los components de la Suite iHRIS (Qualify, Manage, Plan) comparten algunas funciones communes y el sistema de módulos asegura la reutilizacion de códigos de manera adecuada.
  • El sistema de módulos permite encapsular varias personalizaciones sin tener que cambiar el código base subyacente. Esto permite que un desarrollador local pueda realizar sus cambios sin preocuparse por tener que rehacer esos cambios cada vez que se actualice el sistema core.
  • Ya que los módulos están organizados de acuerdo a la funcionalidad que brindan al sistema, un desarrollador puede encontrar rapidamente los códigos relevantes que Deben cambiarse solo con ver los módulos relevantes.
  • Las personalizaciones al software encapsuladas en un modulo pueden compartirse fácilmente entre desarrolladores.

El Módulo I2CE

Este es el modulo "top"-most. Cada módulo tiene esto como requisito de manera implícita. El módulo central el que brinda la funcionalidad mínima incluyendo datos magic, búsqueda de archivos, el sistema de plantillas y la fábrica de módulos. No tiene requisitos.

I2CE proporciona varios sub-módulos opcionales. Por ejemplo:

  • Admin -- Proporciona un sistema de manejo de módulos.
  • Proceso de Fondo -- Proporciona una plataforma independiente con los medios para lanzar y monitorear procesos de fondo
  • Reportes Personalizados -- Proporciona la funcionalidad de Reportes Personalizados
  • Gráficos Flash -- proporciona una interfaz para el sistema de maani flash charting
  • Formularios -- proporciona la estructura básica de formularios y campos que utiliza nuestro software
  • MooTools -- proporciona una interfaz php a la libreria de javascript MooTools
  • Tareas y Roles -- proporciona un sistema de manejo basado en tareas para los roles de los usuarios

El Módulo del Sitio

El modulo "bottom"-most es el Módulo del Sitio. Este modulo es el que se carga con el archive index.php y le dice al sistema que módulos utiliza su sistema. Es el lugar apropiado para realizer personalizaciones básicas al sistema, por ejemplo, cambiar la imágen que se muestra en la página de inicio o para mostrar el nombre de su organización. Vea por ejemplo Customizing iHRIS Manage

Archivo de Configuración de Módule

Un modulo esiste al definer sus archivos de configuración. Hay un nodo de top-level <I2CEConfiguration> bajo el cual hay dos posibles nodos:

La etiqueta <I2CEConfiguration> tiene un atributo requerido nombre cuyos valores deben ser un nombre corto único para describer este modulo tal como I2CE, ihris-manage o mercury_javascript_popup. El DTD que describe el format del arcivo de configuración esta ubicado en I2CE/lib/I2CE_Configuration.DTD. Como ejemplo:

<?xml version="1.0"?>  
<!DOCTYPE I2CEConfiguration SYSTEM "I2CE_Configuration.dtd">
<I2CEConfiguration name='mercury_javascript_popup'>     
  <metadata>
    Some stuff defined below 
  </metadata>
  <configurationGroup name='mercury_javascript_popup'>
    Some stuff defined below 
  </configurationGroup>
</I2CEConfiguration>

metadata

La etiqueta de DTD para <metadata> permite los siguientes nodos:

<!ELEMENT metadata (displayName,className?,category?,description?,creator?,email?,link?,
  version,(enable|requirement|conflict|path)*,priority?)>

En su mayoría, el orden de estas etiquetas es importante debido a las limitaciones en la estructura de los DTDs. Las excepciones son que las etiquetas de <permitidos>, <requeridos>, <conflictos> y <ruta> pueden enlistarse en cualquier orden entre ellos.

displayName

Esta etiqueta se require que sea el nombre de este modulo humanamente legible que se muestra, por ejemplo, en el Configure Modules pa

Ejemplo: <displayName>Popup Box</displayName>

className

La etiqueta es opcional y asocial una clase para el modulo. Vea #The Module Class para obtener información específica acerca de la clase del módulo

Ejemplo: <className>I2CE_Module_JavascriptPopup</className>

category

Esta es una etiqueta opcional que se utiliza para agrupar módulos similares por categoría en la pñagina deConfigure Modules.

Ejemplo: <category>Javascript Library</category>

description

Esta es una etiqueta opcional que da una descripción de este módulo que se muestra en la página de Configure Modules .

Ejemplo: <description>Provides a javascript popup box</description>

creator

Esta es una etiqueta opcional que muestra al creador en la página de Configure Modules.

Ejemplo: <creator>Freddy Mercury</creator>

link

Esta es una etiqueta opcional que proporciona un URL para el modulo en la página 'Configure Modules .

Ejemplo: <link>http://en.wikipedia.org/wiki/Freddie_Mercury</link>

version

Esta es una etiqueta requerida que se puede utilizar para versionar su módulo.

Ejemplo: <version>1.0.0</version>

requirement

Esta es una etiqueta opcional, de la cual puede tener cuantas quiera. Cada etiqueta debe tener el nombre del atributo cuyo valor es el nombre de un módulo requeirdo por este módulo. Esta etiqueta puede tener hasta cuatro sub-etiquetas posibles:

  • atLeast
  • atMost
  • lessThan
  • greaterThan

cada una de las cuales deben tener la version del atributo con un valor de una versión del modulo. Como ejemplo:

<requirement name='I2CE'>
 <atLeast version='3.1'/>
 <lessThan version='3.2'/>
</requirement>

dice que nuestro módulo require que I2CE tenga la versión al menos 3.1 y una menor que la versión 3.2.

Para que el módulo cargue, debe complir con todos los requerimientos satisfactoriamente.

conflict

Esta es una etiqueta opcional de la cual se puede tener cuantas desee. Esto es opuesto a la etiqueta <requirement> y enumera todos los módulos con los que este mñodulo tiene conflictos. Por ejemplo:

<conflict name='plant_javascript_popup'>
</conflict>
<conflict name='ringo_javascript_popup'>
  <lessThan version=3.2/>
</conflict>

Dice que nuestro módulo tiene un conflict con todas las versiones de la ventana emergente javascript de http://en.wikipedia.org/wiki/Robert_Plant Robert Plant], pero solamente tiene conflicto con la ventana emergente de Starr para las versiones menores a 3.2.

Un modulo no cargará si tiene un conflicto con cualquier otro módulo que ya este cargado.

enable

Esta etiqueta es opciones, de la cual puede tener tantas como quiera. Esta etiqueta requiere el atributo name con el valor del nombre corto de un modulo. Esta etiqueta es más débil que la etiqueta de <requirement> en que tratará de permitir el módulo nombrado, pero no causará que este modulo no cargue si no puede. También se diferencia de las etiquetas <requerimiento> y <conflicto> ya que no hay información sobre la version (bajo las sub-etiquetas atLeast,atMost, lessThan, greaterThan). Por ejemplo:

<enable name='alex_patterson_javascript_paginator'/>

Dice que si el modulo paginador javascript de Alex Patterson puede cargarse, entonces que lo cargue. De lo contrario, no se preocupe por eso.

path

Esta es una etiqueta opcional de la cual pueden haber las que desee. Cada etiqueta de <path> require el atributo name y puede tener tantas sub-etiquetas de <value> como lo desee. La etiqueta de <path> permite que el modulo especifique los directorios que se agregarán al grupo de utilidad de busqueda de archivos por categoría. Las categorías se especifican por el nombre del atributo y algunos nombres comúnmente utilizados son:

  • plantillas Estos son los directorios para buscar archivos de plantillas html
  • imagenes Estos son los directorios para buscar archivos de imagenes
  • css Estos son los directorios para buscar archivos CSS
  • scripts Estos son los directorios para buscar archivos javascript
  • classes Estos son los directorios para buscar archivos que contengan clases de php. La convención aqui es que MyClass se localiza en el archivo MyClass.php
  • módulos Estos son los directorios para buscar (sub-)módulos del modulo actual.

Para mayor información acerca de las rutas permitidas, vea File Search Paths

priority

Esta etiqueta es opcional, la prioridad de un módulo es 50.

Ejemplo: <priority>50</priority>

Estas son algunas prioridades estándar:

  • I2CE 0
  • sub-módulos de I2CE 50
  • ihris-common 100
  • sub-módulos de ihris-common 150
  • ihris-manage, ihris-qualify, ihris-plan 200
  • sub-módulos ihris-manage, ihris-qualify, ihris-plan 250
  • un módulo de sitio 400

Configuración Datos (Magic)

El nodo de <configurationGroup> es opcional. Si está presente tiene que tener el atributo name que tiene el mismo valor que el atributo name en la etiqueta que contiene <I2CEConfiguration> .

Todos los datos magic son relativos a la ruta definifa por este configurationGroup. Hay tres opciones:

  • La ruta del atributo no está presente. En el siguiente ejemplo, los datos magic se guardan bajo /modules/mercury_javascript_path.
Ejemplo:
 <configurationGroup name='mercury_javascript_popup'>
   SOME STUFF GOES HERE
</configurationGroup>
  • La ruta del atributo está presente. En el siguiente ejemplo, los datos magic se guardan bajo /some/other/place.
Ejemplo:
 <configurationGroup name='mercury_javascript_popup' path='/some/other/place'>
   SOME STUFF GOES HERE
 </configurationGroup> 
  • El módulo es 'I2CE'. Los datos magic se guardan con relación a /I2CE

Este nodo <configurationGroup> realiza una doble función. Proporciona los datos de configuración que se guardan en los datos mágic. También proporciona, por medio del modulo Admin, un sistema de menú de árbol para editar los datos magic establecidos por este sistema. Esto permite las personalizaciones dinámicas de su sitio.

Vea Configuration (Magic) Data para mayor información.

La Clase del Módulo

La clase del módulo debe proporcionar funcionalidad php a la clase. La clase del módulo es nombrada por la etiqueta opcional <className> en la sección <metadata> del archivo de configuración del modulo. Debe existir en las rutas de classes del modulo y debe ser sub-clase I2CE_Module que se encuentra en i2ce/lib/I2CE_Module.php.

There are three basic types of functionality it provides. The first are methods to be called when a method is enabled, upgraded or disabled. The second is to provide hooks into the system. The third is to provide fuzzy methods.

Enabling/Disabling a Module

There are several methods used to initialize, enable, disable and upgrade a module which are called by the module factory. All of these methods expect that the module returns true to indicate success.

  • When a module is enabled the method action_enable() is called.
  • Before a module is enabled for the first time action_initialize() is called.
    This is the appropriate place to do things like ensure that any tables in the database the module expects to have are created.
    For example, the module 'I2CE' has its own class 'I2CE_Module_Core' which does the following:
    • Checks that the user database table is there, if not it creates it.
    • Makes sure that there is an administrative user for the system. If not, it creates it.
    • Checks that the config table for magic data is present, if not it creates it.
  • When a module is disabled the method action_disabled() is called.
  • When the version in the configuration file changes upgrade($old_vers,$new_vers) is called.

Hooked Methods

There are certain specific places in the code that may naturally lend themselves to be hooked in for greater functionality. A module may hook into the sytem at various points. To add a hook at some point you add either the line:

         I2CE_ModuleFactory::callHooks('some_hook_name',$some_argument);

or the line:

         I2CE_ModuleFactory::callHooks('some_hook_name');

I2CE_ModuleFactory will take care of calling all modules that register hooks for that point,with either the one or no arguments as appropriate. All hooked methods are called (in order of priority). The result of each hooked methods appended to an array which is then returned back from the callHooks() method.

A module registers the methods to call via its getHooks() method which returns an array with keys the hook name and value the method name in the module's class.

Fuzzy Methods

A fuzzy method is a method that a module provides to some other PHP class extended I2CE_Fuzzy via the __call() method. There are three reasons to use fuzzy methods:

  • PHP cannot do multiple-inheritance for classes which makes it difficult to combine functionality of two classes into one. One can always do an interface, but then one has to rewrite a lot of code.
  • The second is to provide modular functionality that can be turned on and off.
  • The functionality of a class may need to change depending if the class is called from a webserver or from the command line.

The later reason is why they are fuzzy: the methods may or not be present in the class depending on which modules you have turned on. The fuzzy methods that a module provides are defined by arrays returned from the methods getMethods() and getCLIMethods(). The results of these methods are processed every time the module is enabled or a change is detected to the module's class source file. When a module is disabled, the fuzzy methods it provides are removed from the class.

For example the moduleFormWorm's getMethod() returns:

array('I2CE_Page->addFormWorm'=>'addFormWorm',
      'I2CE_Template->addFormWorm'=>'addFormWorm'
      )

when the module FormWorm is turned on, this provides the methods addFormWorm() to both the class I2CE_Page and I2CE_Template as well as any child classes of these. The general form for this array is:

  CLASS->CLASSMETHOD => MODULEMETHOD

where CLASSMETHOD is a fuzzy method provided to the class CLASS. This fuzzy method is implemented by calling MODULEMETHOD on the instance of the module's class. The first argument to MODULEMETHOD will be the class that the fuzzy method was called and the remaining arguments are the arguments that CLASSMETHOD was called with.

For example, if $page is an instanceof I2CE_Page then the call:

 $page->addFormWorm($arg1,$arg2) 

results that the module factory will takes its instance, $module, of the I2CE_Module_FormWorm and call:

 $module->addFormWorm($page, $arg1,$arg2);

Fuzzy method will only have access to the public methods and variables of the calling class (I2CE_Page in this example). Incidentally, this encourages the development of a good API for the calling class.

Like the other components of a module (such as template files), fuzzy methods are prioritized and only the one of the lowest priority is called. You can see the documentation for the classes I2CE_Module and I2CE_ModuleFactory for more information.