# Handling common coding tasks

This chapter has reusable code for common tasks one needs to code when working on a module. The code is not only reusable, but shows best-practice examples for using the moregroupware framework and the libraries we use.

Coding the way described herein reduces your work, avoids errors and makes the code easier to read afterwards!

## The definition.xml file

Modules have some important information associated with them. This information is stored in a file named `defintion.xml` in the modules root directory.

The type defines whether the module is a core module (type 1, always installed, not shown for selection), currently there is only one core module, the 'general' module. Modules with type 2 are base modules, and are shown on the module selection screen, but are always installed. Type 3 denotes user modules, they are selectable at the user's will.

### The defintion.xml of the notes module.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mgw PUBLIC "-//MGW//DTD Moregroupware DTD V1.0//EN" "http://130.89.166.186/mgw/mgw.dtd">
    <mgw>
    	<moduleDefinition>
    		<module type="3">
    			<name>notes</name>
    			<version>0.8</version>
    			<date>2003-02-28</date>
    			<author>Karsten Dambekalns</author>
    			<email>k.dambekalns@fishfarm.de</email>
    			<description>A module for managing notes.</description>
    			<compatibility>
    				<version>0.6.6</version>
    			</compatibility>
    			<updates>
    			</updates>
    			<dependancies>
    			</dependancies>
    			<cache>
    			</cache>
    		</module>
    	</moduleDefinition>
    </mgw>

## Logging functions

A module author will sooner or later want to log what the module is doing. Most helpful is logging when the module is not doing what it should do, though...

This is not intended to notify the end user of errors or tell them what happens. Have a look at the notification functions for this!

### Using the core logging in more.groupware

In the settings module, in the general section, the are a bunch of logging settings. The first one, 'enable_logging' is a systemwide on/off switch for logging. When it is enabled a 'log' link is placed next to 'help' in the mgw submenu. This link opens a window displaying all log data for the page you just requested.

There are also 'log level' settings for each module (except general, which always has all levels enabled). You can turn these all on/off independantly. If a level is off, all log calls for that level are discarded.

Only the admin user can change the logging settings. During normal use, it is probably a good idea to disable logging (disabled by default after setup) to reduce overhead.

You can always log messages with one simple function call. Those messages can have one of five logging levels: MGW_FATAL, MGW_ERROR, MGW_WARNING, MGW_NOTICE, MGW_INFO. Those are predefined constants you can use right away.

In appconfig the logging class is initiated and can be reached anywhere using $GLOBALS['log']. To log stuff, use the function $GLOBALS['log']->message(). It returns a boolean value to indicate the call result.

#### Firing a log message.

    $GLOBALS['log']->message(MGW_INFO, 'This is a info message.', __LINE__, __FILE__);

If you want to force logging even if a particular log level is turned off, you can specify a boolean as fifth parameter. If you set this to true, the message is logged forcibly. But: if logging is disabled generally, the message will be discarded regardless of this setting!

Finally you can specify another optional parameter (a string), to overwrite the module name associated with the message. Ususally this is taken from $myEnv, so you generally shouldn't need this.

#### Firing an extended log message.

    $GLOBALS['log']->message(MGW_NOTICE, 'Forced logging under a manually set module name.',
                             __LINE__, __FILE__, true, 'test');

Use those calls wherever you see fit, and try to distribute them logically throughout the code. The main purpose is tracking what the code really does to aid debugging, so you might want to log error messages, checkpoints reached, ...

## Notification functions

A user usually expects some feedback from a computer. So if the user created a new entry, deleted something or executed some other function, you might want to output a message indicating success or notifying the user about an error that occurred. This is where the notification comes into play, plus it offers a few more nifty features.

This is not intended to create a debugging log of what is happening internally to the module. Have a look at the logging functions for this!

### Using notification in more.groupware

In the settings module, in the general section, are a few notification settings. Some are accessible for all users, some are for admin users only. Those are explained elsewhere in the manual.

You can always trigger notification with one simple function call. The framework knows about several types of messages, namely NOTIFY_SCREEN, NOTIFY_MIM and NOTIFY_MAIL. Those are predefined constants you can use right away.

In appconfig the notification class is initiated and can be reached anywhere using $GLOBALS['notify']. Use the function $GLOBALS['notify']->message() to make use of it. (If you noticed the similarity to the logging function - yes, this is intentional.)

The types of message available are the following: NOTIFY_SCREEN spools a message for direct display on the screen, either below the sub menu or as a JavaScript alert() window (depending on user settings). Those messages will be shown upon next page load, for users not currently logged in those messages are stored and displayed at the next login. If used for the current user, this is perfect for displaying results of user actions.

NOTIFY_MIM sends an instant message to the target user's MIM. This can be used to notify users of new items that have been created or, as in todo and calendar, to inform about delegated items and new appointments.

NOTIFY_MAIL can be used to send a message through email. This does not use the webmail2 module, but uses PHP's mail() function. This may cause problems on some systems, and will eventually be changed.

#### Displaying a success message.

    $GLOBALS['notify']->message(NOTIFY_SCREEN, 'Item creation succeeded.');

The example above is the most simple way of using notification. The message will be displayed for the current user upon next page load (in most cases 'right after the call', when $smarty->display() is called).

to be continued...

## Database handling

Handling database connections, fetching results, preparing input values... Remember to read the ADOdb manual as well!

## SQL portability

We want to support more than just MySQL. That's why we use ADOdb. But to make moregroupware portable you need to do more than just a database abstraction layer. You need to write portable SQL statements as well. We learned that the hard way, and you can profit from that experience...

## Date and time handling

Date and time handling. You need to make sure that date and time values are formatted according to the user's preference settings, you need the user to input date and time values, and need to parse input submitted by the user? This section is for you.

## Templates with Smarty

Smarty is the template engine used in moregroupware. Read this to get a head start on it and the templates and techniques used in moregroupware.

## Session usage

We heavily rely on PHP's session management. This discusses the standard ways of using session variables in moregroupware and introduces you to some predefined variables and objects.

### Using session standards in more.groupware

Since we want more.groupware to work with register_globals being set to off, always use $_SESSION to access session variables!

When using $_SESSION (as we do), the use of functions like session_register() or session_is_registered() is forbidden (see PHP manual). Instead one should assign values to the $_SESSION array directly, and use isset() instead of session_is_registered().

There are a few things always available in the $_SESSION array for use in your module. One of those things is $_SESSION['MGW'], which is an instance of the MGW class, and holds information about the current user (e.g. $_SESSION['MGW']->userid) and some more interesting things. There is $_SESSION['MGW']->settings, which holds all of the user settings, there are the users rights, and more.

You do not need to worry about starting the session usually. If you work on a regular module, the session will be started by the more.groupware code for you.

#### Checking for the ID and rights of the current user.

Here we do two things together. We check for the ID of the current user and access the user rights information.Be aware that those will hopefully change ASAP!

    if(($_SESSION["MGW"]->rights["contact"]->modify and $row["owner"] == $_SESSION["MGW"]->userid)
       OR ($_SESSION["MGW"]->rights["contact"]->modify_others and $row["owner"] <> $_SESSION["MGW"]->userid)) {
        $editlink = "<a href=\"".$_SERVER['PHP_SELF']."?mod=contact&amp;obj=person&amp;view=editform&amp;id=$myid&amp;act=$action&amp;searchterm=$searchterm&amp;list=$list&amp;npage=$curr_page&amp;".SID."\" class=\"edit\">".$icons["edit"]."</a>";
    }
    else {
        $editlink = "";
    }

#### Checking for user settings.

Note the third line, there we check the use_webmail setting.

    function linkEmail($email){
        if($email!=""){
            if($_SESSION["MGW"]->settings["use_webmail"] == 1) $email="<a href=\"../webmail2/index.php?rightframe=".rawurlencode("sendmail.php?to=".$email)."&amp;".SID."\">".$email."</a>";
    	else $email = "<a href=\"mailto:".$email."\">".$email."</a>";
        }
        return $email;
    }

### Passing sessions around in more.groupware

There was a problem with conflicting session names, caused relying on the default session name provided by PHP (see bug #550122 and feature request #564819) when using more than one application using sessions simultaneously.

So we want this to be something other then PHPSESSID, it defaults to MGWSESSID, and is configurable in config.inc.php. To make this work, a few things are needed:

- Before every session_start(), a call to session_name() has to be done. There are only a few places where this is needed. If you are writing a module there should be no need to worry about this.

- The must not use $PHPSESSID (or $MGWSESSID). If this is used, links will stop to work after changing the session name. Use the constant SID instead!

- Templates must use {$SESSION} when creating links directly, and use {$SESSIONNAME} and {$SESSIONID} when creating hidden input fields in forms.

There are three Smarty assignments in appconfig.inc, these populate the variables explained in above.

The following examples show typical uses of the variables explained above. The first shows how to create a hidden form field for passing the session. The second show a line from a template creating a simple link. The third shows how to create HTML links in PHP.

#### Creating a hidden form field for session passing.

    <form name="f1" action="{$phpself}" method="POST">
    <input type="hidden" name="{$SESSIONNAME}" value="{$SESSIONID}" />
     ...
    </form>

#### Creating a regular link for session passing.

    <a href="index.php?mod=todo&amp;obj=item&amp;view=newform&amp;{$SESSION}" class="new">{$new}</a>

Note the use of the predefined (uppercase) variables in Smarty. Those get defined in appconfig.inc. The following example uses the standard PHP constant SID.

#### Creating a regular link for session passing in PHP.

    // build action urls
    $detlink = "<a href=\"".$_SERVER['PHP_SELF']."?mod=todo&amp;obj=item&amp;view=details&amp;id=$myid&amp;ty=dto&amp;".SID."\" CLASS=\"edit\">".$icons["details"]."</a>";
    $editlink = "<a href=\"".$_SERVER['PHP_SELF']."?mod=todo&amp;obj=item&amp;view=editform&amp;id=$myid&amp;".SID."\" CLASS=\"edit\">".$icons["edit"]."</a>";

### Storing per-module information in the session

The todo module uses $_SESSION["todo"][...] to store the state of viewing (current items/archive) and the searchterm used in searching. This makes those persistent, without having to worry about each and every link, and whether it adds those to the URL, or not. Other modules might store more, e.g. the current page being viewed, if paged result sets are used.

Just use the name of your module as the first array index, to avoid name clashes and overwriting other information.

## Using the settings module

As soon as you want the users to be able to change the behaviour of a module you need a possibility to manage user preferences. The moregroupware settings module makes this a lot easier. Read on for the gory details...