Call us: +1 (716) 989 6531 or email at:

Forecasting Software for sales, demand and call volumes

RSS RSS

Navigation





Search the wiki
»

PoweredBy

Web Services Tutorial with PHP5 and standard SOAP libraries for Time-Series Forecasting

RSS
Developers » Web Services » Here

Deprecated content. Please refer to the Programmers Guide to Forecasting API v3 instead.

Web Services Tutorial with PHP5 and standard SOAP libraries

Last revision: 2008-09-07 By Toby Champion

Target audience: developers, system administrators

In this tutorial, we will see how to use Lokad Web Services in a simple application written in PHP 5 and using the SOAP extension distributed with PHP 5. Lokad specializes in business time-series forecasting, but this document is neither an introduction to Lokad nor an introduction to Web Services.

Download: source-code for this tutorial


Requirements
(*) The Free subscription plan is sufficient to reproduce this tutorial, with the exception of the last section Retrieving forecasts which requires that the Enterprise plan be selected in your Lokad account.

Introduction

Web Services are an industrial-strength standard currently embraced by most (if not all) major software vendors. Lokad features Web Services: all operations that can be performed from the web application can also be performed programmatically through our Web Services. The Lokad Web Services can be reached at


Creating a SOAP client object using the WSDL

You should use http://sandbox-ws.lokad.com/TimeSeries.asmx?wsdl as a test WSDL URL. The call below uses the production version. To use the production WSDL instead, remove the prefix sandbox-.
$client = new SOAPClient('http://sandbox-ws.lokad.com/TimeSeries.asmx?wsdl');

Web Services Authentication

Lokad Web Services are authenticated: to access our Web Services, as part of each method call you must provide the username and password associated with your Lokad Web Account. Lokad relies on SOAP headers to authenticate each call.

You can check your headers will authenticate your SOAP requests by using the SOAP method IsAuthenticated, which will return true or false depending on whether the call was authenticated. The code below calls this method and prints the result: it will be false, because we've not yet added the authentication information to the SOAP header.
try {
    $result = $client->IsAuthenticated();
} catch (SoapFault $soapFault) {
    die($soapFault);
}
printf("result = %d", $result->IsAuthenticatedResult); // This will be 0 (false)

Let's now add the authentication information. What we want to end up with is a header in the SOAP request that looks something like this:

<SOAP-ENV:Header>
    <AuthHeader xmlns="lokad.com/ws">
        <UserName>user@example.com</UserName>
        <Password>password</Password>
    </AuthHeader>
</SOAP-ENV:Header>

To do this, we can use the __setSOAPHeaders method on the SOAP client to ensure each request will include this information in the header:
$username = 'email@example.com';
$password = 'mypassword';

$ns = "lokad.com/ws"; $auth = array(); $auth['UserName'] = new SOAPVar($username, XSD_STRING, null, null, null, $ns); $auth['Password'] = new SOAPVar($password, XSD_STRING, null, null, null, $ns); $headerBody = new SOAPVar($auth, SOAP_ENC_OBJECT); $header = new SOAPHeader($ns, 'AuthHeader', $headerBody); $client->__setSOAPHeaders(array($header));

We can now call the IsAuthenticated again to check that we've got it right:
try {
    $result = $client->IsAuthenticated();
} catch (SoapFault $soapFault) {
    die($soapFault);
}
printf("result = %d\n", $result->IsAuthenticatedResult); // This will be 1 (true)

Time-series management

Lokad specializes in time-series forecasting. Before actually performing a forecast, you first need to upload your data; and this can be easily achieved with our Web Services. Technically, a time-series is simply an array of time-value pairs. Let's see how a time-series can be generated programmatically.

First, we'll create an array of time-value pairs, with $length entries:
class TimeValue {
  public function __construct($time, $value)
    {
      $this->Time = date('Y-m-d\TH:i:s', $time);
      $this->Value = $value;
    }
}

function randomTimeSerie($length) { $timeValues = array(); for ($i = 0; $i < $length; $i++) { $times = mktime(0, 0, 0, date("m"), date("d") + $i, date("Y")); $timeValues[$i] = new TimeValue($time, rand()); } return $timeValues; }

Note that we specify a UtcOffset in the example above; this value is expressed in hours according to the formula local time = UTC time + offset. In our example, for simplicity, the values are regularly spaced (one day increment for each value) but this is not a requirement. The intervals between the successive values can vary arbitrarily.

We'll now create a TimeSerie object with our ten entries, and add this to your Lokad account.

Naming conventions: although the word serie (singular) does not exist in English, we have found it quite convenient to distinguish serie (singular) from series (plural) in the source code. So, when the term serie is used in our examples, it's not a mistake, it's intentional.

We'll define our TimeSerie class, create an instance populated with our array, and call the AddSerie Web Service method to add the time series to our account:
class TimeSerie {
    public function __construct($name,  $unitName, $utcOffset)
        $this->Name = $name;
        $this->UnitName = $unitName;
        $this->UtcOffset = $utcOffset;
        $this->TimeValues = null;
    }
}

$timeSerie = new TimeSerie('TestSerie'.rand(), '', 0); $timeSerie->TimeValues = array('TimeValue' => randomTimeSerie(10));

try { $result = $client->AddSerie(array('serie' => $timeSerie)); } catch (SoapFault $soapFault) { die($soapFault); }

To delete a time-series from your account, you just need to specify the name identifier of the time-series in question:
try {
    $result = $client->DeleteSerie(array('serieName' => 'My Time Series'));
} catch (SoapFault $soapFault) {
    die($soapFault);
}

You can also retrieve the names of the existing time-series in your account; the following code outputs the names of the time-series in your account. We'll define a function, to_array(), to handle the special cases of Lokad results coming back through the PHP 5 SOAP extension.
function to_array ($data) {
  if (!property_exists($data, 'string')) // 0 elements
    return array();
  else if (is_string($data)) // 1 element
    return array($data);
  else // >1 elements
    return $data->string;
}

try { $result = $client->GetAllSerieNames(); } catch (SoapFault $soapFault) { die($soapFault); }

foreach (to_array($result->GetAllSerieNamesResult) as $key => $name) echo "$name\n";

You can retrieve the time-value pairs in a particular series as follows:
try {
    $result = $client->GetSerie(array('serieName' => $timeSerie->Name));
} catch (SoapFault $soapFault) {
    die($soapFault);
}
   
printf("Here is the data in %s:\n\n", $timeSerie->Name);
printTimeValues($result->GetSerieResult->TimeValues->TimeValue);

function printTimeValues($timeValues) { foreach ($timeValues as $timeValue) printf("%s %d\n", $timeValue->Time, $timeValue->Value); }

Forecasting task management

Before you can retrieve a time-series forecast, you need to define a forecasting task that will specify how the forecast time-series should be computed. In the Lokad data model, a forecasting task is always associated with a particular time-series; several forecasting tasks can be associated with the same time-series.
class Task {
    public function __construct($name, $aggregator, $period, $pastPeriods,
                                $futurePeriods, $periodStart))
    {
        $this->Name = $name;
        $this->Aggregator = $aggregator;
        $this->Period = $period;
        $this->PastPeriods = $pastPeriods;
        $this->FuturePeriods = $futurePeriods;
        $this->PeriodStart = $periodStart;
    }
}

$task = new Task('TestTask'.rand(), 'Sum', 'Day', 10, 5, '2001-01-01T00:00:00');

Tip: the time-series names should be unique within the scope of your Lokad account (you cannot have two distinct time-series identified by the same name). However, the names of the forecasting tasks only need to be unique within the scope of their base time-series. In other words, you can have several forecasting tasks identified by the same name but associated with different time-series.

Now we add the task.
try {
    $result = $client->AddTask(array('serieName' => $timeSerie->Name,
	                                    'task' => $task));
} catch (SoapFault $soapFault) {
    die($soapFault);
}

Retrieving forecasts

The following code will retrieve the forecasts for the task previously created.
try {
    $result = $client->GetSerie(array('serieName' => $timeSerie->Name));
} catch (SoapFault $soapFault) {
    die($soapFault);
}

printTimeValues($result->GetSerieResult->TimeValues->TimeValue);

try { $result = $client->GetForecast(array('serieName' => $timeSerie->Name, 'taskName' => $task->Name)); } catch (SoapFault $soapFault) { die($soapFault); }

printTimeValues($result->GetForecastResult->TimeValues->TimeValue);
Google Code

All add-ons developed by Lokad have been released as open source under the BSD license on Google Code.

The BSD license is compatible with closed-source commercial applications. Integrating a forecasting technology has never been easier.

What people say

From a developer standpoint, we found that the Lokad API was very well documented and easy to use. The Lokad team was also extremely responsive to any questions we had. Most importantly, we were able to develop a Lokad plugin for our data browser in very short order. Jeff Engel, Kirix Corporation