AccessTokenService   F
last analyzed

Complexity

Total Complexity 78

Size/Duplication

Total Lines 434
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 95.65%

Importance

Changes 0
Metric Value
wmc 78
lcom 1
cbo 6
dl 0
loc 434
ccs 198
cts 207
cp 0.9565
rs 2.16
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getAccessTokenKey() 0 4 1
A getUserAccessTokensKey() 0 4 1
A getClientAccessTokensKey() 0 4 1
A getAccessTokenListKey() 0 4 1
A getUserListKey() 0 4 1
A save() 0 9 2
D insert() 0 65 15
F update() 0 100 25
B findOne() 0 31 6
A findAllByUserId() 0 12 4
A deleteAllByUserId() 0 12 3
A findAllByClientId() 0 12 4
A deleteAllByClientId() 0 12 3
A delete() 0 30 4
A deleteAllExpired() 0 23 3
A findAll() 0 12 4

How to fix   Complexity   

Complex Class

Complex classes like AccessTokenService 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 AccessTokenService, and based on these observations, apply Extract Interface, too.

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 11
    public function getAccessTokenKey($aid)
57
    {
58 11
        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 12
    public function getUserAccessTokensKey($uid)
67
    {
68 12
        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 13
    public function getClientAccessTokensKey($cid)
77
    {
78 13
        return $this->clientNamespace . ':' . $cid . ':accessTokens';
79
    }
80
81
    /**
82
     * @return string key of all access tokens list
83
     */
84 11
    public function getAccessTokenListKey()
85
    {
86 11
        return $this->namespace . ':keys';
87 11
    }
88 11
89 1
    /**
90
     * @return string key of all users list
91 11
     */
92
    public 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 11
        } else {
105
            $result = $this->update($accessToken, $attributes);
106 11
        }
107 11
        return $result;
108
    }
109
110 11
    /**
111 11
     * Save Access Token
112 11
     * @param AccessTokenModelInterface $accessToken
113 11
     * @param null|array $attributes attributes to save
114 11
     * @return bool
115
     * @throws DatabaseException
116
     * @throws DuplicateIndexException
117 11
     * @throws DuplicateKeyException
118
     * @since 1.0.0
119
     */
120 11
    protected function insert(AccessTokenModelInterface $accessToken, $attributes)
121 11
    {
122 1
        $result = false;
123
        if (!$accessToken->beforeSave(true)) {
124
            return $result;
125 11
        }
126 11
        $accessTokenId = $accessToken->getKey();
127 11
        $accessTokenKey = $this->getAccessTokenKey($accessTokenId);
128 11
        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 11
            $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 11
            $userAccessTokensKey = null;
132 11
        }
133 11
        $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 11
        $accessTokenListKey = $this->getAccessTokenListKey();
135 11
        $userListKey = $this->getUserListKey();
136 11
137 11
        //check if record exists
138 11
        $entityStatus = (int)$this->db->executeCommand('EXISTS', [$accessTokenKey]);
139
        if ($entityStatus === 1) {
140 11
            throw new DuplicateKeyException('Duplicate key "' . $accessTokenKey . '"');
141 11
        }
142
143 11
        $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 11
        $redisParameters = [$accessTokenKey];
145 11
        $this->setAttributesDefinitions($accessToken->attributesDefinition());
146 11
        $expire = null;
147 11
        foreach ($values as $key => $value) {
148 11
            if (($key === 'expiry') && ($value > 0)) {
149 11
                $expire = $value;
150 11
            }
151 11
            if ($value !== null) {
152 11
                $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 11
            try {
160 11
                $this->db->executeCommand('HMSET', $redisParameters);
161 11
                if ($expire !== null) {
162 11
                    $this->db->executeCommand('EXPIREAT', [$accessTokenKey, $expire]);
163 11
                }
164 11
                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 1
            }
178
        }
179 1
        $changedAttributes = array_fill_keys(array_keys($values), null);
180
        $accessToken->setOldAttributes($values);
181
        $accessToken->afterSave(true, $changedAttributes);
182
        $result = true;
183 1
        return $result;
184 1
    }
185 1
186 1
187
    /**
188 1
     * Update Access Token
189 1
     * @param AccessTokenModelInterface $accessToken
190 1
     * @param null|array $attributes attributes to save
191
     * @return bool
192
     * @throws DatabaseException
193 1
     * @throws DuplicateIndexException
194
     * @throws DuplicateKeyException
195 1
     */
196 1
    protected function update(AccessTokenModelInterface $accessToken, $attributes)
197 1
    {
198 1
        if (!$accessToken->beforeSave(false)) {
199 1
            return false;
200
        }
201 1
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 1
        $modelKey = $accessToken->key();
204
        $accessTokenId = isset($values[$modelKey]) ? $values[$modelKey] : $accessToken->getKey();
205 1
        $accessTokenKey = $this->getAccessTokenKey($accessTokenId);
206 1
        $accessTokenListKey = $this->getAccessTokenListKey();
207 1
        $userListKey = $this->getUserListKey();
208 1
209 1
        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 1
            $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 1
        } else {
212 1
            $userAccessTokensKey = null;
213 1
        }
214 1
        $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 1
216
        if (isset($values[$modelKey]) === true) {
217 1
            $newAccessTokenKey = $this->getAccessTokenKey($values[$modelKey]);
218 1
            $entityStatus = (int)$this->db->executeCommand('EXISTS', [$newAccessTokenKey]);
219 1
            if ($entityStatus === 1) {
220 1
                throw new DuplicateKeyException('Duplicate key "' . $newAccessTokenKey . '"');
221 1
            }
222
        }
223 1
224 1
        $this->db->executeCommand('MULTI');
225 1
        try {
226 1
            $reAddKeyInList = false;
227 1
            if (array_key_exists($modelKey, $values) === true) {
228 1
                $oldId = $accessToken->getOldKey();
229 1
                $oldAccessTokenKey = $this->getAccessTokenKey($oldId);
230
                $this->db->executeCommand('RENAMENX', [$oldAccessTokenKey, $accessTokenKey]);
231
                if ($userAccessTokensKey !== null) {
232 1
                    $this->db->executeCommand('ZREM', [$userAccessTokensKey, $oldAccessTokenKey]);
233 1
                }
234
                $this->db->executeCommand('ZREM', [$clientAccessTokensKey, $oldAccessTokenKey]);
235 1
                $this->db->executeCommand('ZREM', [$accessTokenListKey, $oldAccessTokenKey]);
236 1
                $reAddKeyInList = true;
237 1
            }
238 1
239 1
            $redisUpdateParameters = [$accessTokenKey];
240 1
            $redisDeleteParameters = [$accessTokenKey];
241 1
            $this->setAttributesDefinitions($accessToken->attributesDefinition());
242 1
            $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 1
            foreach ($values as $key => $value) {
244 1
                if ($value === null) {
245
                    if ($key === 'expiry') {
246
                        $expire = false;
247
                    }
248 1
                    $redisDeleteParameters[] = $key;
249 1
                } else {
250
                    if (($key === 'expiry') && ($value > 0)) {
251
                        $expire = $value;
252
                    }
253
                    $redisUpdateParameters[] = $key;
254
                    $redisUpdateParameters[] = $this->convertToDatabase($key, $value);
255
                }
256
            }
257 1
            if (count($redisDeleteParameters) > 1) {
258 1
                $this->db->executeCommand('HDEL', $redisDeleteParameters);
259 1
            }
260 1
            if (count($redisUpdateParameters) > 1) {
261 1
                $this->db->executeCommand('HMSET', $redisUpdateParameters);
262 1
            }
263 1
            if ($expire === false) {
264 1
                $this->db->executeCommand('PERSIST', [$accessTokenKey]);
265
            } elseif ($expire > 0) {
266
                $this->db->executeCommand('EXPIREAT', [$accessTokenKey, $expire]);
267
            }
268
269
            if ($reAddKeyInList === true) {
270 11
                if ($userAccessTokensKey !== null) {
271
                    $this->db->executeCommand('ZADD', [$userAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenKey]);
272 11
                }
273 11
                $this->db->executeCommand('ZADD', [$clientAccessTokensKey, $expire === false ? -1 : $expire, $accessTokenKey]);
274 11
                $this->db->executeCommand('ZADD', [$accessTokenListKey, $expire === false ? -1 : $expire, $accessTokenKey]);
275 11
            }
276 11
            $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 11
278
            $this->db->executeCommand('EXEC');
279 11
        } catch (DatabaseException $e) {
280 11
            // @codeCoverageIgnoreStart
281 11
            // we have a REDIS exception, we should not discard
282 11
            Yii::debug('Error while updating entity', __METHOD__);
283 11
            throw $e;
284 11
            // @codeCoverageIgnoreEnd
285 11
        }
286 11
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 11
        $accessToken->afterSave(false, $changedAttributes);
294 11
        return true;
295 11
    }
296 11
297 11
    /**
298 11
     * @inheritdoc
299 11
     */
300
    public function findOne($key)
301
    {
302
        $record = null;
303
        $accessTokenKey = $this->getAccessTokenKey($key);
304
        $accessTokenExists = (bool)$this->db->executeCommand('EXISTS', [$accessTokenKey]);
305 3
        if ($accessTokenExists === true) {
306
            $accessTokenData = $this->db->executeCommand('HGETALL', [$accessTokenKey]);
307 3
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\AccessTokenModelInterface');
308 3
            /** @var AccessTokenModelInterface $record */
309 3
            $properties = $record->attributesDefinition();
310 3
            $this->setAttributesDefinitions($properties);
311 2
            $attributes = [];
312 2
            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 2
                if (isset($properties[$accessTokenData[$i]]) === true) {
314 2
                    $accessTokenData[$i + 1] = $this->convertToModel($accessTokenData[$i], $accessTokenData[($i + 1)]);
315 3
                    $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 1
                }
322
                // @codeCoverageIgnoreEnd
323 1
            }
324 1
            if (empty($attributes) === false) {
325 1
                $record->setOldAttributes($attributes);
326 1
            }
327 1
            $record->afterFind();
328 1
        }
329 1
        return $record;
330 1
    }
331
332
    /**
333
     * @inheritdoc
334
     */
335
    public function findAllByUserId($userId)
336 3
    {
337
        $userAccessTokensKey = $this->getUserAccessTokensKey($userId);
338 3
        $userAccessTokens = $this->db->executeCommand('ZRANGE', [$userAccessTokensKey, 0, -1]);
339 3
        $accessTokens = [];
340 3
        if ((is_array($userAccessTokens) === true) && (count($userAccessTokens) > 0)) {
341 3
            foreach ($userAccessTokens as $userAccessTokenId) {
342 2
                $accessTokens[] = $this->findOne($userAccessTokenId);
343 2
            }
344 2
        }
345 2
        return $accessTokens;
346 3
    }
347
348
    /**
349
     * @inheritdoc
350
     */
351
    public function deleteAllByUserId($userId)
352 2
    {
353
        $userAccessTokensKey = $this->getUserAccessTokensKey($userId);
354 2
        $userAccessTokens = $this->db->executeCommand('ZRANGE', [$userAccessTokensKey, 0, -1]);
355 2
        foreach ($userAccessTokens as $userAccessTokenId) {
356 2
            $userAccessToken = $this->findOne($userAccessTokenId);
357 2
            if ($userAccessToken instanceof AccessTokenModelInterface) {
358 1
                $this->delete($userAccessToken);
359 2
            }
360 2
        }
361 2
        return true;
362
    }
363
364
    /**
365
     * @inheritdoc
366
     */
367 2
    public function findAllByClientId($clientId)
368
    {
369 2
        $clientAccessTokensKey = $this->getClientAccessTokensKey($clientId);
370 2
        $clientAccessTokens = $this->db->executeCommand('ZRANGE', [$clientAccessTokensKey, 0, -1]);
371 2
        $accessTokens = [];
372 2
        if ((is_array($clientAccessTokens) === true) && (count($clientAccessTokens) > 0)) {
373 2
            foreach ($clientAccessTokens as $clientAccessTokenId) {
374
                $accessTokens[] = $this->findOne($clientAccessTokenId);
375
            }
376 2
        }
377
        return $accessTokens;
378 2
    }
379 2
380 2
    /**
381
     * @inheritdoc
382 2
     */
383 2
    public function deleteAllByClientId($clientId)
384 2
    {
385 2
        $clientAccessTokensKey = $this->getClientAccessTokensKey($clientId);
386 2
        $clientAccessTokens = $this->db->executeCommand('ZRANGE', [$clientAccessTokensKey, 0, -1]);
387
        foreach ($clientAccessTokens as $clientAccessTokenId) {
388 2
            $clientAccessToken = $this->findOne($clientAccessTokenId);
389 2
            if ($clientAccessToken instanceof AccessTokenModelInterface) {
390 2
                $this->delete($clientAccessToken);
391 2
            }
392 2
        }
393 2
        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