Difference between revisions of "PHPGeneral/Support module writing guide"
(initial) |
|
(No difference)
|
Latest revision as of 15:44, 17 May 2007
Support modules are services used by the applications to perform specific tasks. They encapsulate low-level functionality provided by a service or a library into a class and are responsible for all operations regarding the resource, from initializing till cleanup.
Contents
Environment
All files, which belong to a service implementation are located in a subdirectory underneath the support directory. These service directories contain further directories, where the files for different implementations of a service are stored or different subsystems of an API are located, e.g. the compression and encryption subsystem of a transformation API. An example for the different implementations of a service may be the support/ldap/ directory, which may contain a directory for OpenLdap, Novell's eDirectory and Microsoft's Active Directory. The files in these directories must handle the differences between the ldap implementations.
Basic layout
The file name of a new service, which have to be in lower case, must consist of the service name, the type of the service and the extension (.class.php). Some services are available as unencrypted and encrypted versions and therefore there must be two files created (e.g. ldap and ldaps). The secure version must manage the same things as the unencrypted version and additionally perform all operation necessary to build an encrypted tunnel before any payload is sent.
Each of these files contains a class providing an object-oriented interface to the service or library API. The class name must be named like the file without the extension (.class.php) and should use the C++ naming convention. Therefore the first letter of each word should be upper case, e.g. LdapOpenLdap. These classes can extend a base class located in the same directory or one directory above or must extend the Locale class located in lib/locale/. Otherwise, if a base class is used, then the base class must extend from Locale. Locale provides support for internationalization and enables you to write a destructor for your class, which can close the resource at the end if a class instance isn't used any more.
class ServiceMyService extends Locale { function ServiceMyService( $param, &$errmsg ) {} // Constructor function _ServiceMyService() {} // Destructor function serviceFunction() {} // Member function ... }
Instantiation of the class
If a part of the application needs a class providing a specific service, it (or more precisely the function getref() in lib/include/common.inc.php tries to instantiate the class by using the service name and the implementation type. The application has some information like the (pseudo) URL of the service, which contains the service name, host, port and path (e.g imap://some.host:143/options/), the implementation type and eventually some service specific parameter. The correct class will be found by concatenating the support directory, the service directory, the implementation type and the file name, separated by "/". The file name of the class, which should be instantiated is build by the concatenation of the service name (imap or imaps), the implementation type (e.g. cyrus) and the file extention (.class.php). For example the application will try to instantiate the class described by these attributes
- service: imap
- type: cyrus
by looking into lib/support/imap/cyrus/imapcyrus.class.php. The lookup for the encrypted version will be done by lib/support/imap/cyrus/imapscyrus.class.php.
Constructor explained
A typical constructor for an example module located in lib/support/*/ may look similar to the next few lines:
function ServiceMyExample( $param, &$errmsg ) { // Do the necessary stuff }
Parameter description
The constructor is responsible for creating the connection to the service and authenticating the user or initializing the used library. The first parameter "param" is an associative array and contains at least seven elements:
- userid (name of the authenticated user)
- password (password of the authenticated user)
- (pseudo) url (e.g. conf://localhost:0/etc/general/simple.conf
- service name (e.g. conf, ldap, imap, etc.)
- host name or ip address
- port or 0 if there is no port necessary
- path (component behind the port in the url)
It may contain more elements which are listed for this service in support.conf or which are added by the calling class. The support class itself should get all needed parameters in the $param array and should retrieve additional configuration parameters from other files.
The &$errmsg parameter is a reference to a variable which should be used to store error messages if an error occurs. Error messages must be appended by the ".=" operator and should not be overwritten by "=", because only then the user is able to trace an error. The &$errmsg variable is also used by the function, which instantiated the class to detect, if there was an error. The execution of the script is then aborted by the function at the highest level and the error message stack is displayed. The error messages must begin with the name of the class and the current function (e.g. "ServiceMyExample::ServiceMyExample()\n" for the constructor) and must be followed by a descriptive error message. All error message lines must end with a newline ("\n"), but the newline must not be included into the call to the localization function ($this->i18n( "string" )).
Localization support
One of the first things in the constructor which should be done is the call of the Locale constructor by
Locale::Locale( "localearea", "../lib/locale" );
This ensures, that all (error) messages included into $this->i18n( "string" ) are correctly translated into the language selected by the user. The string "localearea" must be replaced by the appropriate string for this service. A set of classes, which use the same locale area also share the same locale file. All classes related to ldap - the ldap modules in lib/modules/*/ and the support classes in lib/support/ldap/ for example - are in the same locale area "ldap". Thus all messages, which should be translated are in the same file used by gettext for its lookup. The second parameter is the directory, which contains the subdirectories for the available languages. The path has to be relative to the location of the file called by the web browser. For a support module this is always "../lib/locale".
Member functions
The parameters of the member functions, which encapsulates the functionality provided by the service, are not restricted because they depend on the specific service or library API. The appropriate connector in the application is responsible for calling the function with the appropriate parameters.
The naming convention for member functions should be the same as in C++. They should be in lower case and the first character of the second an all subsequent words in upper case, e.g. myMemberFunction(). If a member function should be not used outside the class and is therefore the same as a private function in a C++ class, it should begin with the character "p", e.g. pMyPrivateFunction().
Function and parameter description
The return value of a member function should be TRUE and FALSE so that the calling function can check for this values. If the member function must return a value, then it should be stored in a parameter provided by the calling function and returned by reference. A set of values can also be returned by several parameters or by storing them into an array and returning them as one parameter. This depends on the output of the service or library API or the number of the parameters. An example would be
function myMemberFunction( $input, &$output, &$errmsg ) { return TRUE; }
where $input is the input parameter and &$output is used to store the values returned by the service or the library API.
The last thing you must do is to include the &$errmsg variable as the last parameter. If a function returned an error, your member function should append the name of your function (e.g. "ServiceMyService::myMemberFunction()\n") and a descriptive error message by using the ".=" operator. The error message must be included into a call to the $this->i18n() function to translate it into the chosen language. Finally a newline ("\n") must be appended after each line, but it must not be included into the i18n call.
Now have a lot of fun ;-)
Back to PHPGeneral