RefreshTokenService::getRefreshTokenListKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * RefreshTokenService.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\RefreshTokenModelInterface;
20
use sweelix\oauth2\server\interfaces\RefreshTokenServiceInterface;
21
use yii\db\Exception as DatabaseException;
22
use Yii;
23
24
/**
25
 * This is the refresh token service for redis
26
 *  database structure
27
 *    * oauth2:refreshTokens:<rid> : hash (RefreshToken)
28
 *    * oauth2:users:<uid>:refreshTokens : set (RefreshTokens for user)
29
 *    * oauth2:clients:<cid>:refreshTokens : set (RefreshTokens 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 RefreshTokenService extends BaseService implements RefreshTokenServiceInterface
40
{
41
    /**
42
     * @var string user namespace (collection for refreshtokens)
43
     */
44
    public $userNamespace = '';
45
46
    /**
47
     * @var string client namespace (collection for refreshtokens)
48
     */
49
    public $clientNamespace = '';
50
51
    /**
52
     * @param string $rid refresh token ID
53
     * @return string refresh token Key
54
     * @since 1.0.0
55
     */
56
    public function getRefreshTokenKey($rid)
57 9
    {
58
        return $this->namespace . ':' . $rid;
59 9
    }
60
61
    /**
62
     * @param string $uid user ID
63
     * @return string user refresh tokens collection Key
64
     * @since XXX
65
     */
66
    public function getUserRefreshTokensKey($uid)
67 10
    {
68
        return $this->userNamespace . ':' . $uid . ':refreshTokens';
69 10
    }
70
71
    /**
72
     * @param string $cid client ID
73
     * @return string client refresh tokens collection Key
74
     * @since XXX
75
     */
76
    public function getClientRefreshTokensKey($cid)
77 11
    {
78
        return $this->clientNamespace . ':' . $cid . ':refreshTokens';
79 11
    }
80
81
    /**
82
     * @return string key of all refresh tokens list
83
     */
84
    public function getRefreshTokenListKey()
85 9
    {
86
        return $this->namespace . ':keys';
87 9
    }
88 9
89 9
    /**
90 1
     * @return string key of all users list
91
     */
92 9
    public function getUserListKey()
93
    {
94
        return $this->userNamespace . ':keys';
95
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100
    public function save(RefreshTokenModelInterface $refreshToken, $attributes)
101
    {
102
        if ($refreshToken->getIsNewRecord()) {
103
            $result = $this->insert($refreshToken, $attributes);
104
        } else {
105 9
            $result = $this->update($refreshToken, $attributes);
106
        }
107 9
        return $result;
108 9
    }
109
110
    /**
111 9
     * Save Refresh Token
112 9
     * @param RefreshTokenModelInterface $refreshToken
113 9
     * @param null|array $attributes attributes to save
114 9
     * @return bool
115 9
     * @throws DatabaseException
116
     * @throws DuplicateIndexException
117
     * @throws DuplicateKeyException
118 9
     * @since 1.0.0
119
     */
120
    protected function insert(RefreshTokenModelInterface $refreshToken, $attributes)
121 9
    {
122 9
        $result = false;
123 1
        if (!$refreshToken->beforeSave(true)) {
124
            return $result;
125
        }
126 9
        $refreshTokenId = $refreshToken->getKey();
127 9
        $refreshTokenKey = $this->getRefreshTokenKey($refreshTokenId);
128 9
        if (empty($refreshToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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 9
            $userRefreshTokensKey = $this->getUserRefreshTokensKey($refreshToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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 9
        } else {
131
            $userRefreshTokensKey = null;
132 9
        }
133 9
        $clientRefreshTokensKey = $this->getClientRefreshTokensKey($refreshToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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 9
        $refreshTokenListKey = $this->getRefreshTokenListKey();
135 9
        $userListKey = $this->getUserListKey();
136 9
137 9
        //check if record exists
138 9
        $entityStatus = (int)$this->db->executeCommand('EXISTS', [$refreshTokenKey]);
139 9
        if ($entityStatus === 1) {
140
            throw new DuplicateKeyException('Duplicate key "'.$refreshTokenKey.'"');
141 9
        }
142 9
143
        $values = $refreshToken->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 9
        $redisParameters = [$refreshTokenKey];
145 9
        $this->setAttributesDefinitions($refreshToken->attributesDefinition());
146 9
        $expire = $refreshToken->expiry;
0 ignored issues
show
Bug introduced by
Accessing expiry on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
147 9
        foreach ($values as $key => $value)
148 9
        {
149 9
            if (($key === 'expiry') && ($value > 0)) {
150 9
                $expire = $value;
151 9
            }
152 9
            if ($value !== null) {
153 9
                $redisParameters[] = $key;
154
                $redisParameters[] = $this->convertToDatabase($key, $value);
155
            }
156
        }
157
        //TODO: use EXEC/MULTI to avoid errors
158
        $transaction = $this->db->executeCommand('MULTI');
159
        if ($transaction === true) {
160 9
            try {
161 9
                $this->db->executeCommand('HMSET', $redisParameters);
162 9
                if ($expire !== null) {
163 9
                    $this->db->executeCommand('EXPIREAT', [$refreshTokenKey, $expire]);
164 9
                }
165 9
                if ($userRefreshTokensKey !== null) {
166
                    $this->db->executeCommand('ZADD', [$userRefreshTokensKey, $expire === false ? -1 : $expire, $refreshTokenId]);
167
                }
168
                $this->db->executeCommand('ZADD', [$clientRefreshTokensKey, $expire === false ? -1 : $expire, $refreshTokenId]);
169
                $this->db->executeCommand('ZADD', [$refreshTokenListKey, $expire === false ? -1 : $expire, $refreshTokenId]);
170
                $this->db->executeCommand('SADD', [$userListKey, $refreshToken->userId]);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
171
                $this->db->executeCommand('EXEC');
172
            } catch (DatabaseException $e) {
173
                // @codeCoverageIgnoreStart
174
                // we have a REDIS exception, we should not discard
175
                Yii::debug('Error while inserting entity', __METHOD__);
176
                throw $e;
177
                // @codeCoverageIgnoreEnd
178 1
            }
179
        }
180 1
        $changedAttributes = array_fill_keys(array_keys($values), null);
181
        $refreshToken->setOldAttributes($values);
182
        $refreshToken->afterSave(true, $changedAttributes);
183
        $result = true;
184 1
        return $result;
185 1
    }
186 1
187 1
188
    /**
189 1
     * Update Refresh Token
190 1
     * @param RefreshTokenModelInterface $refreshToken
191 1
     * @param null|array $attributes attributes to save
192
     * @return bool
193
     * @throws DatabaseException
194 1
     * @throws DuplicateIndexException
195
     * @throws DuplicateKeyException
196 1
     */
197 1
    protected function update(RefreshTokenModelInterface $refreshToken, $attributes)
198 1
    {
199 1
        if (!$refreshToken->beforeSave(false)) {
200 1
            return false;
201
        }
202 1
203
        $values = $refreshToken->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 197 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...
204 1
        $modelKey = $refreshToken->key();
205
        $refreshTokenId = isset($values[$modelKey]) ? $values[$modelKey] : $refreshToken->getKey();
206 1
        $refreshTokenKey = $this->getRefreshTokenKey($refreshTokenId);
207 1
        $refreshTokenListKey = $this->getRefreshTokenListKey();
208 1
        $userListKey = $this->getUserListKey();
209
210 1
        if (empty($refreshToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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
            $userRefreshTokensKey = $this->getUserRefreshTokensKey($refreshToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
212 1
        } else {
213 1
            $userRefreshTokensKey = null;
214 1
        }
215 1
        $clientRefreshTokensKey = $this->getClientRefreshTokensKey($refreshToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
216 1
217 1
        if (isset($values[$modelKey]) === true) {
218
            $newRefreshTokenKey = $this->getRefreshTokenKey($values[$modelKey]);
219 1
            $entityStatus = (int)$this->db->executeCommand('EXISTS', [$newRefreshTokenKey]);
220 1
            if ($entityStatus === 1) {
221 1
                throw new DuplicateKeyException('Duplicate key "'.$newRefreshTokenKey.'"');
222 1
            }
223 1
        }
224
225 1
        $this->db->executeCommand('MULTI');
226 1
        try {
227 1
            $reAddKeyInList = false;
228 1
            if (array_key_exists($modelKey, $values) === true) {
229 1
                $oldId = $refreshToken->getOldKey();
230 1
                $oldRefreshTokenKey = $this->getRefreshTokenKey($oldId);
231 1
232
                $this->db->executeCommand('RENAMENX', [$oldRefreshTokenKey, $refreshTokenKey]);
233
                if ($userRefreshTokensKey !== null) {
234 1
                    $this->db->executeCommand('ZREM', [$userRefreshTokensKey, $oldRefreshTokenKey]);
235 1
                }
236
                $this->db->executeCommand('ZREM', [$clientRefreshTokensKey, $oldRefreshTokenKey]);
237 1
                $this->db->executeCommand('ZREM', [$refreshTokenListKey, $oldRefreshTokenKey]);
238 1
                $reAddKeyInList = true;
239 1
            }
240 1
241 1
            $redisUpdateParameters = [$refreshTokenKey];
242 1
            $redisDeleteParameters = [$refreshTokenKey];
243 1
            $this->setAttributesDefinitions($refreshToken->attributesDefinition());
244 1
            $expire = $refreshToken->expiry;
0 ignored issues
show
Bug introduced by
Accessing expiry on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
245 1
            foreach ($values as $key => $value)
246 1
            {
247
                if ($value === null) {
248
                    if ($key === 'expiry') {
249
                        $expire = false;
250 1
                    }
251 1
                    $redisDeleteParameters[] = $key;
252
                } else {
253
                    if (($key === 'expiry') && ($value > 0)) {
254
                        $expire = $value;
255
                    }
256
                    $redisUpdateParameters[] = $key;
257
                    $redisUpdateParameters[] = $this->convertToDatabase($key, $value);
258
                }
259 1
            }
260 1
            if (count($redisDeleteParameters) > 1) {
261 1
                $this->db->executeCommand('HDEL', $redisDeleteParameters);
262 1
            }
263 1
            if (count($redisUpdateParameters) > 1) {
264 1
                $this->db->executeCommand('HMSET', $redisUpdateParameters);
265 1
            }
266 1
            if ($expire === false) {
267
                $this->db->executeCommand('PERSIST', [$refreshTokenKey]);
268
            } elseif ($expire > 0) {
269
                $this->db->executeCommand('EXPIREAT', [$refreshTokenKey, $expire]);
270
            }
271
272 9
            if ($reAddKeyInList === true) {
273
                if ($userRefreshTokensKey !== null) {
274 9
                    $this->db->executeCommand('ZADD', [$userRefreshTokensKey, $expire === false ? -1 : $expire, $refreshTokenKey]);
275 9
                }
276 9
                $this->db->executeCommand('ZADD', [$clientRefreshTokensKey, $expire === false ? -1 : $expire, $refreshTokenKey]);
277 9
                $this->db->executeCommand('ZADD', [$refreshTokenListKey, $expire === false ? -1 : $expire, $refreshTokenKey]);
278 9
            }
279 9
            $this->db->executeCommand('SADD', [$userListKey, $refreshToken->userId]);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
280
281 9
            $this->db->executeCommand('EXEC');
282 9
        } catch (DatabaseException $e) {
283 9
            // @codeCoverageIgnoreStart
284 9
            // we have a REDIS exception, we should not discard
285 9
            Yii::debug('Error while updating entity', __METHOD__);
286 9
            throw $e;
287 9
            // @codeCoverageIgnoreEnd
288 9
        }
289
290
        $changedAttributes = [];
291
        foreach ($values as $name => $value) {
292
            $oldAttributes = $refreshToken->getOldAttributes();
293
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
294
            $refreshToken->setOldAttribute($name, $value);
295 9
        }
296 9
        $refreshToken->afterSave(false, $changedAttributes);
297 9
        return true;
298 9
    }
299 9
300 9
    /**
301 9
     * @inheritdoc
302
     */
303
    public function findOne($key)
304
    {
305
        $record = null;
306
        $refreshTokenKey = $this->getRefreshTokenKey($key);
307 3
        $refreshTokenExists = (bool)$this->db->executeCommand('EXISTS', [$refreshTokenKey]);
308
        if ($refreshTokenExists === true) {
309 3
            $refreshTokenData = $this->db->executeCommand('HGETALL', [$refreshTokenKey]);
310 3
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\RefreshTokenModelInterface');
311 3
            /** @var RefreshTokenModelInterface $record */
312 3
            $properties = $record->attributesDefinition();
313 2
            $this->setAttributesDefinitions($properties);
314 2
            $attributes = [];
315 2
            for ($i = 0; $i < count($refreshTokenData); $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...
316 2
                if (isset($properties[$refreshTokenData[$i]]) === true) {
317 3
                    $refreshTokenData[$i + 1] = $this->convertToModel($refreshTokenData[$i], $refreshTokenData[($i + 1)]);
318
                    $record->setAttribute($refreshTokenData[$i], $refreshTokenData[$i + 1]);
319
                    $attributes[$refreshTokenData[$i]] = $refreshTokenData[$i + 1];
320
                // @codeCoverageIgnoreStart
321
                } elseif ($record->canSetProperty($refreshTokenData[$i])) {
322
                    // TODO: find a way to test attribute population
323 1
                    $record->{$refreshTokenData[$i]} = $refreshTokenData[$i + 1];
324
                }
325 1
                // @codeCoverageIgnoreEnd
326 1
            }
327 1
            if (empty($attributes) === false) {
328 1
                $record->setOldAttributes($attributes);
329 1
            }
330 1
            $record->afterFind();
331 1
        }
332 1
        return $record;
333
    }
334
335
    /**
336
     * @inheritdoc
337
     */
338 3
    public function findAllByUserId($userId)
339
    {
340 3
        $userRefreshTokensKey = $this->getUserRefreshTokensKey($userId);
341 3
        $userRefreshTokens = $this->db->executeCommand('ZRANGE', [$userRefreshTokensKey, 0, -1]);
342 3
        $refreshTokens = [];
343 3
        if ((is_array($userRefreshTokens) === true) && (count($userRefreshTokens) > 0)) {
344 2
            foreach($userRefreshTokens as $userRefreshTokenId) {
345 2
                $refreshTokens[] = $this->findOne($userRefreshTokenId);
346 2
            }
347 2
        }
348 3
        return $refreshTokens;
349
    }
350
351
    /**
352
     * @inheritdoc
353
     */
354 2
    public function deleteAllByUserId($userId)
355
    {
356 2
        $userRefreshTokensKey = $this->getUserRefreshTokensKey($userId);
357 2
        $userRefreshTokens = $this->db->executeCommand('ZRANGE', [$userRefreshTokensKey, 0, -1]);
358 2
        foreach ($userRefreshTokens as $userRefreshTokenId) {
359 2
            $userRefreshToken = $this->findOne($userRefreshTokenId);
360 1
            if ($userRefreshToken instanceof RefreshTokenModelInterface) {
361 2
                $this->delete($userRefreshToken);
362 2
            }
363 2
        }
364
        return true;
365
    }
366
367
    /**
368
     * @inheritdoc
369
     */
370 2
    public function findAllByClientId($clientId)
371
    {
372 2
        $clientRefreshTokensKey = $this->getClientRefreshTokensKey($clientId);
373 2
        $clientRefreshTokens = $this->db->executeCommand('ZRANGE', [$clientRefreshTokensKey, 0, -1]);
374 2
        $refreshTokens = [];
375 2
        if ((is_array($clientRefreshTokens) === true) && (count($clientRefreshTokens) > 0)) {
376 2
            foreach($clientRefreshTokens as $clientRefreshTokenId) {
377
                $refreshTokens[] = $this->findOne($clientRefreshTokenId);
378
            }
379 2
        }
380
        return $refreshTokens;
381 2
    }
382 2
383 2
    /**
384
     * @inheritdoc
385 2
     */
386 2
    public function deleteAllByClientId($clientId)
387 2
    {
388 2
        $clientRefreshTokensKey = $this->getClientRefreshTokensKey($clientId);
389 2
        $clientRefreshTokens = $this->db->executeCommand('ZRANGE', [$clientRefreshTokensKey, 0, -1]);
390
        foreach ($clientRefreshTokens as $clientRefreshTokenId) {
391 2
            $clientRefreshToken = $this->findOne($clientRefreshTokenId);
392 2
            if ($clientRefreshToken instanceof RefreshTokenModelInterface) {
393 2
                $this->delete($clientRefreshToken);
394 2
            }
395 2
        }
396 2
        return true;
397
    }
398
399
400
    /**
401
     * @inheritdoc
402
     */
403
    public function delete(RefreshTokenModelInterface $refreshToken)
404
    {
405
        $result = false;
406
        if ($refreshToken->beforeDelete()) {
407
            if (empty($refreshToken->userId) === false) {
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
408
                $userRefreshTokensKey = $this->getUserRefreshTokensKey($refreshToken->userId);
0 ignored issues
show
Bug introduced by
Accessing userId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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
            } else {
410
                $userRefreshTokensKey = null;
411
            }
412
            $clientRefreshTokensKey = $this->getClientRefreshTokensKey($refreshToken->clientId);
0 ignored issues
show
Bug introduced by
Accessing clientId on the interface sweelix\oauth2\server\in...reshTokenModelInterface 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...
413
            $refreshTokenListKey = $this->getRefreshTokenListKey();
414
415
            $this->db->executeCommand('MULTI');
416
            $id = $refreshToken->getOldKey();
417
            $refreshTokenKey = $this->getRefreshTokenKey($id);
418
419
            $this->db->executeCommand('DEL', [$refreshTokenKey]);
420
            if ($userRefreshTokensKey !== null) {
421
                $this->db->executeCommand('ZREM', [$userRefreshTokensKey, $id]);
422
            }
423
            $this->db->executeCommand('ZREM', [$clientRefreshTokensKey, $id]);
424
            $this->db->executeCommand('ZREM', [$refreshTokenListKey, $id]);
425
            //TODO: check results to return correct information
426
            $queryResult = $this->db->executeCommand('EXEC');
0 ignored issues
show
Unused Code introduced by
$queryResult is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
427
            $refreshToken->setIsNewRecord(true);
428
            $refreshToken->afterDelete();
429
            $result = true;
430
        }
431
        return $result;
432
    }
433
434
    /**
435
     * @inheritdoc
436
     */
437
    public function deleteAllExpired()
438
    {
439
        $date = time();
440
        $refreshTokenListKey = $this->getRefreshTokenListKey();
441
        $this->db->executeCommand('ZREMRANGEBYSCORE', [$refreshTokenListKey, -1, $date]);
442
443
        $client = Yii::createObject('sweelix\oauth2\server\interfaces\ClientModelInterface');
444
        $clientClass = get_class($client);
445
        /* @var \sweelix\oauth2\server\interfaces\ClientModelInterface[] $clientList */
446
        $clientList = $clientClass::findAll();
447
        foreach ($clientList as $client) {
448
            $clientRefreshTokensKey = $this->getClientRefreshTokensKey($client->getKey());
449
            $this->db->executeCommand('ZREMRANGEBYSCORE', [$clientRefreshTokensKey, -1, $date]);
450
        }
451
452
        $userListKey = $this->getUserListKey();
453
        $users = $this->db->executeCommand('SMEMBERS', [$userListKey]);
454
        foreach ($users as $userId) {
455
            $userRefreshTokensKey = $this->getUserRefreshTokensKey($userId);
456
            $this->db->executeCommand('ZREMRANGEBYSCORE', [$userRefreshTokensKey, '-inf', $date]);
457
        }
458
        return true;
459
    }
460
461
    /**
462
     * @inheritdoc
463
     */
464
    public function findAll()
465
    {
466
        $refreshTokenListKey = $this->getRefreshTokenListKey();
467
        $refreshTokenList = $this->db->executeCommand('ZRANGE', [$refreshTokenListKey, 0, -1]);
468
        $refreshTokens = [];
469
        if ((is_array($refreshTokenList) === true) && (count($refreshTokenList) > 0)) {
470
            foreach ($refreshTokenList as $refreshTokenId) {
471
                $refreshTokens[] = $this->findOne($refreshTokenId);
472
            }
473
        }
474
        return $refreshTokens;
475
    }
476
}
477