Contents

   1. ApplicationDevelopmentGuide/Introduction
         1. Overview of application writing
         2. What does the eGroupWare API provide?
   2. ApplicationDevelopmentGuide/Guidelines
         1. Requirements
         2. Writing/porting your application
   3. ApplicationDevelopmentGuide/InstallingYourApplication
         1. Overview
         2. Automatic features
         3. Adding files, directories and icons.
         4. Making eGroupWare aware of your application
         5. Hooking into Administration page
         6. Hooking into Preferences page
   4. ApplicationDevelopmentGuide/Infrastructure
         1. Overview
         2. Directory tree
         3. Translations
   5. ApplicationDevelopmentGuide/APIGuide
         1. API Hooks
         2. API index.php
         3. API setup
         4. API templates
         5. API-BO
         6. API-SO
         7. API-UI
         8. Deprecated APIs
   6. ApplicationDevelopmentGuide/APIFunctions
         1. Introduction
         2. Basic functions
         3. Application Functions
         4. File functions
         5. Email/NNTP Functions
         6. Content History
   7. ApplicationDevelopmentGuide/ConfigurationVariables
         1. Introduction
         2. User information
         3. Group information
         4. Server information
         5. Database information
         6. Mail information
         7. NNTP information
         8. Application information
   8. ApplicationDevelopmentGuide/UsingLanguageSupport
         1. Overview
         2. How to use lang support
         3. Common return codes
   9. ApplicationDevelopmentGuide/UsingTemplates
         1. Overview
         2. How to use PHPLIB templates
  10. ApplicationDevelopmentGuide/eTemplateReferenz
         1. Introduction - The concept of the eTemplates
         2. The xml-interface to the eTemplates
         3. Syntax and Parameter Referenz
         4. How to implement new widgets / extensions to the eTemplates?



Installing your application
Overview

It is fairly simple to add and delete applications to/from eGroupWare.

Adding files, directories and icons.
Guidelines
Requirements
Introduction
eGroupWare is a web based groupware application framework (API), for writing applications. Integrated applications such as email, calendar, todo list, address book, and file manager are included.

Overview of application writing

We have attempted to make writing application for eGroupWare as painless as possible. We hope any pain and suffering is cause by making your application work, but not dealing with eGroupWare itself.

What does the eGroupWare API provide?

The eGroupWare API handles session management, user/group management, has support for multiple databases, using the PHPLIB database abstraction method, we support templates using the PHPLIB Templates class, a file system interface, and even a network i/o interface.

On top of these standard functions, eGroupWare provides several functions to give you the information you need about the users environment, and to properly plug into eGroupWare.

These guidelines must be followed for any application that wants considered for inclusion into eGroupWare deluxe:

    * It must run on PHP4.1.0
    * SQL statements must be compatible with both MySQL, PostgreSQL, M$ SQL Server and MaxDB
    * It must use our default header.inc.php include.
    * It must use our $GLOBALS['phpgw']->link($url) for all links (this is for session support).
    * It must use "POST" for form submit methods.
    * It must respect eGW group rights and eGW user permissions.
    * It must use our directory structure, template support and lang (multi-language) support.
    * Where possible it should run on both Unix and NT platforms.
    * For applications that do not meet these requirements, they can be available to users via the eGroupWare "3rd Party Apps" listing on our website. If you need help converting your application to templates and our lang support, we will try to connect you with someone to help.


Writing/porting your application

Include files

Each PHP page you write will need to include the header.inc.php along with a few variables.
This is done by putting this at the top of each PHP page.

<?php
$GLOBALS['phpgw_info']['flags']['currentapp'] = 'appname';
include('../header.inc.php');
?>



Of course change application name to fit.
This include will provide the following things:

    * The phpgwAPI - The eGroupWare API will be loaded.
    * The eGW navbar will be loaded (by default, but can be disabled until a later point.
    * The eGW footer will be loaded, which closes several connections.


Additionally, to provide compatibility with stock applications, these files will be included:

    * appname/inc/functions.inc.php - This file is loaded just after the phpgwAPI and before any HTML code is generated. This file should include all your application specific functions.. Stock applications include any additional files needed from within this file.
    * appname/inc/header.inc.php - This file is loaded just after the system header/navbar, and allows developers to use it for whatever they need to load.
    * appname/inc/footer.inc.php - This file is loaded just before the system footer, allowing developers to close connections and whatever else they need.


Note: The above 3 files are depricated and not used for OOP (/index.php?menuaction=app.obj.method) calls.

You will need to create the following directories for your code
(replace 'appname' with your application name)

--appname

  +--inc

  |   |--functions.inc.php

  |   |--header.inc.php

  |   |--hook_preferences.inc.php

  |   |--hook_admin.inc.php

  |   +--footer.inc.php

  +--js

  |   |--base

  |   +--js_package_name

  +--setup

  |   |--default_records.inc.php

  |   |--setup.inc.php

  |   +--tables_current.inc.php

  +--templates

      +--default


Making eGroupWare aware of your application

To make the application aware of your application, add your application details to the applications table. This can be done via the GUI administration screen, or via a SQL script. The script below should only be used during initial development. You should use the eGroupWare setup system for install and updating the final version of your application.

INSERT INTO phpgw_applications (app_name, app_title, app_enabled)
        VALUES('appname', 'The App name', 1);
Administration / Site configuration
The Site configuration stores site-wide applications settings and is only accessible by Admins.
The format is the same as for the hook_preferences, but its called <app>/inc/hook_admin.inc.php. Here is an example:

{
   $file = Array(
      'Site configuration' => $GLOBALS['phpgw']->link('/index.php',array(
         'menuaction' => 'admin.uiconfig.admin',
         'appname'    => $appname
      )),
      'Global Categories'  => $GLOBALS['phpgw']->link('/index.php',array(
         'menuaction' => 'admin.uicategories.index',
         'appname'    => $appname,
         'global_cats'=> 'True'
      ))
   );
   //Do not modify below this line

   display_section($appname,$file);
}

Again you dont need the Global Categories if your app does not use Categories and you can use your own function if for the site-config if your app has special requirements, you can realice with the existing with uiconfig which uses a old phplib-template (atm. you should look for the config.tpl of one of the apps).
Please note the display_section-call has only 2 parameters from 0.9.16 on, as the app-title is generated by the applications class.

If you have addition please add them here or mail them to ralfbecker

Preferences
Preferences are are used to store settings on a per user basis.
Admins can give defaults and force preferences to certain values (the users can't change and does not get shown).
Preferences can have more descriptive helptexts which get shown when the user clicks on [Help] or has helptexts as default enabled in his prefs.
How to enable an app to use preferences and specialy the user/default/forced tabs ?
You need to setup 2 files / hooks for your applications:

1. <app>/inc/hook_preferences.inc.php: This file defines a Section for your app in the users preferences.
{
// Only Modify the $file variables.....

    $file = array(

        'Preferences' => $GLOBALS['phpgw']->link('/preferences/preferences.php','appname='.$appname),
        'Grant Access' => $GLOBALS['phpgw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
        'Edit Categories' => $GLOBALS['phpgw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . &cats_level=True&global_cats=True')

    );

//Do not modify below this line

    display_section($appname,$file);

}
Cause you can skip the Grant Access and Edit Categories sections, if you dont use ACL and/or Categories.
Please note the display_section-call has only 2 parameters from 0.9.16 on, as the app-title is generated by the applications class and placed in $GLOBALS['phpgw_info']['apps'][<app>]['title'] to be accessed by all apps.

2. <app>/inc/hook_settings.inc.php: This file defines the certain input-fields with labels, helptexts, names and defaults for your preferences.

The 3 types of prefs (user/default/forced) are handled by the preferences-app, you dont have to care.
All input-fields have min. two necessary and more optional parameters:

   1. label is displayed in front of the input field. Dont use a lang()-call on it, thats done by the prefs itself.
   2. name is a string under which u will later find the preference in $GLOBALS['phpgw_info']['user']['preferences'][<app>][<name>]
   3. helptext optional, if helptexts are availible, a button is shown for the user to switch them on/off
   4. default a default-value (only for the user-prefs and not for passwords)

    Some input types have more params availible, see there.


This are the types of input-fields availible:

    * Inputboxes: The are for entering strings and can have 2 optional parameters length and max-length

    create_input_box('Enter prefix (max. 40 chars)','prefix','long help text','phpgw_',20,40);

    * Checkboxes: The value is either '1' or '0' which evaluates to True and False in php. You can't have '' as this cant be set as default or forced preference !

    create_check_box('Show on main screen','homeShowEvents','long help text',1);

    * Selectboxes: Beside the 4 standard params, the selectboxes have a 5 prameter which is an array with value - label pairs.

    The label is shown in the selectbox and the value is returned as preference when the label is selected.
    create_select_box('Default Filter for InfoLog','defaultFilter',array('own' => 'own Items','others' => 'other peoples stuff'),'long help text','own');
    (Please note the array with the options is the 3. parameter, helptext and default are following as 4. and 5. parameter !!!)

    * Textarea: The are for entering a bigger, multiline Text. They have 2 extra parameters rows and cols:

    create_text_area('Signature','sig','long help text','--',4,40);

    * Passwordbox: it hides its content by displaying asterixes while entering and an empty field (which is not saved) while updateing.

    create_password_box('Password (max. 12 chars)','password','choose a good one',12,12);

    * Headers: You can have one or more header-lines with a descriptive text as a kind of paragraph headings. They are in the table-header-color and in bold writeing. To do so call the function show_list(lang('Headertext')); after (!) each paragraph. If you dont call it, it is called automaticaly at the end and displays and empty header-line.


3. As all hooks they have to be registered in <app>/setup/setup.inc.php (only the hooks part is shown here):

    $setup_info[<app>]['hooks'][] = 'preferences';
    $setup_info[<app>]['hooks'][] = 'settings';

Hooks get installed whit the app by setup or when you manualy call Admin / Find and Register all Application Hooks.
Proposal: Changes for Preferences
In short: A new column app_name should be add to phpgw_preferences, to allow apps to set defaults and forced prefs (to not show all possible prefs after a new install) via their <app>/setup/default_records.inc.php.

Infrastructure
Overview

eGroupWare attempts to provide developers with a sound directory structure to work from. The directory layout may seem complex at first, but after some use, you will see that it is designed to accommodate a large number of applications and functions.

Directory treeS

--eGroupWare
  |
  +--admin
  |
  +--docs (installation docs)
  |
  +--files (Note: must be out of webserver document root!)
  |   |
  |   +--groups
  |   |
  |   +--homes
  |   |
  |   +--users
  |
  +--phpgwapi
  |   |
  |   +--cron (eGroupWare's optional daemons)
  |   |
  |   +--doc (developers docs)
  |   |
  |   +--inc
  |   |   |
  |   |   +--class.phpgw.inc.php
  |   |   |
  |   |   +--phpgw_info.inc.php
  |   |   |
  |   |   +--class.common.inc.php
  |   |   |
  |   |   +--etc..
  |   |
  |   +--js (javascript)
  |   |   |
  |   |   +--base
  |   |   |
  |   |   +--js_package_name
  |   |
  |   +--manual
  |   |
  |   +--setup
  |   |   |
  |   |   +--baseline.inc.php
  |   |   |
  |   |   +--default_records.inc.php
  |   |   |
  |   |   +--tables_current.inc.php
  |   |   |
  |   |   +--tables_update.inc.php
  |   |
  |   +--templates
  |   |   |
  |   |   +--default
  |   |   |   |
  |   |   |   +--images
  |   |   |
  |   |   +--verilak
  |   |       |
  |   |       +--images
  |   |
  |   +--themes
  |       |
  |       +--default.theme
  |
  +--preferences
  |
  +--setup



Translations

The translations are now being done through the database, and may be configurable to use other mechanisms in future releases.

You can use the developer_tools translations application for creating the "lang files", which will be installed through the setup application. Alternatively you can edit the files manually. The file naming convention for the lang files is phpgw_<langcode>.lang. The files are stored in the app/setup directory. The format of the files is as follows:

english phrase in lower case    appname **      Translated phrase in desired case.


Notes:

    * replace ** with the desired language code, as used in the filename
    * tabs are used to deliniate "columns"
The eGroupWare (“eGW”) suite of applications is built upon a very powerful, flexible set of APIs, referred to as phpgwapi. This document will introduce you to the architecture and the major components, allowing you to start programming for eGW quickly, whether working on an existing application or building your own project.

The APIs allow you to separate the HTML code from the application logic, which makes development and maintenance of the application much simpler. It is recommended that you utilize this model whenever possible Within the PHP code, Within the PHP code, all eGW applications should be written to use a three-tier structure, which separates the user interface (“UI”) components from the business rules (“BO”) and from the data manipulation (“SO”) routines. This ensures proper data encapsulation and integrity of the system by avoiding function or variable name collisions.

Here is the directory/file structure that should be used for all new and converted applications:

    * eGroupWare Root (ex. /var/www/html/egroupware/)
          o myapp/
                + index.php (stub entry point)
                + templates/
                      # default/ (required)
                            * *.tpl
                      # idots/ (optional)
                            * *.tpl
                      # ... (optional)
                + inc/
                      # class_ui*.inc.php
                      # class_bo*.inc.php
                      # class_so*.inc.php
                      # hook_*.inc.php
                      # functions.inc.php (deprecated)
                      # header.inc.php (deprecated)
                + setup/
                      # setup.inc.php
                      # phpgw_*.lang
                      # tables_*.inc.php


For those developers interested in porting a PHP application to phpgwapi, check the eGW website for the App Conversion Guide.


The only script called directly by the browser should be the index.php script in eGroupWare's root directory. The query string argument menuaction indicates to the system which application and method to load. This argument is comprised of three components: an application name, a class, and a method. For example, given myapp.ui.runme, eGW knows to load the application myapp through the class ui, and call the method runme.

A simple index.php file should be included in the application's top directory, which sets certain phpgwapi flags and then calls ExecMethod on the primary function, typically named index, located in one of the UI classes.

The Template class in phpgwapi is used to fill in the *.tpl files of your application. Use of this class can be a little tricky, but once you learn how it works, it proves to be very flexible in how you present your application's interface.

[Click here] for an introduction to the Template system, which is based on [PHPlib]'s [template] system.

Business Object Components

These classes encapsulate the business rules that should be applied to the data before displaying to the user. An example function is one that pulls data using an SO class, performs some calculations on the result set, then passes the data up to the calling UI class for display to the user.

Similar to the UI filenames, the BO classes should be in contained in files under <appname>/inc/, named class.bo<section>.inc.php.

These classes should contain a member variable $so named for the corresponding SO classes.

Storage Object Components

The methods in these classes are responsible for communicating with a back-end storage service, such as a database or LDAP directory. This is also the right time to clean up the data for processing, such as removing trailing whitespace from the fields in a database result set.

As noted in the BO notes, the SO classes should be contained in files under <appname>/inc/, named class.so<section>.inc.php.

These classes may contain a member variable $db as a shortcut to the global variable $GLOBAL['phpgw']->db.

User Interface Components

Only the methods in the UI classes should generate code to the client. This includes X/HTML, XML, PNG image data, or any other data that goes directly to the browser. And these are the only methods that should be called directly through the browser via the menuaction query string argument. This is enforced through the use of the $public_functions array, defined at the top of the class. eGW will check that a called method is in this array before executing it.

Note that you may need methods that generate HTML but that are not called directly, such as a helper method that just generates a drop-down menu. These helper methods do belong in a UI class, but should not be listed in the $public_functions array.

A relatively small application may have need of only one UI class, in which case the PHP file should be contained in files under <myapp>/inc/, named class.ui.inc.php. If you need or want to split your UI functions into multiple sections, then the filename should be class.ui<section>.inc.php. For instance, the calendar app has uicalendar, uialarm, and uiholiday, among others. This makes it easier to identify a given file's use.

These classes should contain a member variable $bo named for the corresponding BO* classes. All other variables should be used strictly for the purpose of UI generation, and the use of $GLOBAL variables should be minimized.

    *  <myapp>/inc/functions.inc.php
          o This is the container for all non-class functions, which are loaded into the current script's global execution space. Because of the potential for name collisions and “weirdness”, the use of this file is discouraged by the eGW development team.
    * <myapp>/inc/header.inc.php
          o This file will be used to execute a set of commands at the same location on every page. The use of this file is deprecated, in favor of building the functionality into the application's templates and/or UI methods.

The API
Introduction

eGroupWare attempts to provide developers with a useful API to handle common tasks. To do this we have created a multi-dimensional class $GLOBALS['phpgw']->.

This allows for terrific code organization, and help developers easily identify the file that the function is in. All the files that are part of this class are in the inc/core directory and are named to match the sub-class.

Example: $phpgw->send->msg() is in the inc/phpgwapi/class.send.inc.php file. (Edit this: this way is depreciated.)

Basic functions

$GLOBALS['phpgw']->link

$GLOBALS['phpgw']->link($url, $args)


Add support for session management. ALL links must use this, that includes href's form actions and header location's.

If you are just doing a form action back to the same page, you can use it without any parameters.

This function is right at the core of the class because it is used so often, we wanted to save developers a few keystrokes. Example:

<form name=copy method=post action="<?php echo $GLOBALS['phpgw']->link();?>">
/* If session management is done via passing url parameters */
/* The the result would be */
/* <form name=copy method=post action="somepage.php?sessionid=87687693276?kp3=kjh98u80"> */


Application Functions

$GLOBALS['phpgw']->common->phpgw_header

$GLOBALS['phpgw']->phpgw_header()
Print out the start of the HTML page, including the navigation bar and includes appname/inc/header.php, if using deprecated linear scripts style.
$GLOBALS['phpgw']->common->phpgw_footer

$GLOBALS['phpgw']->phpgw_footer()
Prints the system footer, and includes appname/inc/footer.php
$GLOBALS['phpgw']->common->appsession

$GLOBALS['phpgw']->common->appsession($data)
Store important information session information that your application needs.
$GLOBALS['phpgw']->appsession will return the value of your session data is you leave the parameter empty [i.e. $GLOBALS['phpgw']->appsession()], otherwise it will store whatever data you send to it.
You can also store a comma delimited string and use explode() to turn it back into an array when you receive the value back.

Example:

$GLOBALS['phpgw']->common->appsession("/path/to/something");
echo "Dir: " . $GLOBALS['phpgw']->common->appsession();


File functions

See Virtual File System (VFS) Developers Guide for more info.

Email/NNTP Functions

$phpgw->send->msg

$phpgw->msg->send($service, $to, $subject, $body, $msgtype, $cc, $bcc)
Send a message via email or NNTP and returns any error codes.
Example:

$to = 'someuser@domain.com';
$subject = 'Hello buddy';
$body = "Give me a call\n Been wondering what your up to.";
$errors = $GLOBALS['phpgw']->msg->send('email', $to, $subject, $body);


The API
Introduction

eGroupWare attempts to provide developers with a useful API to handle common tasks.

To do this we have created a multi-dimensional class $GLOBALS['phpgw']->.

This allows for terrific code organization, and help developers easily identify the file that the function is in. All the files that are part of this class are in the inc/core directory and are named to match the sub-class.

Example: $phpgw->send->msg() is in the inc/phpgwapi/class.send.inc.php file. (Edit this: this way is depreciated.)

Basic functions

$GLOBALS['phpgw']->link

$GLOBALS['phpgw']->link($url, $args)


Add support for session management. ALL links must use this, that includes href's form actions and header location's.

If you are just doing a form action back to the same page, you can use it without any parameters.

This function is right at the core of the class because it is used so often, we wanted to save developers a few keystrokes. Example:

<form name=copy method=post action="<?php echo $GLOBALS['phpgw']->link();?>">
/* If session management is done via passing url parameters */
/* The the result would be */
/* <form name=copy method=post action="somepage.php?sessionid=87687693276?kp3=kjh98u80"> */


Application Functions

$GLOBALS['phpgw']->common->phpgw_header

$GLOBALS['phpgw']->phpgw_header()
Print out the start of the HTML page, including the navigation bar and includes appname/inc/header.php, if using deprecated linear scripts style.
$GLOBALS['phpgw']->common->phpgw_footer

$GLOBALS['phpgw']->phpgw_footer()
Prints the system footer, and includes appname/inc/footer.php
$GLOBALS['phpgw']->common->appsession

$GLOBALS['phpgw']->common->appsession($data)
Store important information session information that your application needs.
$GLOBALS['phpgw']->appsession will return the value of your session data is you leave the parameter empty [i.e. $GLOBALS['phpgw']->appsession()], otherwise it will store whatever data you send to it.
You can also store a comma delimited string and use explode() to turn it back into an array when you receive the value back.

Example:

$GLOBALS['phpgw']->common->appsession("/path/to/something");
echo "Dir: " . $GLOBALS['phpgw']->common->appsession();


File functions

See Virtual File System (VFS) Developers Guide for more info.

Email/NNTP Functions

$phpgw->send->msg

$phpgw->msg->send($service, $to, $subject, $body, $msgtype, $cc, $bcc)
Send a message via email or NNTP and returns any error codes.
Example:

$to = 'someuser@domain.com';
$subject = 'Hello buddy';
$body = "Give me a call\n Been wondering what your up to.";
$errors = $GLOBALS['phpgw']->msg->send('email', $to, $subject, $body);

Description

This class keeps track of added, modified and deleted entries for eGroupWare applications and is currently integrated into following eGroupWare applications:

    * Calendar
    * AddressBook
    * InfoLog


Global UID's

Because this class was designed in the first place to support SycnML it is working global UID's. It always returns global UID's. There are functions in phpgwapi which translates them back to UID's again.

Why global UID's?

Inside eGroupWare any application has it's own tables. This allows any application to have it's own numbering schema. But that's not neccesary the same when we synchronize with some other device(for example mobile phone or other eGroupWare installation). When working with global UID's you make sure that there can't be any collision with UID's.

How does a global UID look like?

<appname>-<uid>-<eGroupWare systemid>

Using the class

The class is available for any application as

$GLOBALS['egw']->contenthistory

The class provides 3 functions:
getHistory($_appName, $_action, $_ts)
This function returns all GUID's of entries which got addeded, modified or deleted since the given timestamp.

Example:
$GLOBALS['egw']->contenthistory->getHistory('calendar', 'changed', '103483821');

getTSforAction($_guid, $_action)
This function returns a timestamp when a GUID got added, modified or deleted.

Example:
$GLOBALS['egw']->contenthistory->getTSforAction('calendar-123-7s7dzf8szddfzsd@example.org', 'added');

updateTimeStamp($_appName, $_id, $_action, $_ts)
This function updates the timestamp when an entry got added, modified or deleted. This function get's called from inside the applications.

Example:
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', '123', 'deleted', '103483821');

    
Google

this site the web
Update Notification
Enter the email to be notified about changes of the website:
Unsubscribe
all languages
Amazon
[Web Database Applications with PHP & MySQL : Buy at amazon.com]
Web Database Applications with PHP & MySQL

Configuration Variables
Introduction

eGroupWare attempts to provide developers with as much information about the user, group, server, and application configuration as possible.

To do this we provide a multi-dimensional array called "$GLOBALS['egw_info']", which includes all the information about your environment.

Due to the multi-dimensional array approach. getting these values is easy.

Here are some examples:

<?php
// To do a hello username
echo "Hello " . $GLOBALS['egw_info']['user']['fullname'];
//If username first name is John and last name is Doe, prints: 'Hello John Doe'
?>
<?php
// To find out the location of the imap server
echo 'IMAP Server is named: ' . $GLOBALS['egw_info']['server']['imap_server'];
//If imap is running on localhost, prints: 'IMAP Server is named: localhost'
?>


User information

$GLOBALS['egw_info']['user']['userid'] = The user ID.
$GLOBALS['egw_info']['user']['sessionid'] = The session ID
$GLOBALS['egw_info']['user']['theme'] = Selected theme
$GLOBALS['egw_info']['user']['private_dir'] = Users private dir. Use eGroupWare core functions for access to the files.
$GLOBALS['egw_info']['user']['firstname'] = Users first name
$GLOBALS['egw_info']['user']['lastname'] = Users last name
$GLOBALS['egw_info']['user']['fullname'] = Users Full Name
$GLOBALS['egw_info']['user']['groups'] = Groups the user is a member of
$GLOBALS['egw_info']['user']['app_perms'] = If the user has access to the current application
$GLOBALS['egw_info']['user']['lastlogin'] = Last time the user logged in.
$GLOBALS['egw_info']['user']['lastloginfrom'] = Where they logged in from the last time.
$GLOBALS['egw_info']['user']['lastpasswd_change'] = Last time they changed their password.
$GLOBALS['egw_info']['user']['passwd'] = Hashed password.
$GLOBALS['egw_info']['user']['status'] = If the user is enabled.
$GLOBALS['egw_info']['user']['logintime'] = Time they logged into their current session.
$GLOBALS['egw_info']['user']['session_dla'] = Last time they did anything in their current session
$GLOBALS['egw_info']['user']['session_ip'] = Current IP address


Important Note: If you wish to remain application compatibility with phpgroupware, or you wish your application works in the 1.x branch of egroupware, you should use $GLOBALS['phpgw_info'] instead. However $GLOBALS['egw_info'] will be no longer supported or updated, and might be removed from future version.

Group information

$GLOBALS['egw_info']['group']['group_names'] = List of groups.


Server information

$egw_info[``server''][``server_root''] = Main installation directory $egw_info[``server''][``include_root''] = Location of the 'inc' directory. $egw_info[``server''][``temp_dir''] = Directory that can be used for temporarily storing files $egw_info[``server''][``files_dir''] = Directory er and group files are stored $egw_info[``server''][``common_include_dir''] = Location of the core/shared include files. $egw_info[``server''][``template_dir''] = Active template files directory. This is defaulted by the server, and changeable by the user. $egw_info[``server''][``dir_separator''] = Allows compatibility with WindowsNT directory format $egw_info[``server''][``encrpytkey''] = Key used for encryption functions $egw_info[``server''][``site_title''] = Site Title will show in the title bar of each webpage. $egw_info[``server''][``webserver_url''] = URL to eGroupWare installation. $egw_info[``server''][``hostname''] = Name of the server eGroupWare is installed upon. $egw_info[``server''][``charset''] = default charset, default:iso-8859-1 $egw_info[``server''][``version''] = eGroupWare version.


Database information

It is unlikely you will need these, because $GLOBALS['egw']->db will already be loaded as a database for you to use.
$egw_info[``server''][``db_host''] = Address of the database server. Usually this is set to localhost. $egw_info[``server''][``db_name''] = Database name. $egw_info[``server''][``db_user''] = User name. $egw_info[``server''][``db_pass''] = Password $egw_info[``server''][``db_type''] = Type of database. Currently MySQL and PostgreSQL are supported.


Mail information

It is unlikely you will need these, because most email needs are services thru core eGroupWare functions.

$egw_info[``server''][``mail_server''] = Address of the IMAP server. Usually this is set to localhost.
$egw_info[``server''][``mail_server_type''] = IMAP or POP3
$egw_info[``server''][``imap_server_type''] = Cyrus or Uwash
$egw_info[``server''][``imap_port''] = This is usually 143, and should only be changed if there is a good reason.
$egw_info[``server''][``mail_suffix] = This is the domain name, used to add to email address
$egw_info[``server''][``mail_login_type''] = This adds support for VMailMgr. Generally this should be set to 'standard'.
$egw_info[``server''][``smtp_server''] = Address of the SMTP server. Usually this is set to localhost.
$egw_info[``server''][``smtp_port''] = This is usually 25, and should only be changed if there is a good reason

NNTP information

$egw_info[``server''][``nntp_server''] = Address of the NNTP server.
$egw_info[``server''][``nntp_port''] = This is usually XX, and should only be changed if there is a good reason.
$egw_info[``server''][``nntp_sender''] = Unknown
$egw_info[``server''][``nntp_organization''] = Unknown
$egw_info[``server''][``nntp_admin''] = Unknown


Application information

Each application has the following information available.

$egw_info[``apps''][``appname''][``title''] = The title of the application.
$egw_info[``apps''][``appname''][``enabled''] = If the application is enabled. True or False.
$egw_info[``server''][``app_include_dir''] = Location of the current application include files.
$egw_info[``server''][``app_template_dir''] = Location of the current application tpl files.
$egw_info[``server''][``app_lang_dir''] = Location of the current lang directory.
$egw_info[``server''][``app_auth''] = If the server and current user have access to current application
$egw_info[``server''][``app_current''] = name of the current application.

Using Language Support
Overview

eGroupWare is built using a multi-language support scheme. This means the pages can be translated to other languages very easily. Translations of text strings are stored in the eGroupWare database, and can be modified by the eGroupWare administrator.

How to use lang support

The lang() function is your application's interface to eGroupWare's internationalization support.

While developing your application, just wrap all your text output with calls to lang(), as in the following code:

$x = 42;
echo lang("The counter is %1",$x)."<br>";


This will attempt to translate ``The counter is %1'', and return a translated version based on the current application and language in use. Note how the position that $x will end up is controlled by the format string, not by building up the string in your code. This allows your application to be translated to languages where the actual number is not placed at the end of the string.

When a translation is not found, the original text will be returned with a * after the string. This makes it easy to develop your application, then go back and add missing translations (identified by the *) later.

Without a specific translation in the lang table, the above code will print:

The counter is 42*<br>

If the current user speaks Italian, they string returned may instead be:

il contatore è 42<br>;

The lang function

lang($key, $m1="", $m2="", $m3="", $m4="", $m5="",
        $m6="", $m7="", $m8="", $m9="", $m10="")


    [$key ]
        is the string to translate and may contain replacement directives of the form %n.

    [$m1 ]
        is the first replacement value or may be an array of replacement values (in which case $m2 and above are ignored).

    [$m2 - $m10 ]
        the 2nd through 10th replacement values if $m1 is not an array.


The database is searched for rows with a lang.message_id that matches $key. If a translation is not found, the original $key is used. The translation engine then replaces all tokens of the form %N with the Nth parameter (either $m1[N] or $mN).
Adding translation data

The TranslationTools (former developer_tools) allow easily create new translations of eGW applications.
A developer also can use them to create the english lang-file by searching for new phrases in his sources.
The lang table

The translation class uses the lang table for all translations. We are concerned with 4 of the columns to create a translation:

    [message_id ]
        The key to identify the message (the $key passed to the lang() function). This is written in English.

    [app_name ]
        The application the translation applies to, or common if it is common across multiple applications.

    [lang ]
        The code for the language the translation is in.

    [content ]
        The translated string.


translating the content to reflect the message_id string in the lang language. If the string is specific to your application, put your application name in for app_name otherwise use the name common. The message_id should be in lower case for a small increase in speed.

Common return codes

If you browse through the eGroupWare sources, you may notice a pattern to the return codes used in the higher-level functions. The codes used are partially documented in the doc/developers/CODES file.

Codes are used as a simple way to communicate common error and progress conditions back to the user. They are mapped to a text string through the check_code() function, which passes the strings through lang() before returning.

For example, calling

echo check_code(13);

Would print

Your message has been sent


translated into the current language.

Overview

eGroupWare is built using a templates based design. This means the display pages, stored in tpl files, can be translated to other languages, made to look completely different.

How to use PHPLIB templates

For Further info read the PHPLIBs documentation for their template class. http://phplib.sanisoft.com


eTemplate is a new widget-based template system, which is used eg. for the InfoLog application.
There's a [Tutorial].

The eTemplateReferenz document is currently not migrated to wiki yet, for a (perhaps) wiki bug. I'll do it asap -- ZhangWeiwu


A Style Guide for eGroupWare descrtibes the comon look and feel of eGroupware.
Why do we need a Style Guide for eGroupWare ?
It influences:

    * how easily users get used to eGroupWare,
    * how much they apreciate and accept it,
    * see it as one system and not a bunch of single apps.
          o pobably the best thing to achieve this is designing a programm flow chart. Also helpfull for inside people and developers. Having a flowchart the user can see and diced better if this is what he want and need. (joao)


It is important that all apps and of cause the API adhear to the StyleGuide !!!

The eGroupWare StyleGuide should only differ for very good reason from other well known style guides like [KDE] or MSWindows, as that's what the users know and expect. The main justification for such a divergence would be that we are building a web application.

''We need a volunteer with good eGroupWare knowledge, not necessarly a developer, to create this document.

I just start adding stuff here, please comment on it !!! -- RalfBecker

    * application header: we have 3 types of application headers atm
         1. bold app-title above a horizontal ruler (sometimes with appended - <sub-function>)
         2. line in table-header background-color with bold app-title
         3. no header at all (eg. Calendar standard view and email for some views)
          o We need to decide for one type for a general app. I would prefer #1, as it allows to have some extra buttons / action icons right alligned above the ruler (eg. InfoLog Add Note/ToDo/Phonecall Icons)
          o Apps with a very unique look of there standard views like Calendar or Email might be ok without any app-header (#3) for these standard-views, but not for the other dialogs (eg. not the edit/add event in Calendar).
                + don know ... may be it is only a little bit more difficult to get this app ligned up (joao)
    * We created now a standard way to specify the application header, see App-Titles and iDots Sidebox Menu for the details. Which type of app-header to use, depends now on the selected template-set! -- RalfBecker
    * am I too late? I like ability to use a header with extra links/buttons but to maximum the available space, they should be under the application title (not right justified and in line with it). Also, I think extra buttons/links should be arranged in a table format which lends itself to the application title being a bold, shaded background, table header. IMO the most important thing on the page is NOT the app name (I know it, I clicked on it). With my 800x600 laptop display, screen real estate is reserved for valuable information


    * confirmation dialogs: eg. Delete the entry 'Testentry' ?
          o The text about the implications of the decision should be clear to all users
          o the message should contain a title/name of the entry to eg. delete
                + don't take this too hard, but I HATE confirmations and turn them off whenever possible. It takes an extra click and delay for page load. I have figured out what delete means and if I do it by accident and don't hit stop fast enough, I'll live with the consequences
                + that is ok but for the user we need then a clear app manual (joao)
                + Can't we use Javascript confirmation dialogs. Specially for slow connections it very irritating to load a new screen only for the confirmation. Maybe this can be a General Preference Setting? mipmip
                + java may be slow on certain PCs also, what about a simple html-pop-up showing only the relevant info or question? (joao)
          o Buttons (rather than links) should be used
                + - I prefer links over buttons for almost everything (buttons should be used sparingly). If I expect another screen to appear, I can open the link directly into a new window and continue working while waiting for it to load. Consider me a power user if you must but I have better things to do than wait for a page load
                + that also, the average user do not know about this possibilities (unless it is about certain downloads:) so not worth to build it in or explain it. Work applications should be straight and clear, step to step, 1-2-3, the average user will fill up his 8 hours and will no be a poweruser ... so more we build in more the company falls back to standard 'terminal-apps' (joao)
                + links look like web-pages not like applications and in my oppinion eGW should try to look like an application
          o Buttons should be in this order [Yes] [No] (if aplicable: [Cancel])
                + mhhh, I guess no -cancel- yes is the appropriate sequence the rightmost button ever should be the final decision, yes = save (joao)
          o If the Yes/No answer can be missunderstood, make it [Yes - Delete] [No - Cancel]
          o If the app has a app-header the confirmation dialog should have it too.
          o yes, valid for all table data, e-mail to reports, the action buttons shoul be on top of the list as well as on the button to, so the user can use the nearest ones (joao)
    * edit dialogs
          o should have lines in alternating colors and if applicable sub-headers in the table-header color
                + definitely, makes it much easier to read
          o should have left aligned [Save] and [Cancel] buttons and right aligned [Delete] / [Help] buttons - if required
          o don't know, I believe that the most logical sequence is from left to right, right aligned and the final action on the most right, so when I am in a data input form the YES or SAVE button should be in the rightmost position under the last form field. That is as handwriting. You set the point at the end of the last word, no need to go back to left ... (joao)
                + if the table layout (and total table width) is suitable, I prefer buttons centred within the columns. especially if they are close to alignment with the input boxes on the page (allows for an easy workflow/eye follow)


    * add dialogs
          o should have lines in alternating colors and if applicable sub-headers in the table-header color
          o should have left aligned [Add] and [Cancel] buttons and have right aligned [Clear] / [Help] buttons - if required



    * program flow
          o each dialog should return to the calling page / state, eg. if you click on edit in a list or entries, you should end there again
                + An App should give A standard output/error report after every action that is done. There must be a standard message box to show these mipmip
                + Like I wrote in usability, I believe that we have a wast space in the app title header. No need to have an extra line somewhere. This msg can appear n top of the app, right of the app header, another + it is ever visible
          o each dialog should have a cancel button, which returs without saveing to the previous page
          o this cancel button I like to discuss. For me a cancel button is a special button and most of the cancel buttons in most apps do not make any sense. Think about the meaning of the word! When I want a button which brings me b a c k then write return on it. The cancel button should be present (for me) only in situations where I need to confirm the final action: Do you really want to delete this data? Here I need CANCEL and YES. Going deaper even the famous OK is not correct. OK is a confirmation to a question but not the order to save data right. So on a input form may be should be a SAVE button and not a OK button. Let's find out what else and try to use better labels. (joao)
                + each dialog should go to next page anticipated to be desired most often by users. Program flow should be easy to follow and as intuitive as possible. Consider the browser back button my cancel function (I do)


    * preferences and admin/configuration should be made via the standard eGW functions, to
          o have a common look-and-feel
          o use the 3-level user/default/admin approach, to
                + be customizable by the admin (eg. admin can force/switch off certain unwanted prefs)
                + more comfortable to the user
          o use the long helptexts (most users and admin have no idea what most of our configurable options do)
          o see How to hook into Admin and Preferences for more on this


If you have comments or points to add please do so here or mail them to ralfbecker


Preferences
Preferences are are used to store settings on a per user basis.
Admins can give defaults and force preferences to certain values (the users can't change and does not get shown).
Preferences can have more descriptive helptexts which get shown when the user clicks on [Help] or has helptexts as default enabled in his prefs.
How to enable an app to use preferences and specialy the user/default/forced tabs ?
You need to setup 2 files / hooks for your applications:

1. <app>/inc/hook_preferences.inc.php: This file defines a Section for your app in the users preferences.
{
// Only Modify the $file variables.....

    $file = array(

        'Preferences' => $GLOBALS['phpgw']->link('/preferences/preferences.php','appname='.$appname),
        'Grant Access' => $GLOBALS['phpgw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
        'Edit Categories' => $GLOBALS['phpgw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . &cats_level=True&global_cats=True')

    );

//Do not modify below this line

    display_section($appname,$file);

}
Cause you can skip the Grant Access and Edit Categories sections, if you dont use ACL and/or Categories.
Please note the display_section-call has only 2 parameters from 0.9.16 on, as the app-title is generated by the applications class and placed in $GLOBALS['phpgw_info']['apps'][<app>]['title'] to be accessed by all apps.

2. <app>/inc/hook_settings.inc.php: This file defines the certain input-fields with labels, helptexts, names and defaults for your preferences.

The 3 types of prefs (user/default/forced) are handled by the preferences-app, you dont have to care.
All input-fields have min. two necessary and more optional parameters:

   1. label is displayed in front of the input field. Dont use a lang()-call on it, thats done by the prefs itself.
   2. name is a string under which u will later find the preference in $GLOBALS['phpgw_info']['user']['preferences'][<app>][<name>]
   3. helptext optional, if helptexts are availible, a button is shown for the user to switch them on/off
   4. default a default-value (only for the user-prefs and not for passwords)

    Some input types have more params availible, see there.


This are the types of input-fields availible:

    * Inputboxes: The are for entering strings and can have 2 optional parameters length and max-length

    create_input_box('Enter prefix (max. 40 chars)','prefix','long help text','phpgw_',20,40);

    * Checkboxes: The value is either '1' or '0' which evaluates to True and False in php. You can't have '' as this cant be set as default or forced preference !

    create_check_box('Show on main screen','homeShowEvents','long help text',1);

    * Selectboxes: Beside the 4 standard params, the selectboxes have a 5 prameter which is an array with value - label pairs.

    The label is shown in the selectbox and the value is returned as preference when the label is selected.
    create_select_box('Default Filter for InfoLog','defaultFilter',array('own' => 'own Items','others' => 'other peoples stuff'),'long help text','own');
    (Please note the array with the options is the 3. parameter, helptext and default are following as 4. and 5. parameter !!!)

    * Textarea: The are for entering a bigger, multiline Text. They have 2 extra parameters rows and cols:

    create_text_area('Signature','sig','long help text','--',4,40);

    * Passwordbox: it hides its content by displaying asterixes while entering and an empty field (which is not saved) while updateing.

    create_password_box('Password (max. 12 chars)','password','choose a good one',12,12);

    * Headers: You can have one or more header-lines with a descriptive text as a kind of paragraph headings. They are in the table-header-color and in bold writeing. To do so call the function show_list(lang('Headertext')); after (!) each paragraph. If you dont call it, it is called automaticaly at the end and displays and empty header-line.


3. As all hooks they have to be registered in <app>/setup/setup.inc.php (only the hooks part is shown here):

    $setup_info[<app>]['hooks'][] = 'preferences';
    $setup_info[<app>]['hooks'][] = 'settings';

Hooks get installed whit the app by setup or when you manualy call Admin / Find and Register all Application Hooks.
Proposal: Changes for Preferences
In short: A new column app_name should be add to phpgw_preferences, to allow apps to set defaults and forced prefs (to not show all possible prefs after a new install) via their <app>/setup/default_records.inc.php.
Administration / Site configuration
The Site configuration stores site-wide applications settings and is only accessible by Admins.
The format is the same as for the hook_preferences, but its called <app>/inc/hook_admin.inc.php. Here is an example:

{
   $file = Array(
      'Site configuration' => $GLOBALS['phpgw']->link('/index.php',array(
         'menuaction' => 'admin.uiconfig.admin',
         'appname'    => $appname
      )),
      'Global Categories'  => $GLOBALS['phpgw']->link('/index.php',array(
         'menuaction' => 'admin.uicategories.index',
         'appname'    => $appname,
         'global_cats'=> 'True'
      ))
   );
   //Do not modify below this line

   display_section($appname,$file);
}

Again you dont need the Global Categories if your app does not use Categories and you can use your own function if for the site-config if your app has special requirements, you can realice with the existing with uiconfig which uses a old phplib-template (atm. you should look for the config.tpl of one of the apps).
Please note the display_section-call has only 2 parameters from 0.9.16 on, as the app-title is generated by the applications class.

If you have addition please add them here or mail them to ralfbecker


The file <app>/setup/setup.inc.php is needed by each eGroupWare application. I makes certain important settings for the installation and configuration of the app.
As an example, have a look for the setup.inc.php of the calendar:

<?php
$setup_info['calendar']['name']    = 'calendar';   // the title is not longer here!
$setup_info['calendar']['version'] = '0.9.13.007'; // of your app, NOT the overal egw version
$setup_info['calendar']['app_order'] = 3;
$setup_info['calendar']['enable']  = 1;

/* Informations for the about-page */
$setup_info['calendar']['author'] = 'Mark Peters';
$setup_info['calendar']['license']  = 'GPL';
$setup_info['calendar']['description'] =
    'Powerful calendar with meeting request system and ACL security.';
$setup_info['calendar']['note'] =
    'Bassed on Webcalendar by <a href="http://www.radix.net/~cknudsen" target="_blank">Craig Knudsen</a>.';
$setup_info['calendar']['maintainer'] = array(
    'name'  => 'Ralf Becker',
    'email' => 'ralfbecker@outdoor-training.de'
);

/* the tables this app uses */
$setup_info['calendar']['tables'][] = 'phpgw_cal';     // there are more tables in the cal, just an example here

/* The hooks this app includes, needed for hooks registration */
$setup_info['calendar']['hooks'][] = 'admin';          // to show up in the admin page
$setup_info['calendar']['hooks'][] = 'deleteaccount';  // gets called when an account gets deleted
$setup_info['calendar']['hooks'][] = 'email';          // to recognise the notifications
$setup_info['calendar']['hooks'][] = 'home';           // to show up on the startpage
$setup_info['calendar']['hooks'][] = 'manual';
$setup_info['calendar']['hooks'][] = 'preferences';    // to show up on the preference page
$setup_info['calendar']['hooks'][] = 'settings';       // settings for 3-level prefs
$setup_info['calendar']['hooks'][] = 'sidebox_menu';   // iDots sidebox menu

/* Dependencies for this app to work */
$setup_info['calendar']['depends'][] = array(
     'appname' => 'phpgwapi',
     'versions' => Array('0.9.14','0.9.15')
);

Some of the hooks here have a more detailed description in How to hook into Admin and Preferences.


eGroupWare Setup
June 18, 2001 MilesLott A developer introduction to using the next generation setup application for egroupware.
1. Introduction
1.1 Welcome

Thanks for taking the time to look over this document. If you are a developer who is new to egroupware, this document will be invaluable to your success during the life of your application. This is in addition to the other fine documentation available in the phpgwapi/doc directory in your install. Even long-time phpgw developers should benefit this document. Herein, I will attempt to outline the critical steps required in order to get along with setup.
1.2 Overview

With setup3, we introduce several new capabilities and technologies for the developer and end user alike. Michael Dean was kind enough to offer up schema_proc to form the core of an abstracted and database-independent upgrade process. This enables developers to write a single set of upgrades and table definitions, which should then work on MySQL and PostgreSQL, or any other database type we might add in the future.

Adding to this to control the process was a good chunk of the old setup program, written by Dan Kuykendall (Seek3r). Dan had everything to do with the new dependencies support and with the format of the $setup_info array in setup3.

Setup3 adds multi-language support for the setup application, a long missed feature, I would imagine.

Setup3 gives each application developer control over their application install and upgrade processes, while giving them access to work within a realm formerly owned by only the former core egroupware applications. Yes, this is extra work for the developer. But it is hoped that setup3 is also viewed as a tool that can truly enhance the development process.

OK. Let's dive right in...
2. Application setup files

The files in this section are contained within each application/setup directory. Every app will some of these files in order to operate with setup3.
2.1 setup.inc.php (Required)
Basic information

The values in this section must be used by all applications.

The first section of setup.inc.php defines the very basic and yet critical information about the application. Take a look at the following section:

 

$setup_info['addressbook']['name'] = 'addressbook';
$setup_info['addressbook']['title'] = 'Addressbook';
$setup_info['addressbook']['version'] = '0.9.13.002';
$setup_info['addressbook']['app_order'] = 4;
$setup_info['addressbook']['enable'] = 1;

'name' is used throughout egroupware, typically in $phpgw_info flags such as 'currentapp' or as the 'app_name' almost everywhere else.

'title' would be used in the navbar, admin, preferences, as well as in the application itself.

The 'version' string defines the version of the application and table code. This would be incremented whenever you create a new upgrade function, and typically only for table modifications. If the change is significant from the last code update, you could increment this here also. Incrementing this version string is not trivial, so please do read the rest of this document for more information about that.

'app_order' determines the order of applications in the navbar. If the number you set here is the same as is set for another app, the app whose 'name' is first in the English alphabet would appear first. Smaller numbers show closer to the top or left end of the navbar, depending upon the layout.

The 'enable' string is used by the egroupware API to determine whether an application is disabled, enabled, or enabled but hidden from the navbar. Most applications will want this set to a value of 1 (enabled). The notifywindow app sets this to 2, which keeps it off the navbar. An enable of 0 would disable the app by default. There is one other special case, 3, which is used primarily by the API itself. From the perspective of setup3, the API is an application just like any other application. By setting the 'enable' flag to 3, the API is still enabled, but will not be assignable to a user as a real application. It will thereby be hidden from the admin for application and user/group editing.
Table info
Only applications with database tables will use entries in this section.

The next section of $setup_info values is an array defining all of the application's database tables:

 

$setup_info['addressbook']['tables'] = array(
'phpgw_addressbook',
'phpgw_addressbook_extra'
);

This is a simple array, and must list accurately the current table names you are using in your application. This list will match a much more complex array of table specifications, as you will see below.
Hooks
Some applications will use this section.

The hooks array part of $setup_info contains a simple list of hooks the application will use:

 

$setup_info['addressbook']['hooks'][] = 'preferences';
$setup_info['addressbook']['hooks'][] = 'admin';

Here we also note a different method of 'stuffing the array.' In any case, this list of hooks will be required soon in order for your hook_admin.inc.php and other files to work. This is being done to cut down on the manual directory listing and file_exists loops done currently to discover hook files. Other than 'preferences' and 'admin', 'home', 'manual', 'after_navbar' and 'navbar_end' are all valid hook entries.
Dependencies
All applications will have at least one entry here.

The final section, or array of data, is a listing of the other applications your application requires in order to function:

 

$setup_info['addressbook']['depends'][] = array(
'appname' => 'phpgwapi',
'versions' => Array(
'0.9.10',
'0.9.11',
'0.9.12',
'0.9.13'
)
);

This is the standard dependency array for all egroupware applications. It states that this application requires the phpgwapi, and lists the versions with which versions this app is compatible. This list would need to be appended upon each new API release, assuming your application is compatible with this new API version. You may list other applications here, e.g. your app might depend upon 'email' in order to work properly.

Do NOT list applications here without considering this: If you do list an application here, and your app does not really require it, your application will not install unless that other application is already installed. This is handled normally within the install/upgrade process loops, which will install only applications whose dependencies are satisfied. Using a multipass function, the applications are installed in the correct order to ensure that dependencies are resolved. In all cases, the API would be installed first in every new install or upgrade, since all applications depend on the API.
2.2 tables_baseline.inc.php (Recommended)
Any application that has at least one upgrade routine will have this file.

The tables_baseline file represents the earliest supported version of an application's tables. This file is used only in the upgrade process, and is critical to its success. It contains an array of database-independent table, field, key and index definitions.

This array is formatted for use by the class.schema_proc_array.inc.php file in setup3. See the tables_update section below for more detail about schema_proc, but for now, here is a simple table definition in this format:

 

$phpgw_baseline = array(
'skel' => array(
'fd' => array(
'skel_id' => array('type' => 'auto','nullable' => false),
'skel_owner' => array('type' => 'varchar','precision' => 25),
'skel_access' => array('type' => 'varchar','precision' => 10),
'skel_cat' => array('type' => 'int','precision' => 4),
'skel_des' => array('type' => 'text'),
'skel_pri' => array('type' => 'int','precision' => 4)
),
'pk' => array('skel_id'),
'fk' => array(),
'ix' => array(),
'uc' => array()
)
);

This multi-dimensional array contains 1 subarray with 5 subs of its own. The first array ('skel' above) defines the table name. Below that are 5 sections, 'fd' for field definitions, 'pk' to define primary keys, 'fk' to define foreign keys, 'ix' to define indexed fields, and 'uc' to define columns that require unique values. In the above example, the table 'skel' has 6 fields (skel_id, skel_owner, skel_access, skel_cat, skel_des, skel_pri), and 'skel_id' is defined also as the primary key for this table. More information on this array is below. But, this format was chosen as an available solution for defining tables and fields without having to maintain seperate files for different databases.
2.3 tables_current.inc.php (Recommended)
All applications with tables will need this file.

The tables_current file defines the current table definition that matches the 'version' string in $setup_info as well as the current code. This file is used only for new installs, or whenever the application is removed and reinstalled. The format and name of the array in this file is the same as for the tables_baseline file listed above. In fact, whenever it is required to change your table definitions, you would start by copying the current file over to become the tables_baseline file. After having created your upgrade routines, you would then recreate the current file to match the new table definitions.
2.4 tables_update.inc.php (Recommended)
Any application which requires an upgrade to a previous version's tables will need this file.

This file will be the most complex of all setup-oriented files with which you will be working. It will contain all upgrade functions capable of upgrading any possible version of your egroupware app. These upgrade routines roughly match the old setup program's upgrade functions, but the use of objects and the methods have changed dramatically. The simplest version upgrade routine would look like:

 

$test[] = "0.9.3pre10";
function addressbook_upgrade0_9_3pre10()
{
global $setup_info;
$setup_info['addressbook']['currentver'] = '0.9.3';
return $setup_info['addressbook']['currentver'];
}

This upgrade function merely updates the current version number. Note that there is not only an upgrade function, but also the setting of a value in the $test array. The name 'test' is a holdover from the old setup program, and is an arbitrary choice. However, this name must be used for the upgrade process to work. Prior to each of your upgrade functions, add the value of the previous version to $test.

Now look at the function name. The name is important and should be structured as the application name and the version from which you are intending to upgrade. The '.'s in the version string are replaced with '_'.

Inside the function, we global the $setup_info array. Next, we alter the version number in that array, for our application. Please be careful to specify YOUR application name here. The very last thing we do is to return this new version to the calling function. The upgrade process relies on the value returned, since it uses this directly to determine the new version. This may appear illogical on some level, but it does work. The reason for returning this value instead of a True or 1, etc. has to do with variable scope and lifetime. In this way, even the globaling of $setup_info inside the function may have little effect on the upgrade process. But, there may be values in this array you would want to use within the function. More on that later.

There is one other variable you would need if doing any database operations here. If you global $phpgw_setup, you will then have access to db and schema_proc objects and functions. The objects of interest here are:

 

    * $phpgw_setup->oProc
    * $phpgw_setup->db.

For most database work you should use the oProc object. This also has a db object that should be used for most standard phpgw API db class functions, including $db->query, next_record, num_rows, and f. The use of these for standard db operations is critical to the upgrade process. Schema_proc has a flag that can be set to determine what mode of upgrade we are in. This flag is set in the setup class during the upgrade process, and should not be altered locally.

This flag is a decision on whether to alter the database or the schema_proc array. The tables_baseline file above is loaded by setup prior to running your upgrade routines. If the current installed version is greater than the current upgrade routine, we don't need to alter the database yet. But schema_proc instead alters the $phpgw_baseline array in memory. The maintenance of this array is done even when we do alter the database. Once our version number in the test array matches the currently installed version of an application, real work on the tables begins.

'Why bother modifying this array at all', you may ask. The array must be maintained in order to keep current table definition status. This is used in some schema_proc functions when altering columns and tables. This is especially critical for pgsql schema_proc functions.

By using the $phpgw_setup->oProc object for basic inserts and queries, we acheive the ability to run all upgrade functions in every upgrade cycle without actually altering the database until we reach the current version we actually want to upgrade. For example:

 

$sql = "SELECT * FROM phpgw_addressbook_extra WHERE contact_name='notes'";
$phpgw_setup->oProc->query($sql,__LINE__,__FILE__);
while($phpgw_setup->oProc->next_record()) {

We could have used $phpgw_setup->db or even a copy for the above activity. However, using the above method ensures that an array only upgrade does just that. If the flag was set in setup telling schema_proc to alter the array only, we do not want to touch the tables for inserts or selects yet. In this case, $phpgw_setup->oProc->next_record() returns False, and the loop is skipped. The $phpgw_baseline array does not know about table content, only table and field definitions.

If the upgrade function containing this method is actually working on the tables (currentver <= the upgrade function), then next_record() is returned as the expected action of pulling the next row of data. Inside of this while loop, you can safely use $phpgw_setup->db, or preferably a copy, to do the insert/delete, etc you want to have happen here.

 

$cid = $phpgw_setup->oProc->f('contact_id');
$cvalu = $phpgw_setup->oProc->f('contact_value');
$update = "UPDATE phpgw_addressbook set note='" . $cvalu . "' WHERE id=" . $cid;
$db1->query($update);
$delete = "DELETE FROM phpgw_addressbook_extra WHERE contact_id=" . $cid . " AND contact_name='notes'";
$db1->query($delete);
}

$db1 is a copy of $phpgw_setup->db, to avoid potential conflicts with the rest of setup's db activities.

In addition to the basic API db class functions, schema_proc introduces the following special functions:

 

function DropTable($sTableName)
function DropColumn($sTableName, $aTableDef, $sColumnName)
function RenameTable($sOldTableName, $sNewTableName)
function RenameColumn($sTableName, $sOldColumnName, $sNewColumnName)
function AlterColumn($sTableName, $sColumnName, $aColumnDef)
function AddColumn($sTableName, $sColumnName, $aColumnDef)
function CreateTable($sTableName, $aTableDef)

Please use these functions where appropriate in place of standard SQL CREATE, DROP, and ALTER TABLE commands. This will ensure that your upgrade script works for all supported databases.

Of these functions, DropTable, RenameTable, and RenameColumn are pretty straightforward. Pass these the table names you wish to Drop/Rename, and schema_proc will handle the rest, including indexes and sequences, where applicable.

The remaining functions require some explanation:

 

    * CreateTable:

 

$phpgw_setup->oProc->CreateTable(
'categories', array(
'fd' => array(
'cat_id' => array('type' => 'auto','nullable' => false),
'account_id' => array('type' => 'int','precision' => 4,'nullable' => false, 'default' => 0),
'app_name' => array('type' => 'varchar','precision' => 25,'nullable' => false),
'cat_name' => array('type' => 'varchar', 'precision' => 150, 'nullable' => false),
'cat_description' => array('type' => 'text', 'nullable' => false)
),
'pk' => array('cat_id'),
'ix' => array(),
'fk' => array(),
'uc' => array()
)
);

Does this look familiar? The array passed to CreateTable is in the format used also in tables_baseline and tables_current. Note a slight difference where the table name is being passed as a seperate argument. The second argument to the function is the table definition array, starting with 'fd'.

 

    * AddColumn:

 

$phpgw_setup->oProc->AddColumn('phpgw_categories','cat_access',array('type' => 'varchar', 'precision' => 25));

Here we pass the table name of an existing table, the new column name, and a field definition. This definition is merely a slice of the table arrays found earlier in this document.

 

    * AlterColumn:

 

$phpgw_setup->oProc->AlterColumn('phpgw_sessions','session_action',array('type' => 'varchar', 'precision' => '255'));

The format of this function matches AddColumn. It is also a simple case of passing the table name, field name, and field definition.

 

    * DropColumn:

 

$newtbldef = array(
"fd" => array(
'acl_appname' => array('type' => 'varchar', 'precision' => 50),
'acl_location' => array('type' => 'varchar', 'precision' => 255),
'acl_account' => array('type' => 'int', 'precision' => 4),
'acl_rights' => array('type' => 'int', 'precision' => 4)
),
'pk' => array(),
'ix' => array(),
'fk' => array(),
'uc' => array()
);
$phpgw_setup->oProc->DropColumn('phpgw_acl',$newtbldef,'acl_account_type');

This is the most complicated function in schema_proc, from the user's perspective. Its complexity is necessitated by the requirement of some databases to recreate a table in the case of dropping a column. Note that the table definition array is being used yet again. The array defined here should match the table definition you want after this function has completed. Here, we are dropping the column 'acl_account_type' from the table 'phpgw_acl', and the table definition does not have this column defined. You could copy information from your tables_current file here and edit it to match the desired new table spec, less the column you wish to drop.

There are additional functions within schema_proc, the majority of which are not to be called directly. They are used internally. If you do wish to investigate further, use class.schema_proc.inc.php as your guide. This master file includes the class.schema_proc_DBMS.inc.php and class.schema_proc_array.inc.php files. The DBMS files should not be used as a guide, since their functions are called from the master class, and the parameters are different from what you might expect relative to the master.

PLEASE, DO NOT WRITE TO OR ALTER ANOTHER APPLICATION'S TABLES OR THE API TABLES IN YOUR APPLICATION UPGRADE FUNCTIONS!
2.5 default_records.inc.php (Optional)
Any application with tables that wants to load some default data will need this file.

The default_records file consists of a list of SQL INSERTs using the $oProc object directly:

 

$oProc->query("INSERT INTO phpgw_inv_statuslist (status_name) VALUES ('available')");
$oProc->query("INSERT INTO phpgw_inv_statuslist (status_name) VALUES ('no longer available')");
$oProc->query("INSERT INTO phpgw_inv_statuslist (status_name) VALUES ('back order')");

In this case, the developer wanted to insert some status information, which was then used in a select box on an html form. Using the default_records file, every new install will have this data included. This file should consist of queries applicable to the tables defined in setup.inc.php and tables_current.inc.php.
2.6 test_data.inc.php (Optional)
Any developer wanting to test the full list of upgrade routines can use this file.

test_data.inc.php is similar to default_records above. It is called only by schematoy.php and is never installed with a new install or upgrade. This is a developer-only file. The INSERTs here should be applicable to the tables_baseline table definitions.
2.7 language files (Required)
All applications should have at least a file of English translations, used for their application lang() calls.

 

    * Format of a lang file:

 

{phrase}{TAB}{appname}{TAB}{LANG_CODE}{TAB}{translation}
e.g:
first name common en First Name
first name common de Vorname

 

    * Filenames:

 

phpgw_{LANG_CODE}.lang
e.g.
English: phpgw_en.lang
German: phpgw_de.lang

Please see the contents of the API 'languages' table for the correct setting of the LANG_CODE.
3. Developer Tools
3.1 sqltoarray.php
Displays the current schema_proc array defining an application's tables.

This web application reads the current table status live from the database. It then parses this information into a hopefully correct table definition array for schema_proc. Upon visiting this app, you are shown a list of currently installed applications with defined tables. You may then select one app or all apps, and then submit the form. From this form you may then download a tables_current file, suitable for commission to cvs. Please do check the format to make sure the definitions are correct.
3.2 schematoy.php
Runs the full cycle of upgrades, including optional test_data.

This app is not beautiful, may bomb on you, and will definitely drop your application's tables. The display is similar to the user/admin tool, applications.php. You are shown a list of apps with tables. Select one app, and enter a target version. Upon submission of the form:

 

    * All application tables are dropped.
    * tables_baseline.inc.php is loaded.
    * test_data.inc.php is loaded
    * tables_update.inc.php is loaded.
    * a full application upgrade test begins.

This will give a LOT of debugging output. Depending on your database, the process may take quite awhile. This tool should be considered as a destructive test of the full upgrade cycle. If the upgrade process is successful, you can then check the loaded test_data to see that it is still in place as expected after all the table modifications, etc. If not, it should be clear where the error has occurred. Look for the usual INVALID SQL warnings, among others.
3.3 tools subdirectory
some utilities for sql file conversion, etc.

In the tools directory under setup3, there should be at least a couple of hopefully handy perl or shell scripts. These are for running on the commandline only, and might apply to converting SQL files into lang files, etc. They are not expected to be perfect, but might offer some assistance or ideas for additional utilities. Use these at your own risk or benefit.
4. The install/upgrade process
4.1 Overview
Setup internal upgrade functions

Setup uses a common set of functions for new installs and upgrades. These are implemented as multi-pass loops. For a single application install or upgrade, a single pass is done. For multiple application installs or upgrades, multiple passes are done automatically. The order of install in a mass install or upgrade is determined by application dependencies. The other determining factor is the order in which the application directories and setup.inc.php files are read from the filesystem.
4.2 New installs
Detection

Each run of index.php or applications.php in setup3 first runs a set of detection routines. These read the data from each setup.inc.php file, and from the 'applications' or 'phpgw_applications' table as appropriate, and only if one of these tables exists. This data is parsed into the $setup_info array. In this case, this array contains information about all applications. Based on the information gathered, a status flag is set to one of the following values:

 

    * U - Upgrade required/available
    * R - upgrade in pRogress
    * C - upgrade Completed successfully
    * D - Dependency failure
    * F - upgrade Failed
    * V - Version mismatch at end of upgrade
    * M - Missing files at start of upgrade (Not used, proposed only)

Using this information, the setup logic in index.php determines what mode we are in. index.php is not capable of being selective about which application it found as being out of sync. It is designed only for 'Simple Application Management', which is Step 1 of the setup process. For more selective application manipulation, use applications.php. index.php then tells the user that 1) their applications are current 2) some of their applications are out of sync 3) no db exists, etc. For a new install, all applications will be out of sync, since there is not even an 'phpgw_applications' table in the database to tell setup what the status is for any application.
Selection

There is no selection for application installs in 'new install' mode. All physically present applications will be installed, or at least attempted.
Installation

Once the setup user clicks the magic button to install all applications, the following occurs:

 

    * The setup_info array is passed to the process_pass() function, using a method='new'
    * Applications whose status flag='U' (API on first pass) are then handed off to the process_current() function. This handles inclusion and installation of the application's tables_current.inc.php file.
    * The application is registered as a new application in the 'phpgw_applications' table. If for some reason there is old data in this table for this application, it will be updated instead. Its hooks, if any, are registered in the 'phpgw_hooks' table.
    * Next, this array is passed to the process_default_records() function. If this file is present in the current application's setup directory, the queries here are run to install the data to the application's table(s).
    * The above is repeated until all application status flags equal 'C'. However, if an application install failed for some reason, it will then be skipped on the next pass. This keeps the loop from running away.

4.3 Upgrades
Detection

Only an API version mismatch will trigger an automated request for the user to upgrade their install. Once the api is current, they can move on to applications.php for more 'Advanced Application Management', which is Step 4 of the setup process. However, if the API is out of sync, clicking 'Upgrade' in index.php will also attempt to upgrade other applications which may be out of sync, as well. As the phpgwapi continues to stabilize, it is felt that this method of upgrading will become less and less common.
Selection

Within applications.php, a color-coded matrix of application status and actions is displayed. Depending on the status flag of each application, certain actions will be either enabled or disabled. These actions include 'install', 'upgrade', 'remove'. If something is very wrong with previous attempts to install or upgrade an application, another column called 'resolution' will then display a link. This link will display additional information which would be helpful for determining how to resolve the problem. Assuming all is well, the user can select applications requiring upgrade from this list. Once selected, they submit the form. This runs the follow three routines in order:

 

    * remove
    * install
    * upgrade

Upgrade

The idea here is that multiple actions can be selected and run in order in one click. In any case, once they select an application for upgrade, the following occurs:

 

    * A stripped down version of the setup_info array is passed to the process_upgrade() function. This array contains only the information for the selected application
    * Within process_upgrade(), the tables_baseline.inc.php file for the application is loaded.
    * The tables_update.inc.php file for the application is loaded
    * The contents of the test array is used to loop through the entire list of upgrade functions for the application. The application's unique function names are rebuilt, then run.
    * When the currentver (installed) matches the version (available), process_upgrade() exits, setting the status flag for the app to 'C'.
    * Just prior to exiting, the application and its hooks are updated into the 'phpgw_applications' and 'phpgw_hooks' tables.

4.4 Uninstallation/Removal
Selection

Selective removal of an application is done via applications.php, in a manner similar to the method above for upgrades.
Uninstallation

Once an application is selected for removal:

 

    * A stripped down version of the setup_info array is passed to the process_droptables() function. This function removes all of the application's defined tables, but only after first checking to see if the tables are there. In this way, we attempt to cut down on the number of errors sent to the browser.
    * The application's hooks are deregistered (removed from 'phpgw_hooks').
    * The application itself is deregistered (removed from 'phpgw_applications').

5. Caveats
5.1 Must see info
Auto fields

For auto type fields, schema_proc creates a sequence automatically based on the table name for databases that require sequences. In the case of postgresql, the limit for this name based on our tests is 31 characters. The schema_proc format is:

 

$sSequenceSQL = sprintf("CREATE SEQUENCE seq_%s", $sTableName);

This limits the maximum length for a tablename to 27 characters. Based on the tablename standard in phpgw of 'phpgw_tablename', you are further limited to 21 characters in which to describe your table. You will need to be less descriptive in some cases, e.g. use 'phpgw_widget_cats' instead of 'phpgw_widget_info_categories'.

To maintain compatibility with MySQL 3.22.X, please always add "'nullable' => False" to your field spec for an auto field. This and probably older versions of MySQL require that specification within the SQL for a field that will also be an index or unique field, which for our uses should typically be true for an auto field. MySQL 3.23.X and PostgreSQL do not have this issue.
Default 0

For int fields, a default of 0 is not assumed. Only some databases will set this default for you, MySQL being one. You will need to explicitly define this default in the table definition. Also, for auto fields, do not enter a default, since the resulting SQL query would fail on many RDBMS.

Coding Standards

    * Format your code so that we can read it, please!


    * Use tabs for formatting, NOT SPACES. Tabs create smaller files and editors allow developers to view a tab as however many spaces as they prefer. Spaces do not allow this. There is one exception (see arrays below).


    * Use ' instead of " for strings. This is a performance issue, and prevents a lot of inconsistent coding styles.


    * Use the Standard Header in the top of all your scripts


    * Comments go on the line ABOVE the code, NOT to the right of the code!


    * For each section of code put a section divider with basic explanation of the following code/functions. It should look like this:

    /****************************************************************************\
    * These functions are used to pick my nose                                   *
    \****************************************************************************/


    * Do not document every bit of code in comments. PHP is an interpreted language and it will be nasty on performance.


    * Use switch statements where many elseif's are going to be used. Switch is faster and I like it better!


    * If' statements need to use the following format:

    if ($var == 'example')
    {
        echo 'This is only an example';
    }
    else
    {
        echo 'This is not a test.  This is the real thing';
    }

    //Do NOT make if statements like this:

    if ($var == 'example'){ echo 'An example'; }

        * All other styles are not to be used.


    * ALL 'if' statements MUST have matching { } (brackets). Do NOT create 'if' statements like this:

    if ($a == b)
        dosomething();

    //or:

    if ($a == b) dosomething();


        * They make the code more difficult to read and follow.


    * class/function format:

    class testing
    {
        function print_to_screen()
        {
            global phpgw, phpgw_info;

            if ($var == 'example')
            {
                echo 'This is only an example';
            }
            else
            {
                echo 'This is not a test.  This is the real thing';
            }
        }
    }


    * Associative arrays must be written in the following manner:

    $array = array
    (
        'var'    => 'value',
        'var2'    => 'value2'
    );


        * Note that tabs are preferred around the '=>'.


    * Use the long format for <?php. Do NOT use <?.


    * All code should start with 1 tab. Example:

<?php
    dosomething();
    if ($a)
    {
        dosomemorestuff();
    }

    //NOT:

<?php
dosomething();
if ($a)
{
    dosomemorestuff();
}

    * Use lower case for variable and function names. No stubbly-case (mixed-case) code.

    //correct
    var $my_var;
    function my_function()
    //incorrect
    var $MyVar;
    function MyFunction()


Thanks for following these rules :)

eGroupWare Dependencies
eGroupWare is extremely flexible, and so there are many optional dependencies. The dependecies are categorized below.

PHP
The current stable version of eGroupWare will run on any version of php 4.1.0+.

Databases
You must have a database, any of the following are currently supported.

    * MySQL 3.23.x
    * PostgreSQL - 7.2.x
    * SQLServer - ??
    * Orcale - coming soon?
    * SAP - been mentioned

NOTE: You must have support for the database included in php
Developers please refer to this [RDMS functionality X reference] when developing your apps

LDAP
LDAP can be use for storing account or contact data in eGroupWare.

    * OpenLDAP
    * Netscape Directory Server -??

NOTE: You must have support for LDAP included in php

Mail Servers
eGroupWare supports various mailservers
Courier-IMAP
Cyrus-IMAP
UW-IMAP
MS Exchange IMAP access (5.5 tested)
NOTE: You must have support for IMAP included in php to use the default email client
NOTE for POP3: if you only want to use POP3, not imap, then it is possible to use AngleMail without PHP-IMAP module installed. This applies ONLY for POP3 servers. However it is still recommended to have php with the PHP-IMAP module installed because this configuration also works with POP3 and is somewhat better supported - Angles.

ACL - Access Control Lists
Allows to grant other people access to your data on a per user of per group basis.

The principle of the ACL is to grant access, that means:

    * you can say: user x or group y are allowed to read my data
    * the admin can say: all members of group x allow each other or an other group or user to access there data
    * access can be granted for the following levels (and each mixture of them):
          o read - read non-privat (!) data
          o edit - change data
          o add - add new entries
          o delete - delete data
          o privat - access data marked as privat (can not be granted on group-level))
    * not all eGroupWare applications have ACL and/or all of the above levels implemented


Where to set these grants / the ACL:

   1. on a per user basis, each user can do it in his preferences for each app: Grant access
   2. on a per group basis, an admin can set it in admin / group-manager (Group accounts) by clicking on the blue squares behind some app (not all apps implement group level ACL)


good ACL practices for admin's

    * create groups by function and assign people to them, have one group with all users
    * assign ACL's only on group level


Examples

    * Set up a group so that they can eg. read / see each others calendar:

    This can be archived most easy with a group-ACL's. That way it works not only for users who are in that group at the moment, but also for users added later and its automaticaly removed if the user is removed from that group. Go to 'Admin / Group accounts' and edit the concerned group. In the edit view click on the blue square in the ACL column behind the calendar app. This will open another window with the ACL for that group and the calendar app. Now you check read-access for the group itself.


    * Allow a secretary to "manage" my calendar:

    Manage means for me he has to be able to add appointsments in my calendar and confirm them on my behalf. You have to grant him read, edit and add access to your calendar. Go to your preferences and start Calendar / Grant access. Check read, edit and add for that user. He can then select your calendar in any view and add appointsments to it.


If you have question or more content please add it to this page or mail them to ralfbecker

Categories help to organize the data in different eGroupWare applications.

Example: You might create a categorie 'Customers' and assign it in the AddressBook to each address/contact which is a customer. You can now use it to show only the customers. To do so you have to select that Categorie in the List of the AddressBook.

Most of the apps support the phpGW categorie system and there are 3 kind of categories:

    * Global Categories: the are availible for all apps and all users. Only Admins are allowed to create global cats (go to Administration / Admin / Global Categories).
    * Application-global Categories: the are availible for all users but only in the app they are created for. They can also only be created by Admin's, like the global categories (go to Administration / the appalication / Global Categories).
    * User Categories: these categories can be added by each user in his preferences.


Which type of categorie to use: If u need a categorie for more then one app, make it a Global categorie (eg. the 'Cusomter' cat might be usefull in other apps too). If you need a categorie only in one app make it an Application-global Categorie. And last but not least, if you no admin, or your categories are not useful for other users make it a User Categorie.

Categories can be aranged hierachical, so u can have sub-categories like 'customers / first time' or 'customer / key accounts'.

In the planner view in Calendar categories can be used to assign colors to each categoris of appointments / events. To do so, add the color as rgb-value after the description (eg. '#FF0000' for red).

Categories help to organize the data in different eGroupWare applications.

Example: You might create a categorie 'Customers' and assign it in the AddressBook to each address/contact which is a customer. You can now use it to show only the customers. To do so you have to select that Categorie in the List of the AddressBook.

Most of the apps support the phpGW categorie system and there are 3 kind of categories:

    * Global Categories: the are availible for all apps and all users. Only Admins are allowed to create global cats (go to Administration / Admin / Global Categories).
    * Application-global Categories: the are availible for all users but only in the app they are created for. They can also only be created by Admin's, like the global categories (go to Administration / the appalication / Global Categories).
    * User Categories: these categories can be added by each user in his preferences.


Which type of categorie to use: If u need a categorie for more then one app, make it a Global categorie (eg. the 'Cusomter' cat might be usefull in other apps too). If you need a categorie only in one app make it an Application-global Categorie. And last but not least, if you no admin, or your categories are not useful for other users make it a User Categorie.

Categories can be aranged hierachical, so u can have sub-categories like 'customers / first time' or 'customer / key accounts'.

In the planner view in Calendar categories can be used to assign colors to each categoris of appointments / events. To do so, add the color as rgb-value after the description (eg. '#FF0000' for red).

Timed Asynchron Services vor eGroupWare
This general API interface allows all app's to start tasks at certain times.

Eg. the user should get

    * a notification, if a delegated task in InfoLog is not started / finished at the given start- / endtime (notification not received from the user its delegated to).
    * an alarm from the calendar for a Meeting or for a sheduled Phonecall in InfoLog
    * the backup app should run nightly at 2am.


Installation
For windows follow the installation instructions at TimedAsyncServicesWindows

On a Linux or other *nix system you usualy only have to hit the [Install crontab] button.

The asyncservices are tested on the following linux-systems now:

    * SuSE 8.0+: tested by ralfbecker

    The webserver-user 'wwwrun' needs to be included in the group 'trusted', to be able to call the crontab command

    * Debian Woody: tested on the phpgroupware.org by ralfbecker

    Problem was the php4-binary is called php4 (not php) and the db-support is not compiled in the cgi-binary by default. This is solved now (the class checks for a php4 binary and loads dl() the db-support).

    * Redhat: acording to ReinerJ
    * Mandrake: tested

    You need to include the webserver-user 'apache' into /etc/cron.allow, to allow the webserver to use the crontab command

    * Gentoo: tested by knecke

    You need to include the webserver-user 'apache' into the group 'cron', to allow the webserver to use the crontab command


If you or your system-administrator dont want to give the webserver the right to make "his" own crontab entries. You can do it manualy by adding the following line to your /etc/crontab:

    * /5 * * * * <webserver-user> /usr/bin/php -q <eGW-install-dir>/phpgwapi/cron/asyncservices.php <domain>

Eg. for a standard install on redhat:

    * /5 * * * * apache /usr/bin/php -q /var/www/html/phpgwapi/cron/asyncservices.php default

Now you can log into eGW and go to Admin >> Async Services. As you now manualy installed the crontab entry, you should select Disabled (not recomended) for running the asyncservice. If you hit update, you can check that the asyncservice is (still) called by "crontab".

Please let me know if you have problems with the service or the testjob.

General Documentation
All this can not be done with the normal approach of a web-based application. Some app's have included scripts, to be installed as cron jobs (eg. backup).

The new class offers standard eGW service where all app's can register timer, some data and a callback-methode. That service calls the given methode with the data at the given time (or repetivly), if the timer is not canceled before.
Status of the implemenation
The class is up and running in eGW. By default it is only running in the Fallback mode, which means it only checks for jobs to run after each page-request. This methode should run on any platform. On a linux system the service can be run via cron. To do so, you have to go to Admin -> Async Services and hit [install crontab] (if you havn't do so already). If it shows no errors you should be able to change run async service to 'crontab (recomended)'.
If you get an error-message its probably because your webserver-user is not allowed to use the 'crontab' command. See the next section on how to change that for your distribution.
If the service is installed in the crontab and runs via 'crontab', you can test it by starting the test-job. It sends u a mail every 5min (or what ever times u used when installing it).


How to implement that in a portable (*nix and win) and stable way ?
This can hardly be done in one way only, we need several methodes the admin can choose from and a default that works without further actions:

   1. Fallback Mode: is called on every page-request of any user and checks if any timer is ready to run.
          * Benefits: does not need any special installation
          * Drawbacks: can not garantee a in-time delivery (depending on the user of the whole system), might be a performance penality for big installations
   2. Crontab: admin installs it via phpGW admin -> asyncron services to run every 1, 5, 10, ... minutes.
          * Benefits: garanties delivery times in the given frequenz of the script-calls and is realy asnychron (no user has to wait for the script to do its job)
          * Drawbacks: *nix only, needs the cgi-binary of php and has to be installed by admin (see above)
   3. Service under NT: this could be the NT counterpart for the cronjob -- not yet implemented / I have no win-system ;-)

function set_timer($time,$id,$methode,$data)
$time:
unix timestamp or array('min','hour','day','month','year') with execution time. Repeated events are possible to shedule by setting the array only partly, eg. array('day' => 1) for first day in each month 0am or array('min' => '*/5','hour' => '9-17') for every 5mins in the time from 9am to 5pm.
$id:
unique id to cancel the request later, if necessary. Should be in a form like eg. '<app><id>X' where id is the internal id of app and X might indicate the action.
$methode:
Methode to be called via ExecMethode($methode,$data). $methode has the form '<app>.<class>.<public function>'.
$data:
This data is passed back when the method is called. It might simply be an integer id, but it can also be a complete array.
Returns: False if $id already exists, else True
function cancel_timer($id)
Cancels the timer, $id has to be the one used to set it.
Returns: true if the timer exists and is not expired.
Implementation
DB table
'phpgw_timer' => array(

    fd => array(

        'id' => array('type' => 'varchar', precission => '255', 'notnull' => 'True'), // unique id
        'next' => array('type' => 'int', precission => '4', 'notnull' => 'True'), // the timestamp of the next call
        'times' => array('type' => 'varchar', 'precission' => '256', 'default' => ''), // serialized array for repetive timers, $time param
        'method' => array('type' => 'varchar', 'precission' => '80', 'notnull' => 'True'), // $method param
        'data' => array('type' => 'text') // serialized $data param

    ),
    'pk' => array('id'),
    'fk' => array( ),
    'ix' => array('next'),
    'uc' => array( )

);
General Implemenation
set_timer() calculates the next run of the timer and puts that with the rest of the data in the db.
check_run() is called eg. by the cron-script and querys all timers with expired next time and executes there methode with the given data. If the times field is not empty the next execution time is calculated and the db updated with it, else the row is deleted.
cancel_timer() querys the db for the given id and deletes the row

    * NT/W2K has a at service. This is like the cron daemon. Linux has the at daemon too. (lkneschke)