Completed
Push — master ( e7689e...fff7b7 )
by Tobias
01:56
created

AuthenticationPlugin   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 8
lcom 1
cbo 4
dl 0
loc 77
ccs 0
cts 38
cp 0
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B handleRequest() 0 44 6
A getAccessToken() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FAPI\Sylius\Http;
6
7
use Http\Client\Common\Plugin;
8
use Psr\Http\Message\RequestInterface;
9
use Psr\Http\Message\ResponseInterface;
10
11
/**
12
 * This will automatically refresh expired access token.
13
 *
14
 * @author Tobias Nyholm <[email protected]>
15
 */
16
class AuthenticationPlugin implements Plugin
17
{
18
    const RETRY_LIMIT = 2;
19
20
    /**
21
     * @var array
22
     */
23
    private $accessToken;
24
25
    /**
26
     * @var Authenticator
27
     */
28
    private $authenticator;
29
30
    /**
31
     * Store the retry counter for each request.
32
     *
33
     * @var array
34
     */
35
    private $retryStorage = [];
36
37
    public function __construct(Authenticator $authenticator, string $accessToken)
38
    {
39
        $this->authenticator = $authenticator;
40
        $this->accessToken = \json_decode($accessToken, true);
41
    }
42
43
    public function handleRequest(RequestInterface $request, callable $next, callable $first)
44
    {
45
        if (null === $this->accessToken) {
46
            return $next($request);
47
        }
48
49
        $chainIdentifier = \spl_object_hash((object) $first);
50
        $header = \sprintf('Bearer %s', $this->accessToken['access_token'] ?? '');
51
        $request = $request->withHeader('Authorization', $header);
52
53
        $promise = $next($request);
54
55
        return $promise->then(function (ResponseInterface $response) use ($request, $next, $first, $chainIdentifier) {
56
            if (!\array_key_exists($chainIdentifier, $this->retryStorage)) {
57
                $this->retryStorage[$chainIdentifier] = 0;
58
            }
59
60
            if (401 !== $response->getStatusCode() || $this->retryStorage[$chainIdentifier] >= self::RETRY_LIMIT) {
61
                unset($this->retryStorage[$chainIdentifier]);
62
63
                return $response;
64
            }
65
66
            $accessToken = $this->authenticator->refreshAccessToken($this->accessToken['access_token'], $this->accessToken['refresh_token']);
67
            if (null === $accessToken) {
68
                return $response;
69
            }
70
71
            // Save new token
72
            $this->accessToken = \json_decode($accessToken, true);
73
74
            // Add new token to request
75
            $header = \sprintf('Bearer %s', $this->accessToken['access_token']);
76
            $request = $request->withHeader('Authorization', $header);
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $request, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
77
78
            // Retry
79
            ++$this->retryStorage[$chainIdentifier];
80
            $promise = $this->handleRequest($request, $next, $first);
81
82
            return $promise->wait();
83
        });
84
85
        return $response;
0 ignored issues
show
Unused Code introduced by
return $response; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
86
    }
87
88
    public function getAccessToken(): string
89
    {
90
        return \json_encode($this->accessToken);
91
    }
92
}
93