Login / Status
developer.Resource
Home . Documentation . Document Library . Core Documentation
Sponsors
hosted by punkt.deTYPO3 and Open Source Magazine

1.4. Developer's Guide

This chapter describes all you need to know to develop a new service, including advice to developing good services.

Introducing a new service type

Every service belongs to a given service type. A service type is represented by a key, just like an extension key. In the examples above there was mention of the “auth” and “metaExtract” service types.

Each service type will implement its own API corresponding to the task it is designed to handle. For example the “auth” service type requires the two methods getUser() and authUser(). If you introduce a new service type you should think well about its API before starting development. Ideally you should discuss with other developers. Services are meant to be reusable. A badly designed service that is used only once is a failed service. The development mailing list (typo3.dev) is a good place to discuss new service types.

You should plan to provide a base class for your new service type. It is then easier to develop services based on this type as you can start by extending the base class. You should also provide a documentation, that describes the API. It should be clear to other developers what each method of the API is supposed to do.

Implementing a service

The best way to get started when implementing a service is to use the Extension Kickstarter. It will help you create the skeleton of your service. In the Kickstarter you start by setting the general information and declaring that your extension is of type “Service”:

Then move to the “Services” section if the left-hand menu and define a first service. Your screen might look something like this:

Apart from the standard extension declaration file (ext_emconf.php) and extension's icon (ext_icon.gif), the Kickstarter will create the following files:

  1. ext_localconf.php where the service is declared

  2. sv1/class.tx_myext_sv1.php where the code of the service resides

As can be seen the naming convention for services is very close to the one used for FE plug-ins, using “sv” instead of “pi”.

Service registration

Registering a service is done inside the ext_localconf.php file. Let's look at what is inside.

<?php

if (!defined ('TYPO3_MODE')) {

 die ('Access denied.');

}

t3lib_extMgm::addService($_EXTKEY, 'textLang' /* sv type */, 'tx_babelfish_sv1' /* sv key */,

array(

'title' => 'Babelfish',

'description' => 'Guess alien languages by using a babelfish',

'subtype' => '',

'available' => true,

'priority' => 60,

'quality' => 80,

'os' => '',

'exec' => '',

'classFile' => t3lib_extMgm::extPath($_EXTKEY).'sv1/class.tx_babelfish_sv1.php',

'className' => 'tx_babelfish_sv1',

)

);

?>

A service is registered with TYPO3 by calling t3lib_extMgm::addService(). This method takes the following parameters:

Parameter:

Data type:

Description:

$extKey

string

The key of the extension containing the service.

$serviceType

string

Service type of the service.

$serviceKey

string

Unique key for the service. By default, the Kickstarter creates the key as “tx_myext_sv1” for the first service, “tx_myext_sv2” for the second service, etc. This may be changed freely, but the key should be explicit of the service's function.

$info

array

Additional information about the service. This is described below.

The additional information array defines the main properties of a service:

Property:

Data type:

Description:

Default:

title

string

The title of the service.

description

string

The description. If it makes sense it should contain information about

  1. the quality of the service (if it's better or not than normal)

  2. the OS dependency

  3. the dependency on external programs (perl, pdftotext, etc.)

subtype

string / comma list

The subtype is not predefined. Its usage is defined by the API of the service type.

Example:

'subtype' => 'jpg,tif',

available

boolean

Defines if the service is available or not. This means that the service will be ignored if available is set to false.

It makes no sense to set this to false, but it can be used to make a quick check if the service works on the system it installed:

Examples:

  // is the curl extension available we need
'available' => is_function('curl_exec'),

Only quick checks are appropriate here. More extensive checks should be performed when the service is requested and the service class is initialized.

true

priority

integer

The priority of the service. A service of higher priority will be selected first. Can be reconfigured with $TYPO3_CONF_VARS.

Use a value from 0 to 100. Higher values are reserved for reconfiguration by $TYPO3_CONF_VARS. The default value is 50 which means that the service is well implemented and gives normal (good) results.

Imagine that you have two solutions, a pure PHP one and another that depends on an external program. The PHP solution should have a priority of 50 and the other solution a lower one. PHP-only solutions should have a higher priority since they are more convenient in terms of server setup. But if the external solution gives better results you should set both to 50 and set the quality value to a higher value.

50 (0-100)

quality

integer/float

Among services with the same priority, the service with the highest quality by the same priority will be preferred.

The use of the quality range is defined by the service type. Integer or floats can be used. The default range is 0-100 and the default value for a normal (good) quality service is 50.

The value of the quality should represent the capacities of the services. Consider a service type that implements the detection of a language used in a text. Let's say that one service can detect 67 languages and another one only 25. These values could be used directly as quality values.

50 (0-100)

os

string

Defines which operating system is needed to run this service.

Examples:

  // runs only on UNIX

'os' => 'UNIX',

  // runs only on Windows

'os' => 'WIN',

  // no special dependency

'os' => '',

exec

string / comma list

List of external programs which are needed to run the service. Absolute paths are allowed but not recommended, because the programs are searched for automatically by t3lib_exec. Leave empty if no external programs are needed.

Examples:

'exec' => 'perl',

'exec' => 'pdftotext',

classFile

string

Created by the kickstarter

Example:

t3lib_extMgm::extPath($_EXTKEY).'sv1/class.tx_myextkey_sv1.php'

className

string

Created by the kickstarter

Example:

'tx_myextkey_sv1'

Skeleton service class

The Kickstarter will generate a skeleton PHP class for each service defined. The example above will generate file sv1/class.tx_babelfish_sv1.php, which contains the following sample code:

/**
 * Service "Babelfish" for the "babelfish" extension.
 *
 * @authorZaphod Beeblebrox <zaphod@goldenheart.com>
 * @packageTYPO3
 * @subpackagetx_babelfish
 */
class tx_babelfish_sv1 extends t3lib_svbase {
var $prefixId = 'tx_babelfish_sv1';// Same as class name
var $scriptRelPath = 'sv1/class.tx_babelfish_sv1.php';// Path to this script relative to the extension dir.
var $extKey = 'babelfish';// The extension key.
/**
 * [Put your description here]
 *
 * @return[type]...
 */
function init(){
$available = parent::init();
// Here you can initialize your class.
// The class have to do a strict check if the service is available.
// The needed external programs are already checked in the parent class.
// If there's no reason for initialization you can remove this function.
return $available;
}
/**
 * [Put your description here]
 * performs the service processing
 *
 * @paramstringContent which should be processed.
 * @paramstringContent type
 * @paramarrayConfiguration array
 * @returnboolean
 */
function process($content='', $type='', $conf=array()){
// Depending on the service type there's not a process() function.
// You have to implement the API of that service type.
return false;
}
}

This sample code shows how a service class must inherit from the t3lib_svbase base class, which is described in more details below. It provides a skeleton for the init() method which is the single most important method for a service, as it defines – at runtime – whether a given service is really available or not. This method is also discussed in more details below.

The skeleton process() method is just an example of what you might want to implement in your service depending on the API of the service type. In the example Kickstarter input above, the “babelfish” service was declared as a “textLang” type of service. In this case the specific service type API indeed consists of just the process() method.

The sample code generated by the Kickstarter may change in the future.

Service API

All service classes must inherit from the base service class t3lib_svbase, unless the service type provides a specific base class (authentication services, for example, inherit from tx_sv_authbase instead). These specific classes should normally themselves extend t3lib_svbase. This class provides a large number of important or useful methods which are described below, grouped by type of usage.

Getter methods for service information

Most of the below methods are quite obvious, except for getServiceOption().

Method:

Description:

getServiceInfo

Returns the array containing the service's properties

getServiceKey

Returns the service's key

getServiceTitle

Returns the service's title

getServiceOption

This method is used to retrieve the value of a service option, as defined in the $TYPO3_CONF_VARS['SVCONF'] array. It will take into account possible default values as described in the “Service configuration” chapter above.

The getServiceOption() method requires more explanations. Imagine your service has an option called “ignoreBozo”. To retrieve it in a proper way, you should not access $TYPO3_CONF_VARS['SVCONF'] directly, but use getServiceOption() instead. In its simplest form, it will look like this (inside your service's code):

$ignoreBozo = $this->getServiceOption('ignoreBozo');

This will retrieve the value of the “ignoreBozo” option for your specific service, if defined. If not, it will try to find a value in the default configuration. Additional call parameters can be added:

  1. the second parameter is a default value to be used if no value was found at all (including in the default configuration)

  2. the third parameter can be used to temporarily switch off the usage of the default configuration.

This allows for a lot of flexibility.

Error handling

This set of methods handles the error reporting and manages the error queue. The error queue works as a stack. New errors are added on top of the previous ones. When an error is read from the queue it is the last one in that is taken (last in, first out). An error is actually a short array comprised of an error number and an error message.

The error queue exists only at run-time. It is not stored into session or any other form of permanence.

Method:

Description:

devLog

Writes a message to the devlog, implicitly using the service key as a log key. Depends on the member variable “writeDevLog” being set to true (it's set to false by default).

errorPush

Puts a new error on top of the queue stack.

errorPull

Removes the latest (topmost) error in the queue stack.

getLastError

Returns the error number from the latest error in the queue, or true if queue is empty.

getLastErrorMsg

Same as above, but returns the error message.

getErrorMsgArray

Returns an array with the error messages of all errors in the queue.

getLastErrorArray

Returns the latest error as an array (number and message).

resetErrors

Empties the error queue.

General service functions

Method:

Description:

checkExec

This method checks the availability of one or more executables on the server. A comma-separated list of excutables names is provided as a parameter. The method returns true if all executables are available.

The method relies on t3lib_exec::checkCommand() to find the executables, so it will search through the paths defined/allowed by the TYPO3 configuration.

deactivateService

Internal method to temporarily deactivate a service at run-time, if it suddenly fails for some reason.

I/O tools

A lot of early services were designed to handle files, like those used by the DAM. Hence the base service class provides a number of methods to simplify the service developer's life when it comes to read and write files. In particular it provides an easy way of creating and cleaning up temporary files.

Method:

Description:

checkInputFile

Checks if a file exists and is readable within the paths allowed by the TYPO3 configuration.

readFile

Reads the content of a file and returns it as a string. Calls on checkInputFile() first.

writeFile

Writes a string to a file, if writable and within allowed paths. If no file name is provided, the data is written to a temporary file, as created by tempFile() below. The file path is returned.

tempFile

Creates a temporary file and keeps its name in an internal registry of temp files.

registerTempFile

Adds a given file name to the registry of temporary files.

unlinkTempFiles

Deletes all the registered temporary files.

I/O Input and I/O output

These methods provide a standard way of defining or getting the content that needs to be processed – if this is the kind of operation that the service provides – and the processed output after that.

Method:

Description:

setInput

Sets the content (and optionally the type of content) to be processed.

setInputFile

Sets the input file from which to get the content (and optionally the type).

getInput

Gets the input to process. If the content is currently empty, tries to read it from the input file.

getInputFile

Gets the name of the input file, after putting it through checkInputFile(). If no file is defined, but some content is, the method writes the content to a temporary file and returns the path to that file.

setOutputFile

Sets the output file name.

getOutput

Gets the output content. If an output file name is defined, the content is gotten from that file.

getOutputFile

Gets the name of the output file. If such file is not defined, a temporary file is created with the output content and that file's path is returned.

Service implementation

These methods are related to the general functioning of services. init() and reset() are the most important methods to implement when developing your own services.

Method:

Description:

init

This method is expected to perform any necessary initialization for the service. Its return value is critical. It should return false if the service is not available for whatever reason. Otherwise it should return true.

Note that's it's not necessary to check for OS compatibility, as this will already have been done by t3lib_extMgm::addService() when the service is registered.

Executables should be checked, though, if any.

The init() method is automatically called by t3lib_div::makeInstanceService() when requesting a service.

reset

When a service is requested by a call to t3lib_div::makeInstanceService(), the generated instance of the service class is kept in a registry ($GLOBALS['T3_VAR']['makeInstanceService']). When the same service is requested again during the same code run, a new instance is not created. Instead the stored instance is returned. At that point the reset() method is called.

This method can be used to clean up data that may have been set during the previous use of that instance.

__destruct

Clean up method. The base implementation calls on unlinkTempFiles() to delete all temporary files.

The little schema below summarizes the process of getting a service instance and when each of init() and reset() are called.

Service-related API

This section describes the methods of the TYPO3 core that are related to the use of services.

t3lib_extMgm

This extension management class contains three methods related to services:

Method:

Description:

addService

This method is used to register services with TYPO3. It checks for availability of service with regards to OS dependency (if any) and fills the $GLOBALS['T3_SERVICES'] array, where information about all registered services is kept.

findService

This method is used to find the appropriate service given a type and a subtype. It handles priority and quality rankings. It also checks for availability based on executables dependencies, if any.

This method is normally called by t3lib_div::makeInstanceService(), so you shouldn't have to worry about calling it directly, but it can be useful to check if there's at least one service available.

deactivateService

Marks a service as unavailable. It is called internally by addService() and findService() and should probably not be called directly unless you're sure of what you're doing.

t3lib_div

This class contains a single method related to services, but the most useful one, used to get an instance of a service.

Method:

Description:

makeInstanceService

This method is used to get an instance of a service class of a given type and subtype. It calls on t3lib_extMgm::findService() to find the best possible service (in terms of priority and quality).

As described above it keeps a registry of all instantiated service classes and uses existing instances whenever possible, in effect turning service classes into singletons.