Passed
Push — develop ( a89f38...e77623 )
by Jens
19:19
created

Manager::setCacheAdapter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @author @jayS-de <[email protected]>
4
 * @created: 22.01.15, 12:34
5
 */
6
7
namespace Commercetools\Core\Client\OAuth;
8
9
use Cache\Adapter\Common\CacheItem;
10
use Commercetools\Core\Config;
11
use Commercetools\Core\Error\ApiException;
12
use Psr\Cache\CacheItemPoolInterface;
13
use Psr\Http\Message\ResponseInterface;
14
use Commercetools\Core\AbstractHttpClient;
15
use Commercetools\Core\Cache\CacheAdapterFactory;
16
use Commercetools\Core\Cache\CacheAdapterInterface;
17
use Commercetools\Core\Error\InvalidClientCredentialsException;
18
19
/**
20
 * @package Commercetools\Core\OAuth
21
 * @internal
22
 */
23
class Manager extends AbstractHttpClient
24
{
25
    const TOKEN_CACHE_KEY = 'commercetools_io_access_token';
26
27
    const ANONYMOUS_ID = 'anonymous_id';
28
    const REFRESH_TOKEN = 'refresh_token';
29
    const ACCESS_TOKEN = 'access_token';
30
    const EXPIRES_IN = 'expires_in';
31
    const ERROR = 'error';
32
    const SCOPE = 'scope';
33
    const ERROR_DESCRIPTION = 'error_description';
34
35
    /**
36
     * @var array
37
     */
38
    protected $cacheKeys;
39
40
    /**
41
     * @var CacheAdapterInterface|CacheItemPoolInterface
42
     */
43
    protected $cacheAdapter;
44
45
    /**
46
     * @var CacheAdapterFactory
47
     */
48
    protected $cacheAdapterFactory;
49
50 55
    public function __construct($config, $cache = null)
51
    {
52 55
        parent::__construct($config);
53 55
        $this->cacheKeys = [];
54 55
        $this->setCacheAdapter($cache);
55 55
    }
56
57
    /**
58
     * @return CacheAdapterFactory
59
     */
60 55
    public function getCacheAdapterFactory()
61
    {
62 55
        if (is_null($this->cacheAdapterFactory)) {
63 55
            $this->cacheAdapterFactory = new CacheAdapterFactory($this->getConfig()->getCacheDir());
64
        }
65 55
        return $this->cacheAdapterFactory;
66
    }
67
68
    /**
69
     * @param $cache
70
     * @return $this
71
     */
72 55
    public function setCacheAdapter($cache)
73
    {
74 55
        $this->cacheAdapter = $this->getCacheAdapterFactory()->get($cache);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getCacheAdapterFactory()->get($cache) can also be of type object<Commercetools\Cor...\CacheAdapterInterface>. However, the property $cacheAdapter is declared as type object<Psr\Cache\CacheItemPoolInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
75
76 55
        return $this;
77
    }
78
79
    /**
80
     * @internal will become protected in version 2.0
81
     * @return CacheAdapterInterface|CacheItemPoolInterface
82
     */
83 335
    public function getCacheAdapter()
84
    {
85 335
        return $this->cacheAdapter;
86
    }
87
88
    /**
89
     * @return Token
90
     * @throws InvalidClientCredentialsException
91
     */
92 333
    public function getToken()
93
    {
94 333
        $scope = $this->getConfig()->getScope();
95 333
        if ($token = $this->getCacheToken()) {
96 332
            return new Token($token, null, $scope);
97
        }
98
99 20
        return $this->refreshToken();
100
    }
101
102
    /**
103
     * @return Token
104
     * @throws InvalidClientCredentialsException
105
     */
106 27
    public function refreshToken()
107
    {
108 27
        $scope = $this->getConfig()->getScope();
109 27
        $grantType = $this->getConfig()->getGrantType();
110 27
        $data = [Config::SCOPE => $scope, Config::GRANT_TYPE => $grantType];
111
112
        switch ($grantType) {
113 27
            case Config::GRANT_TYPE_PASSWORD:
114 11
                $user = $this->getConfig()->getUsername();
115 11
                $password = $this->getConfig()->getPassword();
116 11
                $data[Config::USER_NAME] = $user;
117 11
                $data[Config::PASSWORD] = $password;
118 11
                break;
119 24
            case Config::GRANT_TYPE_REFRESH:
120 2
                $refreshToken = $this->getConfig()->getRefreshToken();
121 2
                $data[Config::REFRESH_TOKEN] = $refreshToken;
122 2
                break;
123 23
            case Config::GRANT_TYPE_ANONYMOUS:
124 8
                $data[Config::GRANT_TYPE] = Config::GRANT_TYPE_CLIENT;
125 8
                $anonymousId = $this->getConfig()->getAnonymousId();
126 8
                if (!empty($anonymousId)) {
127 4
                    $data[Config::ANONYMOUS_ID] = $anonymousId;
128
                }
129
        }
130
131 27
        $token = $this->getBearerToken($data);
132
133
        // ensure token to be invalidated in cache before TTL
134 26
        $ttl = max(1, floor($token->getTtl()/2));
135
136 26
        $this->cache($token, $ttl);
137
138 26
        if ($grantType === Config::GRANT_TYPE_PASSWORD || $grantType == Config::GRANT_TYPE_ANONYMOUS) {
139 18
            $this->getConfig()->setGrantType(Config::GRANT_TYPE_REFRESH);
140 18
            $this->getConfig()->setRefreshToken($token->getRefreshToken());
141 18
            $this->cache($token, $ttl);
142
        }
143
144 26
        return $token;
145
    }
146
147 26
    protected function cache(Token $token, $ttl)
148
    {
149 26
        $cache = $this->getCacheAdapter();
150 26
        if ($cache instanceof CacheAdapterInterface) {
151 5
            $cache->store($this->getCacheKey(), $token->getToken(), (int)$ttl);
152
        }
153 26
        if ($cache instanceof CacheItemPoolInterface) {
154 21
            $item = new CacheItem($this->getCacheKey(), true, $token->getToken());
155 21
            $item->expiresAfter((int)$ttl);
156 21
            $cache->save($item);
157
        }
158 26
    }
159
160 333
    protected function getCacheToken()
161
    {
162 333
        $cache = $this->getCacheAdapter();
163 333
        if ($cache instanceof CacheAdapterInterface) {
164 6
            return $cache->fetch($this->getCacheKey());
165
        }
166 328
        if ($cache instanceof CacheItemPoolInterface) {
167 328
            $item = $cache->getItem($this->getCacheKey());
168 328
            if ($item->isHit()) {
169 328
                return $item->get();
170
            }
171
        }
172
173 15
        return false;
174
    }
175
176
    /**
177
     * @return string
178
     */
179 333
    protected function getCacheKey()
180
    {
181 333
        $scope = $this->getConfig()->getScope();
182 333
        $grantType = $this->getConfig()->getGrantType();
183 333
        $cacheScope = $scope . '-' . $grantType;
184
185
        switch ($grantType) {
186 333
            case Config::GRANT_TYPE_PASSWORD:
187 11
                $user = base64_encode($this->getConfig()->getUsername());
188 11
                $cacheScope .= '-' . $user;
189 11
                break;
190 333
            case Config::GRANT_TYPE_REFRESH:
191 18
                $token = $this->getConfig()->getRefreshToken();
192 18
                $cacheScope .= '-' . $token;
193 18
                break;
194 333
            case Config::GRANT_TYPE_ANONYMOUS:
195 7
                $anonymousId = $this->getConfig()->getAnonymousId();
196 7
                if (!empty($anonymousId)) {
197 3
                    $cacheScope .= '-' . $anonymousId;
198
                }
199 7
                break;
200
        }
201
202 333
        if (!isset($this->cacheKeys[$cacheScope])) {
203 25
            $this->cacheKeys[$cacheScope] = static::TOKEN_CACHE_KEY . '_' .
204 25
                sha1($cacheScope);
205
        }
206
207 333
        return $this->cacheKeys[$cacheScope];
208
    }
209
210
    /**
211
     * @param array $data
212
     * @return Token
213
     * @throws ApiException
214
     * @throws \Commercetools\Core\Error\BadGatewayException
215
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
216
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
217
     */
218 27
    protected function getBearerToken(array $data)
219
    {
220
        try {
221 27
            $response = $this->execute($data);
222 2
        } catch (ApiException $exception) {
223 2
            throw ApiException::create($exception->getRequest(), $exception->getResponse());
224
        }
225
226 26
        $result = json_decode($response->getBody(), true);
227
228 26
        $token = new Token($result[static::ACCESS_TOKEN], $result[static::EXPIRES_IN], $result[static::SCOPE]);
229 26
        $token->setValidTo(new \DateTime('now +' . $result[static::EXPIRES_IN] . ' seconds'));
230 26
        if (isset($result[static::REFRESH_TOKEN])) {
231 18
            $token->setRefreshToken($result[static::REFRESH_TOKEN]);
232
        }
233
234 26
        return $token;
235
    }
236
237
    /**
238
     * @param $data
239
     * @return ResponseInterface
240
     */
241 27
    public function execute($data)
242
    {
243 27
        return $this->getHttpClient()->authenticate(
244 27
            $this->getConfig()->getOauthUrl(),
245 27
            $this->getConfig()->getClientId(),
246 27
            $this->getConfig()->getClientSecret(),
247
            $data
248
        );
249
    }
250
251
    /**
252
     * @return string
253
     */
254 27
    protected function getBaseUrl()
255
    {
256 27
        return $this->getConfig()->getOauthUrl();
257
    }
258
}
259