Completed
Pull Request — master (#48)
by
unknown
04:02
created

TokenManager::getToken()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 53
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 53
rs 6.3525
cc 12
eloc 32
nc 12
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace MovingImage\Client\VMPro\Manager;
4
5
use Cache\Adapter\Void\VoidCachePool;
6
use GuzzleHttp\ClientInterface;
7
use MovingImage\Client\VMPro\Entity\ApiCredentials;
8
use MovingImage\Client\VMPro\Entity\Token;
9
use MovingImage\Client\VMPro\Extractor\TokenExtractor;
10
use MovingImage\Client\VMPro\Util\Logging\Traits\LoggerAwareTrait;
11
use Psr\Cache\CacheItemPoolInterface;
12
use Psr\Log\LoggerAwareInterface;
13
14
/**
15
 * Class TokenManager.
16
 *
17
 * @author Ruben Knol <[email protected]>
18
 */
19
class TokenManager implements LoggerAwareInterface
20
{
21
    use LoggerAwareTrait;
22
23
    /**
24
     * @var ClientInterface
25
     */
26
    private $httpClient;
27
28
    /**
29
     * @var ApiCredentials
30
     */
31
    protected $credentials;
32
33
    /**
34
     * @var TokenExtractor
35
     */
36
    private $tokenExtractor;
37
38
    /**
39
     * @var Token
40
     */
41
    private $accessToken;
42
43
    /**
44
     * @var Token
45
     */
46
    private $refreshToken;
47
48
    /**
49
     * If provided in the constructor, will be used to cache the access token.
50
     *
51
     * @var CacheItemPoolInterface
52
     */
53
    private $cacheItemPool;
54
55
    /**
56
     * TokenManager constructor.
57
     *
58
     * @param ClientInterface        $httpClient
59
     * @param ApiCredentials         $credentials
60
     * @param TokenExtractor         $tokenExtractor
61
     * @param CacheItemPoolInterface $cacheItemPool
62
     */
63
    public function __construct(
64
        ClientInterface $httpClient,
65
        ApiCredentials $credentials,
66
        TokenExtractor $tokenExtractor,
67
        CacheItemPoolInterface $cacheItemPool = null
68
    ) {
69
        $this->httpClient = $httpClient;
70
        $this->credentials = $credentials;
71
        $this->tokenExtractor = $tokenExtractor;
72
        $this->cacheItemPool = $cacheItemPool ?: new VoidCachePool();
73
    }
74
75
    /**
76
     * Create completely fresh Access + Refresh tokens.
77
     *
78
     * @TODO Implement proper error handling
79
     *
80
     * @return array
81
     */
82
    protected function createNewTokens()
83
    {
84
        $logger = $this->getLogger();
85
        $logger->debug('Starting request to create fresh access & refresh tokens');
86
87
        $response = $this->httpClient->post('auth/login', [
88
            'json' => [
89
                'username' => $this->credentials->getUsername(),
90
                'password' => $this->credentials->getPassword(),
91
            ],
92
            'headers' => [
93
                'accept: application/json',
94
                'cache-control: no-cache',
95
                'content-type: application/json',
96
            ],
97
        ]);
98
99
        $data = \json_decode($response->getBody(), true);
100
        $logger->debug('Successfully retrieved new access & refresh tokens', $data);
101
102
        return [
103
            'accessToken' => new Token(
104
                $data['accessToken'],
105
                $this->tokenExtractor->extract($data['accessToken']),
106
                $data['validForVideoManager']
107
            ),
108
            'refreshToken' => new Token(
109
                $data['refreshToken'],
110
                $this->tokenExtractor->extract($data['refreshToken']),
111
                null
112
            ),
113
        ];
114
    }
115
116
    /**
117
     * Create a new access token for a video manager using a refresh token.
118
     *
119
     * @param Token $refreshToken
120
     * @param int   $videoManagerId
121
     *
122
     * @return Token
123
     */
124
    protected function createAccessTokenFromRefreshToken(Token $refreshToken, $videoManagerId)
125
    {
126
        $logger = $this->getLogger();
127
        $logger->debug('Starting request to create fresh access token from refresh token');
128
129
        $response = $this->httpClient->post(sprintf('auth/refresh/%d', $videoManagerId), [
130
            'json' => [
131
                'refreshToken' => $refreshToken->getTokenString(),
132
            ],
133
            'headers' => [
134
                'accept: application/json',
135
                'cache-control: no-cache',
136
                'content-type: application/json',
137
            ],
138
        ]);
139
140
        $data = \json_decode($response->getBody(), true);
141
        $logger->debug('Successfully retrieved new access token', $data);
142
143
        return new Token(
144
            $data['accessToken'],
145
            $this->tokenExtractor->extract($data['accessToken']),
146
            $videoManagerId
147
        );
148
    }
149
150
    /**
151
     * Log information about which tokens we have.
152
     */
153
    protected function logTokenData()
154
    {
155
        $this->getLogger()->debug('Token information', [
156
            'accessTokenExists' => isset($this->accessToken),
157
            'accessTokenExpiration' => isset($this->accessToken) ? $this->accessToken->getTokenData()['exp'] : null,
158
            'accessTokenHasExpired' => isset($this->accessToken) ? $this->accessToken->expired() : null,
159
            'refreshTokenExists' => isset($this->refreshToken),
160
            'refreshTokenExpiration' => isset($this->refreshToken) ? $this->refreshToken->getTokenData()['exp'] : null,
161
            'refreshTokenHasExpired' => isset($this->refreshToken) ? $this->refreshToken->expired() : null,
162
            'localTime' => time(),
163
        ]);
164
    }
165
166
    /**
167
     * Retrieve a valid token.
168
     *
169
     * @param int $videoManagerId Which video manager a token is requested for
170
     * @TODO Refactor token storage to support multiple re-usable tokens, one per video manager
171
     *
172
     * @return string
173
     */
174
    public function getToken($videoManagerId = null)
175
    {
176
        $logger = $this->getLogger();
177
        $this->logTokenData();
178
179
        $cacheKey = sha1(sprintf('%s.%s', __METHOD__, json_encode(func_get_args())));
180
        $cacheItem = $this->cacheItemPool->getItem($cacheKey);
181
        if (!$this->accessToken && $cacheItem->isHit()) {
182
            $this->accessToken = $cacheItem->get();
183
        }
184
185
        // Access token has expired, but expiration token has not expired.
186
        // Issue ourselves a new access token for the same video manager.
187
        if (!is_null($this->accessToken)
188
            && $this->accessToken->expired()
189
            && !$this->refreshToken->expired()) {
190
            $logger->info('Access token has expired - getting new one for same video manager with refresh token');
191
            $tokenData = $this->createAccessTokenFromRefreshToken(
192
                $this->refreshToken,
193
                $this->accessToken->getVideoManagerId()
194
            );
195
196
            $this->accessToken = $tokenData['accessToken'];
197
        } elseif (is_null($this->accessToken)
198
            || (!is_null($this->refreshToken) && $this->refreshToken->expired())) {
199
            // Either we have no token, or the refresh token has expired
200
            // so we will need to generate completely new tokens
201
            $logger->info('No access token, or refresh token has expired - generate completely new ones');
202
            $tokenData = $this->createNewTokens();
203
204
            $this->accessToken = $tokenData['accessToken'];
205
            $this->refreshToken = $tokenData['refreshToken'];
206
        }
207
208
        // Video manager is not matching with the one that our token
209
        // was generated with - issue ourselves a token for the video manager
210
        // we need.
211
        if (!is_null($videoManagerId)
212
            && isset($this->accessToken)
213
            && $this->accessToken->getVideoManagerId() != $videoManagerId) {
214
            $logger->info('Attempting to use token for different video manager - generate valid access token');
215
            $this->accessToken = $this->createAccessTokenFromRefreshToken($this->refreshToken, $videoManagerId);
216
        }
217
218
        $cacheItem->set($this->accessToken);
219
        $cacheItem->expiresAt((new \DateTime())
220
            ->setTimestamp($this->accessToken->getTokenData()['exp'])
221
            ->sub(new \DateInterval('PT30S'))
222
        );
223
        $this->cacheItemPool->save($cacheItem);
224
225
        return $this->accessToken->getTokenString();
226
    }
227
}
228