Manager   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Test Coverage

Coverage 99.13%

Importance

Changes 0
Metric Value
wmc 42
eloc 121
dl 0
loc 265
ccs 114
cts 115
cp 0.9913
rs 9.0399
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getCacheAdapter() 0 3 1
A getBaseUrl() 0 3 1
A cache() 0 12 4
A setCacheAdapter() 0 5 1
A getBearerToken() 0 17 3
A getToken() 0 11 3
A __construct() 0 5 1
A getCacheAdapterFactory() 0 6 2
A getHttpClient() 0 16 5
A getCacheToken() 0 14 4
B getCacheKey() 0 31 7
A execute() 0 7 1
B refreshToken() 0 43 9

How to fix   Complexity   

Complex Class

Complex classes like Manager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Manager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @author @jenschude <[email protected]>
4
 * @created: 22.01.15, 12:34
5
 */
6
7
namespace Commercetools\Core\Client\OAuth;
8
9
use Commercetools\Core\Client\Adapter\CorrelationIdAware;
10
use Commercetools\Core\Config;
11
use Commercetools\Core\Error\ApiException;
12
use Commercetools\Core\Helper\CorrelationIdProvider;
13
use Psr\Cache\CacheItemPoolInterface;
14
use Psr\Http\Message\ResponseInterface;
15
use Commercetools\Core\AbstractHttpClient;
16
use Commercetools\Core\Cache\CacheAdapterFactory;
17
use Commercetools\Core\Error\InvalidClientCredentialsException;
18
use Psr\SimpleCache\CacheInterface;
19
20
/**
21
 * @package Commercetools\Core\OAuth
22
 * @internal
23
 */
24
class Manager extends AbstractHttpClient implements TokenProvider
25
{
26
    const TOKEN_CACHE_KEY = 'commercetools_io_access_token';
27
28
    const ANONYMOUS_ID = 'anonymous_id';
29
    const REFRESH_TOKEN = 'refresh_token';
30
    const ACCESS_TOKEN = 'access_token';
31
    const EXPIRES_IN = 'expires_in';
32
    const ERROR = 'error';
33
    const SCOPE = 'scope';
34
    const ERROR_DESCRIPTION = 'error_description';
35
36
    /**
37
     * @var array
38
     */
39
    protected $cacheKeys;
40
41
    /**
42
     * @var CacheItemPoolInterface|CacheInterface
43
     */
44
    protected $cacheAdapter;
45
46
    /**
47
     * @var CacheAdapterFactory
48
     */
49
    protected $cacheAdapterFactory;
50
51 75
    public function __construct($config, $cache = null)
52
    {
53 75
        parent::__construct($config);
54 75
        $this->cacheKeys = [];
55 75
        $this->setCacheAdapter($cache);
56 75
    }
57
58
    /**
59
     * @return CacheAdapterFactory
60
     */
61 75
    public function getCacheAdapterFactory()
62
    {
63 75
        if (is_null($this->cacheAdapterFactory)) {
64 75
            $this->cacheAdapterFactory = new CacheAdapterFactory($this->getConfig()->getCacheDir());
65
        }
66 75
        return $this->cacheAdapterFactory;
67
    }
68
69
    /**
70
     * @param $cache
71
     * @return $this
72
     */
73 75
    public function setCacheAdapter($cache)
74
    {
75 75
        $this->cacheAdapter = $this->getCacheAdapterFactory()->get($cache);
76
77 75
        return $this;
78
    }
79
80
    /**
81
     * @return CacheItemPoolInterface|CacheInterface
82
     */
83 62
    protected function getCacheAdapter()
84
    {
85 62
        return $this->cacheAdapter;
86
    }
87
88
    /**
89
     * @return Token
90
     * @throws InvalidClientCredentialsException
91
     */
92 62
    public function getToken()
93
    {
94 62
        $scope = $this->getConfig()->getScope();
95 62
        if ($this->getConfig()->getGrantType() == Config::GRANT_TYPE_BEARER_TOKEN) {
96 1
            return new Token($this->getConfig()->getBearerToken(), null, $scope);
97
        }
98 61
        if ($token = $this->getCacheToken()) {
99 50
            return new Token($token, null, $scope);
100
        }
101
102 45
        return $this->refreshToken();
103
    }
104
105
    /**
106
     * @return Token
107
     * @throws InvalidClientCredentialsException
108
     */
109 50
    public function refreshToken()
110
    {
111 50
        $scope = $this->getConfig()->getScope();
112 50
        $grantType = $this->getConfig()->getGrantType();
113 50
        $data = [Config::GRANT_TYPE => $grantType];
114 50
        if (!empty($scope)) {
115 48
            $data[Config::SCOPE] = $scope;
116
        }
117
118 50
        switch ($grantType) {
119
            case Config::GRANT_TYPE_BEARER_TOKEN:
120 1
                return new Token($this->getConfig()->getBearerToken(), null, $scope);
121
            case Config::GRANT_TYPE_PASSWORD:
122 15
                $user = $this->getConfig()->getUsername();
123 15
                $password = $this->getConfig()->getPassword();
124 15
                $data[Config::USER_NAME] = $user;
125 15
                $data[Config::PASSWORD] = $password;
126 15
                break;
127
            case Config::GRANT_TYPE_REFRESH:
128 1
                $refreshToken = $this->getConfig()->getRefreshToken();
129 1
                $data[Config::REFRESH_TOKEN] = $refreshToken;
130 1
                break;
131
            case Config::GRANT_TYPE_ANONYMOUS:
132 7
                $data[Config::GRANT_TYPE] = Config::GRANT_TYPE_CLIENT;
133 7
                $anonymousId = $this->getConfig()->getAnonymousId();
134 7
                if (!empty($anonymousId)) {
135 2
                    $data[Config::ANONYMOUS_ID] = $anonymousId;
136
                }
137
        }
138
139 49
        $token = $this->getBearerToken($data);
140
141
        // ensure token to be invalidated in cache before TTL
142 48
        $ttl = max(1, floor($token->getTtl()/2));
143
144 48
        $this->cache($token, $ttl);
145
146 48
        if ($grantType === Config::GRANT_TYPE_PASSWORD || $grantType == Config::GRANT_TYPE_ANONYMOUS) {
147 20
            $this->getConfig()->setRefreshToken($token->getRefreshToken());
148 20
            $this->cache($token, $ttl, $this->getCacheKey(Config::GRANT_TYPE_REFRESH));
149
        }
150
151 48
        return $token;
152
    }
153
154 48
    protected function cache(Token $token, $ttl, $cacheKey = null)
155
    {
156 48
        if (is_null($cacheKey)) {
157 48
            $cacheKey = $this->getCacheKey();
158
        }
159 48
        $cache = $this->getCacheAdapter();
160 48
        if ($cache instanceof CacheItemPoolInterface) {
161 47
            $item = $cache->getItem($cacheKey)->set($token->getToken())->expiresAfter((int)$ttl);
162 47
            $cache->save($item);
163
        }
164 48
        if ($cache instanceof CacheInterface) {
165 48
            $cache->set($cacheKey, $token->getToken(), (int)$ttl);
166
        }
167 48
    }
168
169 61
    protected function getCacheToken()
170
    {
171 61
        $cache = $this->getCacheAdapter();
172 61
        if ($cache instanceof CacheItemPoolInterface) {
173 59
            $item = $cache->getItem($this->getCacheKey());
174 59
            if ($item->isHit()) {
175 49
                return $item->get();
176
            }
177
        }
178 46
        if ($cache instanceof CacheInterface) {
179 46
            return $cache->get($this->getCacheKey(), false);
180
        }
181
182
        return false;
183
    }
184
185
    /**
186
     * @return string
187
     */
188 62
    protected function getCacheKey($grantType = null)
189
    {
190 62
        $scope = $this->getConfig()->getScope();
191 62
        if (is_null($grantType)) {
192 62
            $grantType = $this->getConfig()->getGrantType();
193
        }
194 62
        $cacheScope = $scope . '-' . $grantType;
195
196 62
        switch ($grantType) {
197
            case Config::GRANT_TYPE_PASSWORD:
198 15
                $user = base64_encode($this->getConfig()->getUsername());
199 15
                $cacheScope .= '-' . $user;
200 15
                break;
201
            case Config::GRANT_TYPE_REFRESH:
202 20
                $token = $this->getConfig()->getRefreshToken();
203 20
                $cacheScope .= '-' . $token;
204 20
                break;
205
            case Config::GRANT_TYPE_ANONYMOUS:
206 6
                $anonymousId = $this->getConfig()->getAnonymousId();
207 6
                if (!empty($anonymousId)) {
208 1
                    $cacheScope .= '-' . $anonymousId;
209
                }
210 6
                break;
211
        }
212
213 62
        if (!isset($this->cacheKeys[$cacheScope])) {
214 33
            $this->cacheKeys[$cacheScope] = static::TOKEN_CACHE_KEY . '_' .
215 33
                sha1($cacheScope);
216
        }
217
218 62
        return $this->cacheKeys[$cacheScope];
219
    }
220
221
    /**
222
     * @param array $data
223
     * @return Token
224
     * @throws ApiException
225
     * @throws \Commercetools\Core\Error\BadGatewayException
226
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
227
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
228
     */
229 49
    protected function getBearerToken(array $data)
230
    {
231
        try {
232 49
            $response = $this->execute($data);
233 3
        } catch (ApiException $exception) {
234 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse());
235
        }
236
237 48
        $result = json_decode($response->getBody(), true);
238
239 48
        $token = new Token($result[static::ACCESS_TOKEN], $result[static::EXPIRES_IN], $result[static::SCOPE]);
240 48
        $token->setValidTo(new \DateTime('now +' . $result[static::EXPIRES_IN] . ' seconds'));
241 48
        if (isset($result[static::REFRESH_TOKEN])) {
242 20
            $token->setRefreshToken($result[static::REFRESH_TOKEN]);
243
        }
244
245 48
        return $token;
246
    }
247
248
    /**
249
     * @inheritDoc
250
     */
251 54
    public function getHttpClient($options = [])
252
    {
253 54
        if (is_null($this->httpClient)) {
254 41
            $clientOptions = $this->config->getOAuthClientOptions();
255 41
            if (count($clientOptions) > 0) {
256 3
                $options = array_merge($clientOptions, $options);
257
            }
258 41
            $client = parent::getHttpClient($options);
259 41
            if ($this->getConfig()->getCorrelationIdProvider() instanceof CorrelationIdProvider
260 41
                && $client instanceof CorrelationIdAware
261
            ) {
262 41
                $client->setCorrelationIdProvider($this->getConfig()->getCorrelationIdProvider());
263
            }
264 41
            $this->httpClient = $client;
265
        }
266 54
        return $this->httpClient;
267
    }
268
269
    /**
270
     * @param $data
271
     * @return ResponseInterface
272
     */
273 50
    public function execute($data)
274
    {
275 50
        return $this->getHttpClient()->authenticate(
276 50
            $this->getConfig()->getOauthUrl(),
277 50
            $this->getConfig()->getClientId(),
278 50
            $this->getConfig()->getClientSecret(),
279
            $data
280
        );
281
    }
282
283
    /**
284
     * @return string
285
     */
286 41
    protected function getBaseUrl()
287
    {
288 41
        return $this->getConfig()->getOauthUrl();
289
    }
290
}
291