Services
From Harmoni
Contents |
Introduction
History and OSID relationship
The Harmoni Services system provides global access to configured instances of OSID and Harmoni services. Services can be configured once during application startup and then accessed and used elsewhere in the program.
The Services system accomplishes approximately the same function of the OSIDLoader in version 2 of the OSIDs. For historical reasons and some technical limitations of OSIDv2, we never implemented the OSIDLoader and are still using this Services API. The architecture of the upcoming OSIDv3 makes the OSIDLoader much more attractive for use, and the Services system will likely become less used in OSIDv3 implementations.
Overview
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:
- registration
- starting (instantiation/configuration)
- accessing
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.
$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:
function storeMyFile($file, $path, $filename) {
$storage = Services::getService("Storage");
return $storage->store($file, $path, $filename);
}
Registering New Services
Services methods involved in registration are
- Services::registerService(<a service name>, <a class name>)
- Services::registerObjectAsService(<a service name>, <an object>)
- Services::createServiceAlias(<a service name>, <an alias>)
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.
...
/*********************************************************
* 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".
assignContext() and assignConfiguration() methods defined in the OsidManager interface. Please note that this is a hack. Future versions of Harmoni written in PHP5 may require that services actually implement 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:
$myObj = new SomeClass($bla, $foo);
Services::registerObjectAsService("MyServiceTwo",$myObj);
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).
...
/*********************************************************
* 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);
...
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.

