Skip to content

Commit 7f34d74

Browse files
committed
First commit
0 parents  commit 7f34d74

File tree

13 files changed

+1066
-0
lines changed

13 files changed

+1066
-0
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
charset = utf-8
9+
end_of_line = lf
10+
indent_style = space
11+
indent_size = 4
12+
insert_final_newline = true
13+
trim_trailing_whitespace = true

.gitattributes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/tests/ export-ignore
2+
/.editorconfig export-ignore
3+
/.gitattributes export-ignore
4+
/.gitignore export-ignore
5+
/.php_cs export-ignore

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
.php_cs.cache
3+
.phpunit.result.cache
4+
composer.lock
5+
vendor/

.php_cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
$finder = PhpCsFixer\Finder::create()
4+
->in(__DIR__ . '/src')
5+
->in(__DIR__ . '/tests')
6+
;
7+
8+
return PhpCsFixer\Config::create()
9+
->setRiskyAllowed(true)
10+
->setRules([
11+
'@PSR2' => true,
12+
'@DoctrineAnnotation' => true,
13+
'no_leading_import_slash' => true,
14+
'no_trailing_comma_in_singleline_array' => true,
15+
'no_singleline_whitespace_before_semicolons' => true,
16+
'no_unused_imports' => true,
17+
'concat_space' => ['spacing' => 'one'],
18+
'no_whitespace_in_blank_line' => true,
19+
'ordered_imports' => true,
20+
'single_quote' => true,
21+
'no_empty_statement' => true,
22+
'no_extra_consecutive_blank_lines' => true,
23+
'phpdoc_no_package' => true,
24+
'phpdoc_scalar' => true,
25+
'no_blank_lines_after_phpdoc' => true,
26+
'array_syntax' => ['syntax' => 'short'],
27+
'whitespace_after_comma_in_array' => true,
28+
'function_typehint_space' => true,
29+
'hash_to_slash_comment' => true,
30+
'no_alias_functions' => true,
31+
'lowercase_cast' => true,
32+
'no_leading_namespace_whitespace' => true,
33+
'native_function_casing' => true,
34+
'no_short_bool_cast' => true,
35+
'no_unneeded_control_parentheses' => true,
36+
'phpdoc_no_empty_return' => true,
37+
'phpdoc_trim' => true,
38+
'no_superfluous_elseif' => true,
39+
'no_useless_else' => true,
40+
'phpdoc_types' => true,
41+
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
42+
'return_type_declaration' => ['space_before' => 'none'],
43+
'cast_spaces' => ['space' => 'none'],
44+
'declare_equal_normalize' => ['space' => 'single'],
45+
'dir_constant' => true,
46+
'phpdoc_no_access' => true
47+
])
48+
->setFinder($finder);;

LICENSE.txt

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# JobRouter Client
2+
3+
## Introduction
4+
5+
[JobRouter](https://www.jobrouter.com/) is a scalable digitization platform which links
6+
processes, data and documents. This JobRouter client eases the access to the REST API.
7+
The library supports JobRouter version 4.2 and up, as the token authentication is used.
8+
9+
At the current stage the authentication is done in the background so you concentrate on
10+
the your business domain. Only JSON-related requests and responses are currently supported.
11+
12+
For the requests the [Symfony HTTP Client](https://symfony.com/doc/current/components/http_client.html)
13+
is used where multiple requests can be done simultaneously.
14+
15+
The library can be used to automate tasks in PHP scripts like importing or synchronising
16+
data in the JobData module or working with archive documents.
17+
18+
## Installation
19+
20+
The preferred way to install this library is with composer:
21+
22+
composer req brotkrueml/jobrouter-client
23+
24+
## Usage
25+
26+
Let's start with an example, where you want to retrieve some information out of a JobData
27+
table. Assuming this PHP script is in the root directory of your project:
28+
29+
<?php
30+
31+
use Brotkrueml\JobrouterClient\Client\RestClient;
32+
use Brotkrueml\JobrouterClient\Configuration\ClientConfiguration;
33+
use Symfony\Component\HttpClient\Exception;
34+
35+
require_once 'vendor/autoload.php';
36+
37+
$configuration = new ClientConfiguration(
38+
'https://example.org/jobrouter/',
39+
'technical_user',
40+
'the_password'
41+
);
42+
$configuration->setLifetime(30);
43+
44+
$client = new RestClient($configuration);
45+
46+
$response = $client->request(
47+
'application/jobdata/tables/FB6E9F2F-8486-8CD7-5FA5-640ACB9019E5/datasets',
48+
'GET'
49+
);
50+
51+
try {
52+
echo $response->getStatusCode() . "\n";
53+
var_dump($response->getContent());
54+
} catch (ClientException $e) {
55+
echo $e->getMessage() . "\n";
56+
echo $e->getResponse()->getContent(false) . "\n\n";
57+
}
58+
59+
First, you have to instantiate a configuration class, which holds the base URI of
60+
the JobRouter installation and the credentials for signing-in. Additionally, you can
61+
define a lifetime of the JSON Web Token in seconds. If you don't define the lifetime,
62+
a default value of 600 seconds will be used.
63+
64+
Second, create the REST client, you pass the configuration object for initialisation.
65+
The authentication is done immediately, so you will get an exception if there is
66+
something wrong with the credentials.
67+
68+
After the initialisation part you can now request the needed data or
69+
store some data. You can make as many requests as you want, but keep in
70+
mind: When the lifetime of the token is exceeded you will get an
71+
authentication error. At this time, you have to handle it on your own. If this
72+
happens, you can call at any time the authenticate method of the rest client:
73+
74+
$restClient->authenticate();
75+
76+
You can do this also in advance.

composer.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "brotkrueml/jobrouter-client",
3+
"description": "Rest client for the JobRouter digitisation platform",
4+
"type": "library",
5+
"keywords": [
6+
"jobrouter",
7+
"rest client"
8+
],
9+
"license": "GPL-2.0-or-later",
10+
"authors": [
11+
{
12+
"name": "Chris Müller",
13+
"role": "Developer",
14+
"homepage": "https://github.com/brotkrueml"
15+
}
16+
],
17+
"require": {
18+
"php": "^7.2",
19+
"ext-json": "*",
20+
"symfony/http-client": "^4.3"
21+
},
22+
"require-dev": {
23+
"phpunit/phpunit": "^8.3.4"
24+
},
25+
"suggest": {
26+
"ext-curl": "Improves the performance of the HTTPClient component"
27+
},
28+
"config": {
29+
"sort-packages": true
30+
},
31+
"autoload": {
32+
"psr-4": {
33+
"Brotkrueml\\JobrouterClient\\": "src/"
34+
}
35+
},
36+
"autoload-dev": {
37+
"psr-4": {
38+
"Brotkrueml\\JobrouterClient\\Tests\\": "tests/"
39+
}
40+
}
41+
}

src/Client/RestClient.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace Brotkrueml\JobrouterClient\Client;
5+
6+
use Brotkrueml\JobrouterClient\Configuration\ClientConfiguration;
7+
use Brotkrueml\JobrouterClient\Exception\RestException;
8+
use Symfony\Component\HttpClient\HttpClient;
9+
use Symfony\Component\HttpClient\MockHttpClient;
10+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
11+
use Symfony\Contracts\HttpClient\HttpClientInterface;
12+
use Symfony\Contracts\HttpClient\ResponseInterface;
13+
14+
class RestClient
15+
{
16+
/** @var ClientConfiguration */
17+
protected $configuration;
18+
19+
/** @var HttpClientInterface */
20+
protected $client;
21+
22+
private $jwToken = '';
23+
24+
/**
25+
* @param ClientConfiguration $configuration
26+
* @param MockHttpClient|null $client (only for testing purposes!)
27+
*/
28+
public function __construct(ClientConfiguration $configuration, MockHttpClient $client = null)
29+
{
30+
$this->configuration = $configuration;
31+
32+
if ($client) {
33+
$this->client = $client;
34+
} else {
35+
$this->client = HttpClient::create([
36+
'base_uri' => $this->configuration->getRestApiUri(),
37+
]);
38+
}
39+
40+
$this->authenticate();
41+
}
42+
43+
/**
44+
* Authenticate against the configured JobRouter system
45+
*/
46+
public function authenticate(): void
47+
{
48+
$this->jwToken = null;
49+
50+
$json = [
51+
'username' => $this->configuration->getUsername(),
52+
'password' => $this->configuration->getPassword(),
53+
'lifetime' => $this->configuration->getLifetime(),
54+
];
55+
56+
$response = $this->request('application/tokens', 'POST', ['json' => $json]);
57+
58+
try {
59+
$content = $response->toArray();
60+
} catch (\Throwable $e) {
61+
throw new RestException($e->getMessage(), 1565710927, $e);
62+
}
63+
64+
$this->jwToken = $content['tokens'][0];
65+
}
66+
67+
/**
68+
* Send a request to the configured JobRouter system
69+
*
70+
* @param string $route The route
71+
* @param string $method The method
72+
* @param array $options Additional options for the request (the JobRouter authorization header is added automatically)
73+
* @return ResponseInterface
74+
*
75+
* @see https://github.com/symfony/contracts/blob/master/HttpClient/HttpClientInterface.php Overview of options
76+
*/
77+
public function request(string $route, string $method = 'GET', array $options = []): ResponseInterface
78+
{
79+
$route = \ltrim($route, '/');
80+
81+
if ($this->jwToken) {
82+
$options['headers'][] = 'X-Jobrouter-Authorization: Bearer ' . $this->jwToken;
83+
}
84+
85+
try {
86+
return $this->client->request($method, $route, $options);
87+
} catch (TransportExceptionInterface $e) {
88+
throw new RestException($e->getMessage(), 1565710963, $e);
89+
}
90+
}
91+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace Brotkrueml\JobrouterClient\Configuration;
5+
6+
final class ClientConfiguration
7+
{
8+
public const API_ENDPOINT = 'api/rest/v2/';
9+
public const DEFAULT_TOKEN_LIFETIME_IN_SECONDS = 600;
10+
public const MINIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS = 0;
11+
public const MAXIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS = 3600;
12+
13+
private $restBaseUri;
14+
private $username;
15+
private $password;
16+
private $lifetime = self::DEFAULT_TOKEN_LIFETIME_IN_SECONDS;
17+
18+
public function __construct(string $baseUri, string $username, string $password)
19+
{
20+
$baseUri = \filter_var($baseUri, FILTER_VALIDATE_URL);
21+
22+
if ($baseUri === false) {
23+
throw new \InvalidArgumentException(
24+
sprintf('Given baseUri "%s" is not a valid URL!', $baseUri),
25+
1565710531
26+
);
27+
}
28+
29+
if (empty($username)) {
30+
throw new \InvalidArgumentException('Empty username is not allowed!', 1565710532);
31+
}
32+
33+
if (empty($password)) {
34+
throw new \InvalidArgumentException('Empty password is not allowed!', 1565710533);
35+
}
36+
37+
$this->restBaseUri = \rtrim($baseUri, '/') . '/' . self::API_ENDPOINT;
38+
$this->username = $username;
39+
$this->password = $password;
40+
}
41+
42+
public function getRestApiUri(): string
43+
{
44+
return $this->restBaseUri;
45+
}
46+
47+
public function getUsername(): string
48+
{
49+
return $this->username;
50+
}
51+
52+
public function getPassword(): string
53+
{
54+
return $this->password;
55+
}
56+
57+
public function setLifetime(int $lifetime): void
58+
{
59+
if (
60+
$lifetime < self::MINIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS
61+
|| $lifetime > self::MAXIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS
62+
) {
63+
throw new \InvalidArgumentException(
64+
sprintf(
65+
'Lifetime value "%d" is not allowed! It has to be between "%d" and "%d"',
66+
$lifetime,
67+
self::MINIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS,
68+
self::MAXIMUM_ALLOWED_TOKEN_LIFETIME_IN_SECONDS
69+
),
70+
1565710534
71+
);
72+
}
73+
74+
$this->lifetime = $lifetime;
75+
}
76+
77+
public function getLifetime(): int
78+
{
79+
return $this->lifetime;
80+
}
81+
}

src/Exception/RestException.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Brotkrueml\JobrouterClient\Exception;
4+
5+
class RestException extends \RuntimeException
6+
{
7+
}

0 commit comments

Comments
 (0)