# Adding a module to moregroupware

This document describes the way of adding a complete new module to moregroupware. It also describes the complete framework of moregroupware which is needed for module development. After reading this document, the reader should be able to add his first module.

## Directory-Structure of a Module

A module allways has its own folder in the moregroupware root tree. For this introduction, we use the module "contacts" as example. Below you see the module directory tree for "contacts":

### Module directory tree

module-folder

  The module folder (contacts in this example) resides on the top level of the moregroupware tree. It must(!) contain at least the following folders: inc / lang / templates. All important scripts which will be triggered by the application should also go into this folder.

module include folder (inc)

  The module include folder is the place where you can keep your include files with module specific functions or classes. IMPORTANT: you can define a file with the name mmmmm_func.inc.php (where mmmmmm = modulename / name of your modulefolder) this file will be auto-included in your scripts. More on this below.

module lang folder (lang)

  The folder contains the language files for the module following this naming convention: mmmmm.xx.lang (where mmmm = modulename, xx = language code) IMPORTANT: This language file will be read in automaticly by the framework, so please be careful to name it correctly. If you want to know more please refer to "how to localize Moregroupware" You should provide at least mmmmm.en.lang. If you can provide more languages yourself, add more files to the module lang folder, as you can see above, the contacts module has more language files.

module template folder (templates)

  This folder doesnt contain any files, but other folder(s). "default" is the default skin of your module, you should place your templates into this tree (not the directory itself) when you add a new module. There is the chance to add other folders into templates for example "blueice" if you want to have a skin called blueice. But at the moment, put everything in "default", or more exactly, put everything in the folders below default.

module template output folder (html / wml)

  This is the folder where your templates actually resides. The framework make it possible to output your application data to different target. Right now we moregroupware has html and wml defined as output folders. When you develop a new module, you must at least provide "html" folder.

media folder (media)

  In this folder should you place all your images and other media files which are needed by your module

Your minimal module directory tree would look like this:

### Minimal module directory tree

## Module Application Structure

The following code block is takem from contacts/index.php, its the main module script for contacts. The very first 5 lines are important to be moregroupware-module compliant.

    <?php
          $myEnv["module"] = "contact";
          $myEnv["output"] = "html";

          include("../config.inc.php");
          include(INCLUDEPATH . "container.inc");

          // adding file revision into global array
          revisionInit("\$Revision: 1.7 $", __FILE__);

The first line is a declaration of the modulename, the modulename MUST be the same as the folder name. This string will be used in the complete framework to determine the different paths in the groupware. The second line identifies the output target, this will be normally html.

The next two lines are mandatory, you can copy them into your own module script. In the next chapter there is a description of what these two important includes do.

The last line adds the file's revision number to a global array, this is used as a debugging aid.

### Never use include($var/myinclude.php)!

Please use never an include like described above, because this way you open a big security hole. Always use something like this: include(ROOTPATH . "/folder/myinclude.php")

You should always use $HTTP_*_VARS to access input data! Never rely on register_globals being on! It is deprecated, insecure and clumsy!

### Don't use your own database connections

You see parameters like $appconf["dbuser"] or other database based parameters, please dont use them to create your own database connections, use the auto-generated $conn ADOdb object instead, more on this later.

## What is the config.inc.php file?

the config.inc.php file will be created by the setup routine. It defines several important parameters which are needed by the moregroupware framework. All parameters are in a hashmap called $appconf. Below you can see an config.inc.php example:

    <?php
          // this file is auto-generated by setup, only modify if you are sure what you do
          // Config File
          // Moregroupware.org
          // programmed by Marc Logemann
          // 01/04/01 (c)
          $appconf["dbvendor"] = "mysql";
          $appconf["dbhost"] = "localhost";
          $appconf["dbuser"] = "mgwuser";
          $appconf["dbpassword"] = "mgwpass";
          $appconf["dbname"] = "moregw";
          $appconf["rooturl"] = "http://localhost/moregroupware";
          $appconf["rootpath"] = "/home/apache/moregroupware";
          $appconf["theme"] = "default";
          $appconf["auth_method"]= "sql";
          $appconf["auth_ldaptype"]= "0";//0 for openldap; 1 for ADSI
          $appconf["auth_ldaphost"] = "";
          $appconf["auth_ldapbase"] = "";
          $appconf["auth_ldapuid"] = "";
          $appconf["auth_ldappasswd"] = "";
          $appconf["auth_ldapsuffixe"] = "";
          $appconf["create_accounts_on_login"] = 0;
          $appconf["mgw_version"] = "";
          $appconf["mgw_releasedate"] = "";
          $appconf["def_language"] = "de";
          $appconf["def_charset"] = "iso-8859-1";
          $appconf["html_compressor"] = false;
          $appconf["html_compressor_debug"] = false;
          define("SMARTY_DIR", "/home/apache/mgw/include/smarty/");
          define("ROOTPATH","/home/apache/mgw");
          define("INCLUDEPATH","/home/apache/mgw/include/");
          ?>

Its important to know that in each script, that starts with the necessary lines described above, you have access to the $appconf hashmap in order to use this settings, you will often need things like $appconf["rooturl"] or $appconf["rootpath"]. There are also 2 constant definitions, you will perhaps use ROOTPATH or INCLUDEPATH in order to include a different file.

## What does container.inc do exactly?

container.inc is just a container for other includes. It was introduced to package all includes into one file. All the includes which are in the container.inc dont have other includes itself. This mean there are only 2 include levels, the first is the container.inc and the second level are the includes inside container.inc. There is no 3. level. Below the content of container.inc:

    <?php
          /* $Id: coding_addmodule.xml,v 1.7 2003/11/01 21:41:28 emailtotom Exp $ */

          require_once(SMARTY_DIR . "Smarty.class.php");

          // definition of moregroupware class, holding application vars
          include(INCLUDEPATH . 'mgw.class.inc');

          // functions for translation
          include(INCLUDEPATH . 'lang.inc');

          // array for tracking file revision number used in sql error report screen
          $Revisions_array = Array();

          // important functions like connect to database
          include(INCLUDEPATH . 'userfunc.inc');

          // definition of moregroupware version and label
          include(INCLUDEPATH . 'version.inc');

          // Auto-Assigns for template engine and global definitions
          include(INCLUDEPATH . 'appconfig.inc');

          // include module specific functions if present (they are now in module/inc)
          // must be named module_func.inc.php (i.e. calendar_func.inc.php)
          if(file_exists(ROOTPATH . "/modules/" . $myEnv["module"]. "/inc/" . $myEnv["module"] . "_func.inc.php")) {
          include(ROOTPATH . "/modules/" . $myEnv["module"] . "/inc/" . $myEnv["module"] . "_func.inc.php");
          }

          // help system
          if(file_exists(ROOTPATH."/modules/".$myEnv["module"]."/help/index.".$MGW->spkz.".html")) $smarty->assign("helpurl", $myEnv["module"]."/help/index.".$MGW->spkz.".html");
          elseif(file_exists(ROOTPATH."/modules/".$myEnv["module"]."/help/index.en.html")) $smarty->assign("helpurl", $myEnv["module"]."/help/index.en.html");
          elseif(file_exists(ROOTPATH."/modules/general/help/index.".$MGW->spkz.".html")) $smarty->assign("helpurl","general/help/nohelp.".$MGW->spkz.".html");
          else $smarty->assign("helpurl","general/help/nohelp.en.html");

          // include module autoexecution of several things like translation, authentication, and more
          include(INCLUDEPATH . 'module_exec.inc');
          ?>

In the next sections, we show the meanings of each include.

### require_once(SMARTY_DIR . "Smarty.class.php");

This include loads the smarty classes which will be used by other includes (appconf.inc) and of course by the user scripts. Without this include, there wont be any output at all.

### include(INCLUDEPATH .'mgw.class.inc');

The MGW class will be stored in the user session in form of an object. This object holds many user related data such as languagecode, username or his current rights. We use this object for checking various things, without being forced to make any database queries. You will learn how to use this class later on, because its very important for your module.

### include(INCLUDEPATH .'lang.inc');

This include provides the language functions which we need also in appconf.inc and sometimes in the userscripts.

### include(INCLUDEPATH .'userfunc.inc');

This is the place where we store system wide useful functions. These are functions which could useful in each module. Dont place functionalities for specialized module tasks in there.

### include(INCLUDEPATH .'version.inc');

This is the most simple include, the version.inc only contains the release number and the name of the product, this will be displayed in some places inside the groupware. See bottom status bar for example in each screen.

### include(INCLUDEPATH .'appconfig.inc');

This is the most complex include, it does various things, below is a list of things which are important to know as a programmer:

- creation of $appconf["gentemplates"], this points to the general/templates/html folder, this will be used for including html fragment from the general folder, instead of the current module template folder, within the template you can reach this variable with {$gentemplates}

- creation of $appconf["imgpath"] and $appconf["imgpathgeneral"], this point to the module image path or to the general image path (name of folder is "media"). You will need this variables inside templates. You can reach them with {$imgpath} or {$imgpathgeneral} inside templates.

- creation of $smarty object, this object you will use to program the output of your module, you will most likely use methods like $smarty->assign(), $smarty->append() and $smarty->display().

- the session will be started in this include

- following templates variables will be auto-created and should be used in the templates: {$PHPSESSID} (actual session id of user), {$rooturl}, {$username}, {$userfullname}, {$phpself}, {$gwversion}, {$gwtitle}. If you dont know some meaning, just insert them in your template, you will see what is being thrown out :)

- creation of main-menu

### include(INCLUDE .'module_exec.inc');

The module_exec include is the only include which you can control from the outside, the operations executed inside can be controlled by flags which you can define in your script. Take a look in the next topic for a detailed view on this include.

## Whats special about module_exec.inc

first we take a look at module_exec.inc:

    // Authentication of User according his session (its not the main auth)
            if($myEnv["auth"] !== false) checkLogin();

            // Connect to database and return $db object
            if($myEnv["connectdb"] !== false) $db = connect_database();

            // do module translation and give back a hashmap with all keys and values
            if($myEnv["translate"] !== false) $hashmap = setLocaledText($MGW->spkz, $myEnv["module"]);

            // get user settingw and return them in $settings hashmap
            if($myEnv["getsettings"] !== false) $settings = get_settings($myEnv["module"]);

            // call standard module submenu (smenu.php) and integrate it
            if($myEnv["stdsmenu"] !== false)
            if(file_exists(ROOTPATH . "/" . $myEnv["module"]. "/inc/smenu.php"))
            include(ROOTPATH . "/" . $myEnv["module"] . "/inc/smenu.php");
            else
            echo "<b>Error: </b>Program cannot find Submenu-Definition File (smenu.php) in module \"inc\" folder. Please create this file or set \$myEnv[stdsmenu] to false in your program and define it there.";

As you can see, this include does 5 important tasks

- Check the user login (and reject him to login if something is wrong)

- Connect to the database and return object $db

- translate the current module and gives back a hashmap $hashmap

- get settings for actual module for actual user (not implemented yet)

- create the submenu

TO BE CONTINUED....