Module Structure: Difference between revisions

From IHRIS Wiki
No edit summary
 
(5 intermediate revisions by 3 users not shown)
Line 1: Line 1:
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.
This tutorial describes the iHRIS Module Structure. An iHRIS module is a collection of various types of "code" by the features that they provide to the system. These modules can be part of the core I2CE system and handle things like user
authentication or database access, or they can provide new functionality to iHRIS, such as leave management.




==¿Qué es un Módulo?==
==What is a Module?==
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.
The iHRIS Suite is based on the Intrahealth Informatics Core Engine (I2CE) which use a module structure to encapsulate and maintain "code" into manageable pieces organized by the functionality provided. By "code" we mean the entire collection of php, html, javascript, xml, image files, css, flash, etc that provide the functionality of a web-based application.




Un modulo está versionado para llevar un registro de los cambios a la funcionalidad y el API que tiene un módulo.
A module is versioned to keep track of the changes to functionality and API that a module has.


=¿Por qué los módulos?=
=Why Modules?=
*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.   
*The main reason to use a module system is to increase code manageability. The various components of the iHRIS Suite (Qualify, Manage, and Plan) are used in a variety of settings each requiring their own customizations.   


*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.
*Each of the iHRIS Suite's components (Qualify, Manage, Plan) share some common functionality and the module system ensures proper code re-use.


*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.
*The module system lets many customizations to be encapsulated without having to change the underlying code base.   This allow a local developer to make their changes without worrying about about having to redo those changes anytime the core system is updated.


*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.
*As modules are organized by the functionality that they provide to the system, a developer can quickly find the relevant code to change by looking at the relevant modules.


*Las personalizaciones al software encapsuladas en un modulo pueden compartirse fácilmente entre desarrolladores.
*Customizations to the software encapsulated in a module can be easily shared among developers.


=El Módulo I2CE=
=The I2CE Module=
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.
The is the "top"-most module. Every module implicitly has this a requirement. It is the core module which provides the minimal functionality including magic data, file search, the templating system, and the module factory.   It has no requirements.


''I2CE'' proporciona varios sub-módulos opcionales. Por ejemplo:
''I2CE'' provides many optional sub-modules. For example:
*Admin -- Proporciona un sistema de manejo de módulos.
*Admin -- Provides a module management system.
*Proceso de Fondo -- Proporciona una plataforma independiente con los medios para lanzar y monitorear procesos de fondo
*Background Process -- Provides a platform independent means to launch and monitor background processes
*Reportes Personalizados -- Proporciona la funcionalidad de Reportes Personalizados
*Custom Reports -- Provides the Custom Reporting functionality
*Gráficos Flash -- proporciona una interfaz para el sistema de maani flash charting  
*Flash Charts -- provides a  php interface to the maani flash charting system
*Formularios -- proporciona la estructura básica de formularios y campos que utiliza nuestro software
*Forms -- provides the basic form and field structure used by our software
*MooTools -- proporciona una interfaz php a la libreria de javascript MooTools
*MooTools -- provides a php interface to the MooTools javascript library
*Tareas y Roles -- proporciona un sistema de manejo basado en tareas para los roles de los usuarios
*Tasks and Roles -- provides a task based management system for user roles


=El Módulo del Sitio=
=The Site Module=
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]]
The "bottom"-most module is the '''Site Module.'''  This module is the one that is loaded by the '''index.php''' file and tells the system which modules we are used by your system. It is the appropriate place to perform basic customizations to the system, for example changing the image displayed on the login page or to display your organizations name. See for example [[Customizing iHRIS Manage]]


=Archivo de Configuración del Módulo=
=Module Configuration File=
Un modulo esiste al definer sus archivos de configuración. Hay un nodo de top-level <I2CEConfiguration> bajo el cual hay dos posibles nodos:
A module exists by defining its configuration files. There is one top-level node <I2CEConfiguration> under which there are two possible nodes:
*Se require la etiqueta de [[#metadata|<metadata>]].
*The [[#metadata|<metadata>]] tag is required.
*La etiqueta de [[#Configuration (Magic) Data|<configurationGroup>]] es opcional.   
*The [[#Configuration (Magic) Data|<configurationGroup>]] tag is optional.   
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.''   
The <I2CEConfiguration> tag has a required attribute '''name''' whose values should be a unique short name to describe this module such as ''I2CE'', ''ihris-manage'' or ''mercury_javascript_popup.''   
El DTD que describe el format del arcivo de configuración esta ubicado en ''I2CE/lib/I2CE_Configuration.DTD''.  Como ejemplo:
The DTD which describes the format of the configuration file is located in ''I2CE/lib/I2CE_Configuration.DTD''.  As an example:
  <?xml version="1.0"?>   
  <?xml version="1.0"?>   
  <!DOCTYPE I2CEConfiguration SYSTEM "I2CE_Configuration.dtd">
  <!DOCTYPE I2CEConfiguration SYSTEM "I2CE_Configuration.dtd">
Line 52: Line 53:


==metadata==
==metadata==
La etiqueta de DTD para <metadata> permite los siguientes nodos:
The DTD has for the <metadata> tag allows the following nodes:
  <nowiki><!ELEMENT metadata (</nowiki>[[#displayName|displayName]],[[#className|className]]?,[[#category|category]]?,[[#description|description]]?,[[#creator|creator]]?,[[#email|email]]?,[[#link|link]]?,
  <nowiki><!ELEMENT metadata (</nowiki>[[#displayName|displayName]],[[#className|className]]?,[[#category|category]]?,[[#description|description]]?,[[#creator|creator]]?,[[#email|email]]?,[[#link|link]]?,
   [[#version|version]],([[#enable|enable]]|[[#requirement|requirement]]|[[#conflict|conflict]]|[[#path|path]])*,[[#priority|priority]]?<nowiki>)></nowiki>
   [[#version|version]],([[#enable|enable]]|[[#requirement|requirement]]|[[#conflict|conflict]]|[[#path|path]])*,[[#priority|priority]]?<nowiki>)></nowiki>
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.
For the most part, the orders of these tags matter due to limitations in the structure of DTDs.  The exceptions is that the <enabled>, <requirement>, <conflict> and <path> tags can be listed in any order amongst themselves.
===displayName===
===displayName===
Esta etiqueta se require que sea el nombre de este modulo humanamente legible que se muestra, por ejemplo, en el ''Configure Modules'' pa
This tag is requireed it is human readable name of this module which is displayed, for example, in the ''Configure Modules'' pa
  Ejemplo: <displayName>Popup Box</displayName>
  Example: <displayName>Popup Box</displayName>
 
===className===
===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
The tag is optional and it associates a class for the module. See [[#The Module Class]] for specific information about the module's class
  Ejemplo: <className>I2CE_Module_JavascriptPopup</className>
  Example: <className>I2CE_Module_JavascriptPopup</className>
===category===
===category===
Esta es una etiqueta opcional que se utiliza para agrupar módulos similares por categoría en la pñagina de''Configure Modules''.
This is an optional tag that is used to group similar modules together by category in the ''Configure Modules'' page.
  Ejemplo: <category>Javascript Library</category>
  Example: <category>Javascript Library</category>
===description===
===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'' .
This is an optional tag which gives a description of this module which is displayed in the ''Configure Modules'' page.
  Ejemplo: <description>Provides a javascript popup box</description>
  Example: <description>Provides a javascript popup box</description>
===creator===
===creator===
Esta es una etiqueta opcional que muestra al creador en la página de ''Configure Modules''.
This is an optional tag which shows the creator in the ''Configure Modules'' page.
  Ejemplo: <creator>Freddy Mercury</creator>
  Example: <creator>Freddy Mercury</creator>
===link===
===link===
Esta es una etiqueta opcional que proporciona un URL para el modulo en la página '''Configure Modules'' .
This is an optional tag which gives a URL for the module in the '''Configure Modules'' page.
  Ejemplo: <link>http://en.wikipedia.org/wiki/Freddie_Mercury</link>
  Example: <link>http://en.wikipedia.org/wiki/Freddie_Mercury</link>
===version===
===version===
Esta es una etiqueta requerida que se puede utilizar para versionar su módulo.
This is a required tag which you can use to version your module.
  Ejemplo: <version>1.0.0</version>
  Example: <version>1.0.0</version>
===requirement===
===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 requerido por este móduloEsta etiqueta puede tener hasta cuatro sub-etiquetas posibles:
This is an optional tag, of which you can have as many as you want. Each tag needs to have the attribute '''name''' whose the value is the name of a module required by this moduleThis tag can have up to four possible sub-tags:
*atLeast  
*atLeast
*atMost
*atMost
*lessThan
*lessThan
*greaterThan
*greaterThan
cada una de las cuales deben tener la '''versión''' del atributo con un valor de una versión del módulo. Como ejemplo:
each of which need to have the attribute '''version''' with a value of a version of the module. As an example:
  <requirement name='I2CE'>
  <requirement name='I2CE'>
   <atLeast version='3.1'/>
   <atLeast version='3.1'/>
   <lessThan version='3.2'/>
   <lessThan version='3.2'/>
  </requirement>
  </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.
says that our module requires that I2CE have version at least 3.1 and less than version 3.2.


Para que el módulo cargue, debe complir con todos los requerimientos satisfactoriamente.
In order for a module to be loaded, it must successfully meet all of its requirements.


===conflict===
===conflict===
Esta es una etiqueta opcional de la cual se puede tener cuantas desee. Esto es opuesto a la etiqueta [[#requirement|<requirement>]] y enumera todos los módulos con los que este mñodulo tiene conflictos. Por ejemplo:
This is an optional tag of which you can have as many as you wish. This is opposite of the [[#requirement|<requirement>]] tag and lists all the modules that this module conflicts with. As an example:
  <conflict name='plant_javascript_popup'>
  <conflict name='plant_javascript_popup'>
  </conflict>
  </conflict>
Line 100: Line 100:
   <lessThan version=3.2/>
   <lessThan version=3.2/>
  </conflict>
  </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 [http://en.wikipedia.org/wiki/Ringo_starr|Ringo Starr] para las versiones menores a 3.2.
Says that our module conflicts's with all versions of [http://en.wikipedia.org/wiki/Robert_Plant Robert Plant]'s javascript popup, but only conflicts with [http://en.wikipedia.org/wiki/Ringo_starr|Ringo Starr]'s popup for versions less that 3.2.


Un modulo no cargará si tiene un conflicto con cualquier otro módulo que ya este cargado.
A module will fail to load if it conflicts with any other modules that are already loaded.


===enable===
===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|<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:
This tag is optional of which you can have as many as you wish. This tag requires the attribute '''name''' with the value the short name of a module. This tag is weaker than the [[#requirement|<requirement>]] tag in that it will try to enable the named module, but it will not cause the cause this module to fail to load if it can't. It also differs from the <requirement> and <conflict> tags as there is no version information (under the subtags atLeast,atMost, lessThan, greaterThan). As an example:
  <enable name='alex_patterson_javascript_paginator'/>
  <enable name='alex_patterson_javascript_paginator'/>
Dice que si el modulo paginador javascript de [http://en.wikipedia.org/wiki/Alex_Patterson Alex Patterson] puede cargarse, entonces que lo cargue. De lo contrario, no se preocupe por eso.
Says that if the [http://en.wikipedia.org/wiki/Alex_Patterson Alex Patterson]'s javascript paginator module is able to loaded, then load it. Otherwise don't worry about it.


===path===
===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:
This is an optional tag of which there can be as many as you wish. Each <path> tag requires the attribute '''name''' and can have as many sub-tags '''<value>''' as you wish.   The <path> tag enables a module to specify directories to be added to the file search utility group by category. The categories are specified by the name attribute and some commonly used names are:
*plantillas Estos son los directorios para buscar archivos de plantillas html
*templates These are the directories to search for html template files
*imagenes Estos son los directorios para buscar archivos de imagenes
*images These are the directories to search for image files
*css Estos son los directorios para buscar archivos CSS  
*css These are the directories to search for CSS files
*scripts Estos son los directorios para buscar archivos javascript  
*scripts These are the directories to search for javascript files
*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
*classes These are the directories to search for files containing php classesThe convention here is that MyClass is located in the file MyClass.php
*módulos Estos son los directorios para buscar (sub-)módulos del modulo actual.
*modules These are the directories to look for (sub-)modules of the current module.
Para mayor información acerca de las rutas permitidas, vea [[File Search Paths]]
For more information about the paths allowed, see [[File Search Paths]]


===priority===
===priority===
Esta etiqueta es opcional, la prioridad de un módulo es 50.
This tag is optional.  If not set, the priority of a module is 50.
  Ejemplo: <priority>50</priority>
  Example: <priority>50</priority>
Estas son algunas prioridades estándar:
Here are some standard priorities:
*I2CE 0
*I2CE 0
*sub-módulos de I2CE 50
*sub-modules of I2CE 50
*ihris-common 100
*ihris-common 100
*sub-módulos de ihris-common 150
*sub-modules of ihris-common 150
*ihris-manage, ihris-qualify, ihris-plan 200
*ihris-manage, ihris-qualify, ihris-plan 200
*sub-módulos ihris-manage, ihris-qualify, ihris-plan 250
*sub-modules ihris-manage, ihris-qualify, ihris-plan 250
*un módulo de sitio 400
*a site module 400


==Configuración Datos (Magic) ==
==Configuration (Magic) Data==
El nodo de <configurationGroup> es opcionalSi está presente tiene que tener el atributo '''name''' que tiene el mismo valor que el atributo '''name''' en la etiqueta que contiene <I2CEConfiguration> .   
The <configurationGroup> node is optionalIf it is present it has to have the attribute '''name''' which has the same value as the attribute '''name''' in the containing <I2CEConfiguration> tag.   


Todos los datos magic son relativos a la ruta definifa por este configurationGroup.  Hay tres opciones:
All magic data is relative to the path defined by the this configurationGroup.  There are three options:
*La ruta del atributo no está presente. En el siguiente ejemplo, los datos magic se guardan bajo ''/modules/mercury_javascript_path.''
*The attribute path is not present. In the following example, the magic data is stored under ''/modules/mercury_javascript_path.''
  Ejemplo:
  Example:
   <configurationGroup name='mercury_javascript_popup'>
   <configurationGroup name='mercury_javascript_popup'>
     <span style='color:red'>SOME STUFF GOES HERE</span>
     <span style='color:red'>SOME STUFF GOES HERE</span>
  </configurationGroup>
  </configurationGroup>
*La ruta del atributo está presente. En el siguiente ejemplo, los datos magic se guardan bajo ''/some/other/place.''
*The attribute path is present. In the following example, the magic data is stored under ''/some/other/place.''
  Ejemplo:
  Example:
   <configurationGroup name='mercury_javascript_popup' path='/some/other/place'>
   <configurationGroup name='mercury_javascript_popup' path='/some/other/place'>
     <span style='color:red'>SOME STUFF GOES HERE</span>
     <span style='color:red'>SOME STUFF GOES HERE</span>
   </configurationGroup>  
   </configurationGroup>  
*El módulo es 'I2CE'.  Los datos magic se guardan con relación a ''/I2CE''
*The module is 'I2CE'.  The magic data is stored relative to ''/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.
This <configurationGroup> node does double duty. It provides the configuration data that is stored into magic data. It also provides, via the ''Admin'' module, a treed menu system to edit the magic data set by this system. This allows for dynamic customizations of your site.


Vea [[Configuration (Magic) Data]] para mayor información.
See [[Configuration (Magic) Data]] for more detailed information.


==La Clase del Módulo==
==The Module Class==
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.''
The module class is in intended to provide php functionality to the class. The module class is named by the optional <className> tag in the <metadata> section of the module configuration file.   It needs to exist in the ''classes'' paths of the module and it needs to subclass '''I2CE_Module''' which is found in ''i2ce/lib/I2CE_Module.php.''


Hay tres tipos básicos de funcionaidad que proporciona. Los primeros son métodos que se llaman cuando se activa, actualiza o desactiva un método. El Segundo es proporcionar ganchos en el sistema. El tercero es proporcionar métodos fuzzy.
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.
===Activar/Desactivar un Módulo===
===Enabling/Disabling a Module===
Hay varios métodos que se utilizan para iniciar, activar, desactivar y actualizar un módulo que se llaman por medio de la fábrica de módulos. Todos estos métodos esperan que el módulo regrese verdadero para indicar éxito.
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.
* Cuando un módulo se activa, se llama el método '''action_enable()'''.
* When a module is enabled the method '''action_enable()''' is called.
* Antes de activar un módulo por primera vez se llama '''action_initialize()'''.  <br/> Este es el lugar adecuado para hacer cosas como asegurar que todas las tablas en la base de datos que se espera que tenga el módulo, hayan sido creadas.  <br/> Por ejemplo, el módulo 'I2CE' tiene su propia clase 'I2CE_Module_Core' que hace lo siguiente:
* Before a module is enabled for the first time '''action_initialize()''' is called.  <br/> This is the appropriate place to do things like ensure that any tables in the database the module expects to have are created.  <br/> For example, the module 'I2CE' has its own class 'I2CE_Module_Core' which does the following:
**Revisa que la base de datos del usuario esta ahí, si no, la crea.
**Checks that the user database table is there, if not it creates it.
**Se asegura de que hay un usuario administrativo para el sistema, si no, lo crea.
**Makes sure that there is an administrative user for the system.  If not, it creates it.
**Revisa que la table config para los datos magis este presente, si no, la crea.
**Checks that the config table for magic data is present, if not it creates it.
* Cuando un módulo esta desactivado, se llama al método '''action_disabled()''' .
* When a module is disabled the method '''action_disabled()''' is called.
* Cuando la versión del archivo de configuración cambia, se llama '''upgrade($old_vers,$new_vers)'''.
* When the version in the configuration file changes '''upgrade($old_vers,$new_vers)''' is called.


===Métodos Enganchados===
===Hooked Methods===
Hay ciertos lugares específicos en el código que pueden prestarse naturalmente a sí mismos para engancharse para lograr mayor funcionalidad.  
There are certain specific places in the code that may naturally lend themselves to be hooked in for greater functionality.  
Un modulo puede engancharse en el sistema en varios puntos. Para agregar un gancho se agrega la línea:
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);
           I2CE_ModuleFactory::callHooks('some_hook_name',$some_argument);
o la línea:
or the line:
           I2CE_ModuleFactory::callHooks('some_hook_name');
           I2CE_ModuleFactory::callHooks('some_hook_name');
I2CE_ModuleFactory se encargará de llamar a todos los módulos que registren ganchos para ese punto, ya sea con uno o sin ningun argumento segun sea adecuado. Todos los métodos enganchados se llaman (en orden de prioridad). El resultado de cada método enganchado adjunto a un arreglo que es entonces devuelto del método callHooks().
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.


Un módulo registra los métodos a llamar vía el método getHooks() que regresa un arreglo con claves el nombre del gancho y valor el nombre del método en la clase del módulo.
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===
===Fuzzy Methods===
Line 199: Line 200:


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.
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.
[[Category:Technical Overview]][[Category:Modules]][[Category:Review2013]][[Category:Needs Intro]]
[[Category:Modules]][[Category:Review2013]]

Latest revision as of 11:56, 8 November 2013

This tutorial describes the iHRIS Module Structure. An iHRIS module is a collection of various types of "code" by the features that they provide to the system. These modules can be part of the core I2CE system and handle things like user authentication or database access, or they can provide new functionality to iHRIS, such as leave management.


What is a Module?

The iHRIS Suite is based on the Intrahealth Informatics Core Engine (I2CE) which use a module structure to encapsulate and maintain "code" into manageable pieces organized by the functionality provided. By "code" we mean the entire collection of php, html, javascript, xml, image files, css, flash, etc that provide the functionality of a web-based application.


A module is versioned to keep track of the changes to functionality and API that a module has.

Why Modules?

  • The main reason to use a module system is to increase code manageability. The various components of the iHRIS Suite (Qualify, Manage, and Plan) are used in a variety of settings each requiring their own customizations.
  • Each of the iHRIS Suite's components (Qualify, Manage, Plan) share some common functionality and the module system ensures proper code re-use.
  • The module system lets many customizations to be encapsulated without having to change the underlying code base. This allow a local developer to make their changes without worrying about about having to redo those changes anytime the core system is updated.
  • As modules are organized by the functionality that they provide to the system, a developer can quickly find the relevant code to change by looking at the relevant modules.
  • Customizations to the software encapsulated in a module can be easily shared among developers.

The I2CE Module

The is the "top"-most module. Every module implicitly has this a requirement. It is the core module which provides the minimal functionality including magic data, file search, the templating system, and the module factory. It has no requirements.

I2CE provides many optional sub-modules. For example:

  • Admin -- Provides a module management system.
  • Background Process -- Provides a platform independent means to launch and monitor background processes
  • Custom Reports -- Provides the Custom Reporting functionality
  • Flash Charts -- provides a php interface to the maani flash charting system
  • Forms -- provides the basic form and field structure used by our software
  • MooTools -- provides a php interface to the MooTools javascript library
  • Tasks and Roles -- provides a task based management system for user roles

The Site Module

The "bottom"-most module is the Site Module. This module is the one that is loaded by the index.php file and tells the system which modules we are used by your system. It is the appropriate place to perform basic customizations to the system, for example changing the image displayed on the login page or to display your organizations name. See for example Customizing iHRIS Manage

Module Configuration File

A module exists by defining its configuration files. There is one top-level node <I2CEConfiguration> under which there are two possible nodes:

The <I2CEConfiguration> tag has a required attribute name whose values should be a unique short name to describe this module such as I2CE, ihris-manage or mercury_javascript_popup. The DTD which describes the format of the configuration file is located in I2CE/lib/I2CE_Configuration.DTD. As an example:

<?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

The DTD has for the <metadata> tag allows the following nodes:

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

For the most part, the orders of these tags matter due to limitations in the structure of DTDs. The exceptions is that the <enabled>, <requirement>, <conflict> and <path> tags can be listed in any order amongst themselves.

displayName

This tag is requireed it is human readable name of this module which is displayed, for example, in the Configure Modules pa

Example: <displayName>Popup Box</displayName>

className

The tag is optional and it associates a class for the module. See #The Module Class for specific information about the module's class

Example: <className>I2CE_Module_JavascriptPopup</className>

category

This is an optional tag that is used to group similar modules together by category in the Configure Modules page.

Example: <category>Javascript Library</category>

description

This is an optional tag which gives a description of this module which is displayed in the Configure Modules page.

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

creator

This is an optional tag which shows the creator in the Configure Modules page.

Example: <creator>Freddy Mercury</creator>

link

This is an optional tag which gives a URL for the module in the 'Configure Modules page.

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

version

This is a required tag which you can use to version your module.

Example: <version>1.0.0</version>

requirement

This is an optional tag, of which you can have as many as you want. Each tag needs to have the attribute name whose the value is the name of a module required by this module. This tag can have up to four possible sub-tags:

  • atLeast
  • atMost
  • lessThan
  • greaterThan

each of which need to have the attribute version with a value of a version of the module. As an example:

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

says that our module requires that I2CE have version at least 3.1 and less than version 3.2.

In order for a module to be loaded, it must successfully meet all of its requirements.

conflict

This is an optional tag of which you can have as many as you wish. This is opposite of the <requirement> tag and lists all the modules that this module conflicts with. As an example:

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

Says that our module conflicts's with all versions of Robert Plant's javascript popup, but only conflicts with Starr's popup for versions less that 3.2.

A module will fail to load if it conflicts with any other modules that are already loaded.

enable

This tag is optional of which you can have as many as you wish. This tag requires the attribute name with the value the short name of a module. This tag is weaker than the <requirement> tag in that it will try to enable the named module, but it will not cause the cause this module to fail to load if it can't. It also differs from the <requirement> and <conflict> tags as there is no version information (under the subtags atLeast,atMost, lessThan, greaterThan). As an example:

<enable name='alex_patterson_javascript_paginator'/>

Says that if the Alex Patterson's javascript paginator module is able to loaded, then load it. Otherwise don't worry about it.

path

This is an optional tag of which there can be as many as you wish. Each <path> tag requires the attribute name and can have as many sub-tags <value> as you wish. The <path> tag enables a module to specify directories to be added to the file search utility group by category. The categories are specified by the name attribute and some commonly used names are:

  • templates These are the directories to search for html template files
  • images These are the directories to search for image files
  • css These are the directories to search for CSS files
  • scripts These are the directories to search for javascript files
  • classes These are the directories to search for files containing php classes. The convention here is that MyClass is located in the file MyClass.php
  • modules These are the directories to look for (sub-)modules of the current module.

For more information about the paths allowed, see File Search Paths

priority

This tag is optional. If not set, the priority of a module is 50.

Example: <priority>50</priority>

Here are some standard priorities:

  • I2CE 0
  • sub-modules of I2CE 50
  • ihris-common 100
  • sub-modules of ihris-common 150
  • ihris-manage, ihris-qualify, ihris-plan 200
  • sub-modules ihris-manage, ihris-qualify, ihris-plan 250
  • a site module 400

Configuration (Magic) Data

The <configurationGroup> node is optional. If it is present it has to have the attribute name which has the same value as the attribute name in the containing <I2CEConfiguration> tag.

All magic data is relative to the path defined by the this configurationGroup. There are three options:

  • The attribute path is not present. In the following example, the magic data is stored under /modules/mercury_javascript_path.
Example:
 <configurationGroup name='mercury_javascript_popup'>
   SOME STUFF GOES HERE
</configurationGroup>
  • The attribute path is present. In the following example, the magic data is stored under /some/other/place.
Example:
 <configurationGroup name='mercury_javascript_popup' path='/some/other/place'>
   SOME STUFF GOES HERE
 </configurationGroup> 
  • The module is 'I2CE'. The magic data is stored relative to /I2CE

This <configurationGroup> node does double duty. It provides the configuration data that is stored into magic data. It also provides, via the Admin module, a treed menu system to edit the magic data set by this system. This allows for dynamic customizations of your site.

See Configuration (Magic) Data for more detailed information.

The Module Class

The module class is in intended to provide php functionality to the class. The module class is named by the optional <className> tag in the <metadata> section of the module configuration file. It needs to exist in the classes paths of the module and it needs to subclass I2CE_Module which is found in 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.