Initialisation of the JobRouter Client

 2use Brotkrueml\JobRouterClient\Client\RestClient;
 3use Brotkrueml\JobRouterClient\Configuration\ClientConfiguration;
 4use Brotkrueml\JobRouterClient\Exception\ExceptionInterface;
 6require_once 'vendor/autoload.php';
 8$configuration = new ClientConfiguration(
 9   '', // The base URL of the JobRouter installation
10   'the_user', // The username
11   'the_password' // The password
13$configuration = $configuration->withLifetime(30);
15try {
16   $client = new RestClient($configuration);
17} catch (ExceptionInterface $e) {
18   echo $e->getCode() . "\n";
19   echo $e->getMessage() . "\n";
21   if ($e->getPrevious()) {
22      var_dump($e->getPrevious());
23   }

Let’s dig into the piece of code:

  1. Lines 2-4: The JobRouter client library uses the namespace Brotkrueml\JobRouterClient, the uses ease the using of the following classes.

  2. Line 6: Require the autoloading file, so the classes are found and can be used.

  3. Lines 8-11: Define a ClientConfiguration object with the base URL, the username and the password for your JobRouter® installation.

  4. Line 13: Overrides the default lifetime of the JSON Web Token in seconds. The default value is 600 seconds - if you are fine with this, you can omit calling the method. As the configuration object is immutable, a new instance of the configuration is returned.

  5. Line 16: Now instantiate the RestClient with the configuration object. During the instantiation the client will authenticate against the JobRouter® installation.

  6. Line 17: As there can be errors during the initialisation - like a typo in the base URL or wrong credentials, so embed the initialisation into a try/catch block. The thrown exception is by default an implementation of the ExceptionInterface. The exception encapsulates sometimes another exception, you’ll get it with ->getPrevious(). Of course, you can also catch by \Exception or \Throwable.

After the initialisation part you can now request the needed data or store some data. You can make as many requests as you want, but keep in mind: When the lifetime of the token is exceeded you will get an authentication error. For now, you have to handle it on your own. If this happens, you can call at any time the authenticate() method of the rest client:

// The JobRouter Client is already initialised


Call this also in advance to omit a timeout.

Retrieve the JobRouter Version

Sometimes it can be handy to know the JobRouter® version. The version number can be retrieved with a RestClient method:

// The JobRouter Client is already initialised


Sending Requests

The RestClient object exposes a request() method to send a request to the JobRouter® REST API:

2// The JobRouter Client is already initialised
4$response = $client->request(
5   $method,
6   $resource,
7   $data


The method can be every available HTTP verb, like GET, POST, PUT or DELETE that is available to the requested resource.


The resource without the base URL and the API path, e.g. application/sessions to retrieve the session of the current user.


The third parameter is optional. This is an array which holds the data to be send along with the request.


Retrieving a JobData Dataset

Let’s start with an example to retrieve some data out of a JobData table. We assume the client is already initialised, like in the introduction above:

 2// The JobRouter Client is already initialised
 4try {
 5   $response = $client->request(
 6      'GET',
 7      'application/jobdata/tables/FB6E9F2F-8486-8CD7-5FA5-640ACB9019E4/datasets'
 8   );
10   echo $response->getStatusCode() . "\n";
11   var_dump($response->getBody()->getContents());
12} catch (ExceptionInterface $e) {
13   // Error handling
  1. Lines 5-8: With the request() method we’ll send a request to the JobRouter® installation. In this example, the method is GET as we want to retrieve data. The second parameter is the resource to the Jobdata module with the GUID of the table. The $response is an object which implements the Psr\Http\Message\ResponseInterface which itself extends the Psr\Http\Message\MessageInterface

  2. Line 10: The ResponseInterface object exposes some methods. One is to get the status code.

  3. Line 11: As the body of the response is returned as a stream you’ll have to use ->getBody()->getContents() to retrieve a string of the response’s body (in this case JSON-encoded).

Posting a JobData Dataset

With the following request you can post a dataset to a JobData table:

 2// The JobRouter Client is already initialised
 4try {
 5   $response = $client->request(
 6      'POST',
 7      'application/jobdata/tables/FB6E9F2F-8486-8CD7-5FA5-640ACB9019E4/datasets',
 8      [
 9         'dataset' => [
10            'column1' => 'content of column 1',
11            'column2' => 'content of column 2',
12         ],
13      ]
14   );
15} catch (ExceptionInterface $e) {
16   // Error handling
  1. Line 6: As we add a new dataset we have to use the POST method.

  2. Lines 8-13: As third parameter of the request() method the data is defines to sent with the request.


Prior to JobRouter® 5.0.8 you have to send all columns of a table for which the user has access rights. Otherwise you will receive an error with status code 422 (Unprocessable entity).

Starting a new Instance of a Process

To start a new instance of a process you have to send the data as multipart/form-data instead of JSON like the previous examples:

 2use Brotkrueml\JobRouterClient\Resource\File;
 4// The JobRouter Client is already initialised
 6// Define instance data
 7$multipart = [
 8   'step' => '1',
 9   'summary' => 'Instance started via JobRouter Client',
10   'processtable[fields][0][name]' => 'INVOICENR',
11   'processtable[fields][0][value]' => 'IN02984',
12   'processtable[fields][1][name]' => 'INVOICE_FILE',
13   'processtable[fields][1][value]' => new File(
14      '/path/to/invoice/file.pdf', // Full path to the file
15      'in02984.pdf', // Optional: Use another file name for storing in JobRouter
16      'contentType' => 'application/pdf' // Optional: The content type
17   ),
20try {
21   $response = $client->request(
22      'POST',
23      'application/incidents/invoice',
24      $multipart
25   );
26} catch (ExceptionInterface $e) {
27   // Error handling
  1. Lines 5-18: Preparing the data to send as an array according to the JobRouter® REST API documentation. To add a file instantiate a Brotkrueml\JobRouterClient\Resource\File object. The first argument receives the full path to the file, the other two are optional: You can overwrite the file name and specify a content type.

  2. Lines 21-25: Send the data.

But instead of having the hassle with the complex processtable and subtable structure just use the IncidentsClientDecorator which gives you an API to handle all the process table and sub table stuff:

 2// Additional uses
 3use Brotkrueml\JobRouterClient\Client\IncidentsClientDecorator;
 4use Brotkrueml\JobRouterClient\Model\Incident;
 5use Brotkrueml\JobRouterClient\Resource\File;
 7// The JobRouter Client is already initialised
 9$incident = (new Incident())
10   ->setStep(1)
11   ->setSummary('Instance started via IncidentsClientDecorator')
12   ->setProcessTableField('INVOICENR', 'IN02984')
13   ->setProcessTableField(
14      'INVOICE_FILE',
15      new File(
16         '/path/to/invoice/file.pdf', // Full path to the file
17         'in02984.pdf', // Optional: Use another file name for storing in JobRouter®
18         'contentType' => 'application/pdf' // Optional: The content type
19      )
20   )
23try {
24   $incidentsClient = new IncidentsClientDecorator($client);
26   $response = $incidentsClient->request(
27      'POST',
28      'application/incidents/invoice',
29      $incident
30   );
31} catch (ExceptionInterface $e) {
32   // Error handling

This is much more intuitive. So, let’s have a look:

  1. Lines 9-21: Create an object instance of the Incident model and use the available setters to assign the necessary data.

  2. Line 24: Create the IncidentsClientDecorator. As an argument it gets an already initialised RestClient instance. It is a decorator for the Rest Client, so you can also use it to authenticate or make other requests, e.g. to the JobData module.

  3. Lines 26-30: Use the Incident model as third argument for the request() method. As usual you’ll get a ResponseInterface object back with the response of the HTTP request. If you would pass an array the request is passed unaltered to the Rest Client.

Archiving a Document

Archiving a document is as easy as starting an instance:

 2use Brotkrueml\JobRouterClient\Resource\File;
 4// The JobRouter Client is already initialised
 6// Define document data
 7$documentContentAndMetaData = [
 8   'indexFields[0][name]' => 'INVOICENR',
 9   'indexFields[0][value]' => 'IN02984',
10   'files[0]' => new File('/path/to/invoice/in02984.pdf'),
13try {
14   $response = $client->request(
15      'POST',
16      sprintf('application/jobarchive/archives/%s/documents', 'INVOICES'),
17      $documentContentAndMetaData
18   );
19} catch (ExceptionInterface $e) {
20   // Error handling

You can also use the DocumentsClientDecorator which eases the handling of the multipart array:

 2// Additional uses
 3use Brotkrueml\JobRouterClient\Client\DocumentsClientDecorator;
 4use Brotkrueml\JobRouterClient\Model\Document;
 5use Brotkrueml\JobRouterClient\Resource\File;
 7// The JobRouter Client is already initialised
 9$document = (new Document())
10   ->setIndexField('INVOICENR', 'IN02984')
11   ->addFile(new File('/path/to/invoice/in02984.pdf'));
13try {
14   $documentsClient = new DocumentsClientDecorator($client);
16   $response = $documentsClient->request(
17      'POST',
18      sprintf('application/jobarchive/archives/%s/documents', 'INVOICES'),
19      $document
20   );
21} catch (ExceptionInterface $e) {
22   // Error handling

Nesting of Client Decorators

The decorators can be nested. This can be useful when, e.g., posting to a JobData table, then archiving a document and at last starting an instance:

 2use Brotkrueml\JobRouterClient\Client\DocumentsClientDecorator;
 3use Brotkrueml\JobRouterClient\Client\IncidentsClientDecorator;
 4use Brotkrueml\JobRouterClient\Client\RestClient;
 5use Brotkrueml\JobRouterClient\Configuration\ClientConfiguration;
 6use Brotkrueml\JobRouterClient\Exception\ExceptionInterface;
 8require_once 'vendor/autoload.php';
10$configuration = new ClientConfiguration(
11   '',
12   'the_user',
13   'the_password'
16$restClient = new RestClient($configuration);
17$incidentsClient = new IncidentsClientDecorator($restClient);
18$overallClient = new DocumentsClientDecorator($incidentsClient);
20// Now you can define an Incident and add it to the overallClient

Using a Factory to Create a Client

To simplify the instantiation of the different clients, you can use a factory that creates them for you. The RestClient can be created with:

2use Brotkrueml\JobRouterClient\Client\ClientFactory;
4$client = ClientFactory::createRestClient(
5   '',
6   'the_user',
7   'the_password',
8   30

The decorators can also be instantiated with factory methods. This is useful when client nesting is not required:

 2use Brotkrueml\JobRouterClient\Client\ClientFactory;
 4$incidentsClientDecorator = ClientFactory::createIncidentsClientDecorator(
 5   '',
 6   'the_user',
 7   'the_password',
 8   30
11$documentsClientDecorator = ClientFactory::createDocumentsClientDecorator(
12   '',
13   'the_user',
14   'the_password',
15   30