:: Table of Contents ::
 
Chapter 3: The Services Setup
3.1 Introduction

The Harmoni Services offer two things: global access to pre-programmed classes, supplying authentication, file storage and others; and a way for you to make classes or objects you write available to all scopes of you program.

This chapter will concentrate on how Services are fetched and created, not on the individual supplied services themselves. For descriptions about those, see the next chapter.

The life-cycle of services includes the following steps:

3.2 Accessing a Pre-defined Service

Use the Services::getService() method anywhere in your application to get a reference to the desired service. If the service of the name that you requested has not been registered or started, an error will be thrown.

Example
$myService =& Services::getService("MyService");
:: Using wrapper classes/functions ::

To make some services even more accessible, one can write wrapper classes or functions to do common tasks with a specific service. For examples of these, take a look at the throwError and userError functions, and the debug class. These are all wrappers for the ErrorHandler, UserError and Debug services, respectively. A short example wrapper function:

Example
function storeMyFile(&$file, $path, $filename) {
    
$storage =& Services::getService("Storage");
    return
$storage->store($file, $path, $filename);
}
3.3 Registering New Services

Services methods involved in registration are

The registration process associates a service name (and aliases if desired) with a particular class name or object. This allows applications to ask for say, "MyService" even if the desired class has change from "MyBasicService" to "MyNewAndImprovedService". Only the registration line would have to be updated to reflect the change.

The Services::registerObjectAsService() allows already instantiated objects to be used and access as services. However, they already are instantiated they cannont be started, only retrieved.

Aliases allow for one service to be referenced by multiple names as your codebase evolves. If we would like to start referring to the "MyService" as the "MySomethingManager" we could simply create an alias Services::createServiceAlias("MyService", "MySomethingManager") without breaking old code that uses the old name.

Example
...

/*********************************************************
* Registration
*********************************************************/
// Include the class file
require_once(HARMONI."errorHandler/ErrorHandler.class.php");

// Register the Service
Services::registerService("ErrorHandler","ErrorHandler");

// Create an alias if desired
Services::createServiceAlias("ErrorHandler", "ErrorManager");

...

Creating new services is easy: Service::registerService("myService","className"). You can name your service anything, as long as another service doesn't have that name. The className argument is the class that should be instantiated. Any class you register should not take any constructor parameters and must implement the OsidManager interface so that it can be configured using assignConfiguration($configurationProperties) and given a context via assignOsidContext($osidContext). Then, anywhere you want, you can get the service named "MyService", and it will hand you the object of the class "className".

NOTE
PHP4 does not have a notion of object interfaces built in. All objects in PHP4 are simply classes. When we write interfaces in Harmoni, we simply write class and name it "interface" and impliment it with a die function that must be over-ridden by child classes. Generally this works fine, but sometimes a class needs to inherit functions from multiple "interfaces". Since classes can only extend a single implimented class, there is no way to have any sort of multiple inheritance in PHP4. To get around this limitation, the current (PHP4) HarmoniServices class does not check specifically that a service extends the "Service" interface, but instead checks that the service provides the start and stop methods defined in the interface. Please note that this is a hack. Future versions of Harmoni written in PHP5 may require that services actually impliment the "Services" interface. But all will be well then with the better object support promised for PHP5.
:: Registering Already Instantiated Objects ::

Sometimes it's useful to register a class that's already been instantiated as a service. This is especially useful if the class' constructor takes arguments. Here's the code:

Example
$myObj =& new SomeClass($bla, $foo);
Services::registerObjectAsService("MyServiceTwo",$myObj);
3.4 Starting Services

Services should not take any constructor parameters and must implement the OsidManager interface so that they can be configured using assignConfiguration($configurationProperties) and given a context via assignOsidContext($osidContext).

Example
...

/*********************************************************
* Registration
*********************************************************/
// Include the class file
require_once(HARMONI."errorHandler/ErrorHandler.class.php");

// Register the Service
Services::registerService("ErrorHandler","ErrorHandler");

// Create an alias if desired
Services::createServiceAlias("ErrorHandler", "ErrorManager");

...

/*********************************************************
* Starting
*********************************************************/
// Create an OsidContext object
// The ErrorHandler doesn't require any Context information, but the Harmoni object
// is useful for many classes, so we will just include it for example purposes.
require_once(OKI2."osid/OsidContext.php");
$context =& new OsidContext;
$context->assignContext('harmoni', $harmoni);

// Create a Properties object for configuration, empty as the ErrorHandler
// doesn't require any configuration.
require_once(HARMONI."oki2/shared/ConfigurationProperties.class.php");
$configuration =& new ConfigurationProperties;

// Start the Service
Services::startManagerAsService("ErrorHandler", $context, $configuration);

...

3.5 Replacing Existing Services

Replacing existing services is as easy as adding them. Two things need to be true for this to work though: 1) the service can't be started, 2) to avoid breaking a program, it must implement the same interface as the service to be replaced. Just call the registerService method with the same service name as the one you want to replace.

Version: $Id: 3.html,v 1.30 2005/04/06 22:35:01 adamfranco Exp $