Completed
Push — feature/mysqlSupport ( 574cbc...a33411 )
by Maxime
37:39
created

AccessTokenService::getAccessTokenListKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * AccessTokenService.php
4
 *
5
 * PHP version 5.6+
6
 *
7
 * @author Philippe Gaultier <[email protected]>
8
 * @copyright 2010-2017 Philippe Gaultier
9
 * @license http://www.sweelix.net/license license
10
 * @version 1.2.0
11
 * @link http://www.sweelix.net
12
 * @package sweelix\oauth2\server\services\redis
13
 */
14
15
namespace sweelix\oauth2\server\services\redis;
16
17
use sweelix\oauth2\server\exceptions\DuplicateIndexException;
18
use sweelix\oauth2\server\exceptions\DuplicateKeyException;
19
use sweelix\oauth2\server\interfaces\AccessTokenModelInterface;
20
use sweelix\oauth2\server\interfaces\AccessTokenServiceInterface;
21
use yii\db\Exception as DatabaseException;
22
use Yii;
23
24
/**
25
 * This is the access token service for redis
26
 *  database structure
27
 *    * oauth2:accessTokens:<aid> : hash (AccessToken)
28
 *    * oauth2:users:<uid>:accessTokens : set (AccessToken for user)
29
 *    * oauth2:clients:<cid>:accessTokens : set (AccessToken for client)
30
 *
31
 * @author Philippe Gaultier <[email protected]>
32
 * @copyright 2010-2017 Philippe Gaultier
33
 * @license http://www.sweelix.net/license license
34
 * @version 1.2.0
35
 * @link http://www.sweelix.net
36
 * @package sweelix\oauth2\server\services\redis
37
 * @since 1.0.0
38
 */
39
class AccessTokenService extends BaseService implements AccessTokenServiceInterface
40
{
41
    /**
42
     * @var string user namespace (collection for accesstokens)
43
     */
44
    public $userNamespace = '';
45
46
    /**
47
     * @var string client namespace (collection for accesstokens)
48
     */
49
    public $clientNamespace = '';
50
51
    /**
52
     * @param string $aid access token ID
53
     * @return string access token Key
54
     * @since 1.0.0
55
     */
56
    protected function getAccessTokenKey($aid)
57
    {
58
        return $this->namespace . ':' . $aid;
59
    }
60
61
    /**
62
     * @param string $uid user ID
63
     * @return string user access tokens collection Key
64
     * @since XXX
65
     */
66
    protected function getUserAccessTokensKey($uid)
67
    {
68
        return $this->userNamespace . ':' . $uid . ':accessTokens';
69
    }
70
71
    /**
72
     * @param string $cid client ID
73
     * @return string client access tokens collection Key
74
     * @since XXX
75
     */
76
    protected function getClientAccessTokensKey($cid)
77
    {
78
        return $this->clientNamespace . ':' . $cid . ':accessTokens';
79
    }
80
81
    /**
82
     * @return string key of all access tokens list
83
     */
84
    protected function getAccessTokenListKey()
85
    {
86
        return $this->namespace . ':keys';
87
    }
88
89
    /**
90
     * @return string key of all users list
91
     */
92
    protected function getUserListKey()
93
    {
94
        return $this->userNamespace . ':keys';
95
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100
    public function save(AccessTokenModelInterface $accessToken, $attributes)
101
    {
102
        if ($accessToken->getIsNewRecord()) {
103
            $result = $this->insert($accessToken, $attributes);
104
        } else {
105
            $result = $this->update($accessToken, $attributes);
106
        }
107
        return $result;
108
    }
109
110
    /**
111
     * Save Access Token
112
     * @param AccessTokenModelInterface $accessToken
113
     * @param null|array $attributes attributes to save
114
     * @return bool
115
     * @throws DatabaseException
116
     * @throws DuplicateIndexException
117
     * @throws DuplicateKeyException
118
     * @since 1.0.0
119
     */
120
    protected function insert(AccessTokenModelInterface $accessToken, $attributes)
121
    {
122
        $result = false;
123
        if (!$accessToken->beforeSave(true)) {
124
            return $result;
125
        }
126
        $accessTokenId = $accessToken->getKey();
127
        $accessTokenKey = $this->getAccessTokenKey($accessTokenId);
128
        if (empty($accessToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
129
            $userAccessTokensKey = $this->getUserAccessTokensKey($accessToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
130
        } else {
131
            $userAccessTokensKey = null;
132
        }
133
        $clientAccessTokensKey = $this->getClientAccessTokensKey($accessToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
134
        $accessTokenListKey = $this->getAccessTokenListKey();
135
        $userListKey = $this->getUserListKey();
136
137
        //check if record exists
138
        $entityStatus = (int)$this->db->executeCommand('EXISTS', [$accessTokenKey]);
139
        if ($entityStatus === 1) {
140
            throw new DuplicateKeyException('Duplicate key "' . $accessTokenKey . '"');
141
        }
142
143
        $values = $accessToken->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 120 can also be of type array; however, sweelix\oauth2\server\in...e::getDirtyAttributes() does only seem to accept array<integer,string>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
144
        $redisParameters = [$accessTokenKey];
145
        $this->setAttributesDefinitions($accessToken->attributesDefinition());
146
        $expire = null;
147
        foreach ($values as $key => $value) {
148
            if (($key === 'expiry') && ($value > 0)) {
149
                $expire = $value;
150
            }
151
            if ($value !== null) {
152
                $redisParameters[] = $key;
153
                $redisParameters[] = $this->convertToDatabase($key, $value);
154
            }
155
        }
156
        //TODO: use EXEC/MULTI to avoid errors
157
        $transaction = $this->db->executeCommand('MULTI');
158
        if ($transaction === true) {
159
            try {
160
                $this->db->executeCommand('HMSET', $redisParameters);
161
                if ($expire !== null) {
162
                    $this->db->executeCommand('EXPIREAT', [$accessTokenKey, $expire]);
163
                }
164
                if ($userAccessTokensKey !== null) {
165
                    $this->db->executeCommand('ZADD', [$userAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenId]);
166
                }
167
                $this->db->executeCommand('ZADD', [$clientAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenId]);
168
                $this->db->executeCommand('ZADD', [$accessTokenListKey, $expire === false ? -1 : $expire, $accessTokenId]);
169
                $this->db->executeCommand('SADD', [$userListKey, $accessToken->userId]);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
170
                $this->db->executeCommand('EXEC');
171
            } catch (DatabaseException $e) {
172
                // @codeCoverageIgnoreStart
173
                // we have a REDIS exception, we should not discard
174
                Yii::debug('Error while inserting entity', __METHOD__);
175
                throw $e;
176
                // @codeCoverageIgnoreEnd
177
            }
178
        }
179
        $changedAttributes = array_fill_keys(array_keys($values), null);
180
        $accessToken->setOldAttributes($values);
181
        $accessToken->afterSave(true, $changedAttributes);
182
        $result = true;
183
        return $result;
184
    }
185
186
187
    /**
188
     * Update Access Token
189
     * @param AccessTokenModelInterface $accessToken
190
     * @param null|array $attributes attributes to save
191
     * @return bool
192
     * @throws DatabaseException
193
     * @throws DuplicateIndexException
194
     * @throws DuplicateKeyException
195
     */
196
    protected function update(AccessTokenModelInterface $accessToken, $attributes)
197
    {
198
        if (!$accessToken->beforeSave(false)) {
199
            return false;
200
        }
201
202
        $values = $accessToken->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 196 can also be of type array; however, sweelix\oauth2\server\in...e::getDirtyAttributes() does only seem to accept array<integer,string>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
203
        $modelKey = $accessToken->key();
204
        $accessTokenId = isset($values[$modelKey]) ? $values[$modelKey] : $accessToken->getKey();
205
        $accessTokenKey = $this->getAccessTokenKey($accessTokenId);
206
        $accessTokenListKey = $this->getAccessTokenListKey();
207
        $userListKey = $this->getUserListKey();
208
209
        if (empty($accessToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
210
            $userAccessTokensKey = $this->getUserAccessTokensKey($accessToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
211
        } else {
212
            $userAccessTokensKey = null;
213
        }
214
        $clientAccessTokensKey = $this->getClientAccessTokensKey($accessToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
215
216
        if (isset($values[$modelKey]) === true) {
217
            $newAccessTokenKey = $this->getAccessTokenKey($values[$modelKey]);
218
            $entityStatus = (int)$this->db->executeCommand('EXISTS', [$newAccessTokenKey]);
219
            if ($entityStatus === 1) {
220
                throw new DuplicateKeyException('Duplicate key "' . $newAccessTokenKey . '"');
221
            }
222
        }
223
224
        $this->db->executeCommand('MULTI');
225
        try {
226
            $reAddKeyInList = false;
227
            if (array_key_exists($modelKey, $values) === true) {
228
                $oldId = $accessToken->getOldKey();
229
                $oldAccessTokenKey = $this->getAccessTokenKey($oldId);
230
                $this->db->executeCommand('RENAMENX', [$oldAccessTokenKey, $accessTokenKey]);
231
                if ($userAccessTokensKey !== null) {
232
                    $this->db->executeCommand('ZREM', [$userAccessTokensKey, $oldAccessTokenKey]);
233
                }
234
                $this->db->executeCommand('ZREM', [$clientAccessTokensKey, $oldAccessTokenKey]);
235
                $this->db->executeCommand('ZREM', [$accessTokenListKey, $oldAccessTokenKey]);
236
                $reAddKeyInList = true;
237
            }
238
239
            $redisUpdateParameters = [$accessTokenKey];
240
            $redisDeleteParameters = [$accessTokenKey];
241
            $this->setAttributesDefinitions($accessToken->attributesDefinition());
242
            $expire = $accessToken->expiry;
0 ignored issues
show
Bug introduced by
Accessing expiry on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
243
            foreach ($values as $key => $value) {
244
                if ($value === null) {
245
                    if ($key === 'expiry') {
246
                        $expire = false;
247
                    }
248
                    $redisDeleteParameters[] = $key;
249
                } else {
250
                    if (($key === 'expiry') && ($value > 0)) {
251
                        $expire = $value;
252
                    }
253
                    $redisUpdateParameters[] = $key;
254
                    $redisUpdateParameters[] = $this->convertToDatabase($key, $value);
255
                }
256
            }
257
            if (count($redisDeleteParameters) > 1) {
258
                $this->db->executeCommand('HDEL', $redisDeleteParameters);
259
            }
260
            if (count($redisUpdateParameters) > 1) {
261
                $this->db->executeCommand('HMSET', $redisUpdateParameters);
262
            }
263
            if ($expire === false) {
264
                $this->db->executeCommand('PERSIST', [$accessTokenKey]);
265
            } elseif ($expire > 0) {
266
                $this->db->executeCommand('EXPIREAT', [$accessTokenKey, $expire]);
267
            }
268
269
            if ($reAddKeyInList === true) {
270
                if ($userAccessTokensKey !== null) {
271
                    $this->db->executeCommand('ZADD', [$userAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenKey]);
272
                }
273
                $this->db->executeCommand('ZADD', [$clientAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenKey]);
274
                $this->db->executeCommand('ZADD', [$accessTokenListKey, $expire === false ? -1 : $expire, $accessTokenKey]);
275
            }
276
            $this->db->executeCommand('SADD', [$userListKey, $accessToken->userId]);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
277
278
            $this->db->executeCommand('EXEC');
279
        } catch (DatabaseException $e) {
280
            // @codeCoverageIgnoreStart
281
            // we have a REDIS exception, we should not discard
282
            Yii::debug('Error while updating entity', __METHOD__);
283
            throw $e;
284
            // @codeCoverageIgnoreEnd
285
        }
286
287
        $changedAttributes = [];
288
        foreach ($values as $name => $value) {
289
            $oldAttributes = $accessToken->getOldAttributes();
290
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
291
            $accessToken->setOldAttribute($name, $value);
292
        }
293
        $accessToken->afterSave(false, $changedAttributes);
294
        return true;
295
    }
296
297
    /**
298
     * @inheritdoc
299
     */
300
    public function findOne($key)
301
    {
302
        $record = null;
303
        $accessTokenKey = $this->getAccessTokenKey($key);
304
        $accessTokenExists = (bool)$this->db->executeCommand('EXISTS', [$accessTokenKey]);
305
        if ($accessTokenExists === true) {
306
            $accessTokenData = $this->db->executeCommand('HGETALL', [$accessTokenKey]);
307
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\AccessTokenModelInterface');
308
            /** @var AccessTokenModelInterface $record */
309
            $properties = $record->attributesDefinition();
310
            $this->setAttributesDefinitions($properties);
311
            $attributes = [];
312
            for ($i = 0; $i < count($accessTokenData); $i += 2) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
313
                if (isset($properties[$accessTokenData[$i]]) === true) {
314
                    $accessTokenData[$i + 1] = $this->convertToModel($accessTokenData[$i], $accessTokenData[($i + 1)]);
315
                    $record->setAttribute($accessTokenData[$i], $accessTokenData[$i + 1]);
316
                    $attributes[$accessTokenData[$i]] = $accessTokenData[$i + 1];
317
                    // @codeCoverageIgnoreStart
318
                } elseif ($record->canSetProperty($accessTokenData[$i])) {
319
                    // TODO: find a way to test attribute population
320
                    $record->{$accessTokenData[$i]} = $accessTokenData[$i + 1];
321
                }
322
                // @codeCoverageIgnoreEnd
323
            }
324
            if (empty($attributes) === false) {
325
                $record->setOldAttributes($attributes);
326
            }
327
            $record->afterFind();
328
        }
329
        return $record;
330
    }
331
332
    /**
333
     * @inheritdoc
334
     */
335
    public function findAllByUserId($userId)
336
    {
337
        $userAccessTokensKey = $this->getUserAccessTokensKey($userId);
338
        $userAccessTokens = $this->db->executeCommand('ZRANGE', [$userAccessTokensKey, 0, -1]);
339
        $accessTokens = [];
340
        if ((is_array($userAccessTokens) === true) && (count($userAccessTokens) > 0)) {
341
            foreach ($userAccessTokens as $userAccessTokenId) {
342
                $accessTokens[] = $this->findOne($userAccessTokenId);
343
            }
344
        }
345
        return $accessTokens;
346
    }
347
348
    /**
349
     * @inheritdoc
350
     */
351
    public function deleteAllByUserId($userId)
352
    {
353
        $userAccessTokensKey = $this->getUserAccessTokensKey($userId);
354
        $userAccessTokens = $this->db->executeCommand('ZRANGE', [$userAccessTokensKey, 0, -1]);
355
        foreach ($userAccessTokens as $userAccessTokenId) {
356
            $userAccessToken = $this->findOne($userAccessTokenId);
357
            if ($userAccessToken instanceof AccessTokenModelInterface) {
358
                $this->delete($userAccessToken);
359
            }
360
        }
361
        return true;
362
    }
363
364
    /**
365
     * @inheritdoc
366
     */
367
    public function findAllByClientId($clientId)
368
    {
369
        $clientAccessTokensKey = $this->getClientAccessTokensKey($clientId);
370
        $clientAccessTokens = $this->db->executeCommand('ZRANGE', [$clientAccessTokensKey, 0, -1]);
371
        $accessTokens = [];
372
        if ((is_array($clientAccessTokens) === true) && (count($clientAccessTokens) > 0)) {
373
            foreach ($clientAccessTokens as $clientAccessTokenId) {
374
                $accessTokens[] = $this->findOne($clientAccessTokenId);
375
            }
376
        }
377
        return $accessTokens;
378
    }
379
380
    /**
381
     * @inheritdoc
382
     */
383
    public function deleteAllByClientId($clientId)
384
    {
385
        $clientAccessTokensKey = $this->getClientAccessTokensKey($clientId);
386
        $clientAccessTokens = $this->db->executeCommand('ZRANGE', [$clientAccessTokensKey, 0, -1]);
387
        foreach ($clientAccessTokens as $clientAccessTokenId) {
388
            $clientAccessToken = $this->findOne($clientAccessTokenId);
389
            if ($clientAccessToken instanceof AccessTokenModelInterface) {
390
                $this->delete($clientAccessToken);
391
            }
392
        }
393
        return true;
394
    }
395
396
    /**
397
     * @inheritdoc
398
     */
399
    public function delete(AccessTokenModelInterface $accessToken)
400
    {
401
        $result = false;
402
        if ($accessToken->beforeDelete()) {
403
            if (empty($accessToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
404
                $userAccessTokensKey = $this->getUserAccessTokensKey($accessToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
405
            } else {
406
                $userAccessTokensKey = null;
407
            }
408
            $clientAccessTokensKey = $this->getClientAccessTokensKey($accessToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...cessTokenModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
409
            $accessTokenListKey = $this->getAccessTokenListKey();
410
411
            $this->db->executeCommand('MULTI');
412
            $id = $accessToken->getOldKey();
413
            $accessTokenKey = $this->getAccessTokenKey($id);
414
415
            $this->db->executeCommand('DEL', [$accessTokenKey]);
416
            if ($userAccessTokensKey !== null) {
417
                $this->db->executeCommand('ZREM', [$userAccessTokensKey, $id]);
418
            }
419
            $this->db->executeCommand('ZREM', [$clientAccessTokensKey, $id]);
420
            $this->db->executeCommand('ZREM', [$accessTokenListKey, $id]);
421
            //TODO: check results to return correct information
422
            $this->db->executeCommand('EXEC');
423
            $accessToken->setIsNewRecord(true);
424
            $accessToken->afterDelete();
425
            $result = true;
426
        }
427
        return $result;
428
    }
429
430
    /**
431
     * @inheritdoc
432
     */
433
    public function deleteAllExpired()
434
    {
435
        $date = time();
436
        $accessTokenListKey = $this->getAccessTokenListKey();
437
        $this->db->executeCommand('ZREMRANGEBYSCORE', [$accessTokenListKey, '-inf', $date]);
438
439
        $client = Yii::createObject('sweelix\oauth2\server\interfaces\ClientModelInterface');
440
        $clientClass = get_class($client);
441
        /* @var \sweelix\oauth2\server\interfaces\ClientModelInterface[] $clientList */
442
        $clientList = $clientClass::findAll();
443
        foreach ($clientList as $client) {
444
            $clientAccessTokensKey = $this->getClientAccessTokensKey($client->getKey());
445
            $this->db->executeCommand('ZREMRANGEBYSCORE', [$clientAccessTokensKey, '-inf', $date]);
446
        }
447
448
        $userListKey = $this->getUserListKey();
449
        $users = $this->db->executeCommand('SMEMBERS', [$userListKey]);
450
        foreach ($users as $userId) {
451
            $userAccessTokensKey = $this->getUserAccessTokensKey($userId);
452
            $this->db->executeCommand('ZREMRANGEBYSCORE', [$userAccessTokensKey, '-inf', $date]);
453
        }
454
        return true;
455
    }
456
457
    /**
458
     * @inheritdoc
459
     */
460
    public function findAll()
461
    {
462
        $accessTokenListKey = $this->getAccessTokenListKey();
463
        $accessTokenList = $this->db->executeCommand('ZRANGE', [$accessTokenListKey, 0, -1]);
464
        $accessTokens = [];
465
        if ((is_array($accessTokenList) === true) && (count($accessTokenList) > 0)) {
466
            foreach ($accessTokenList as $accessTokenId) {
467
                $accessTokens[] = $this->findOne($accessTokenId);
468
            }
469
        }
470
        return $accessTokens;
471
    }
472
}
473