Completed
Pull Request — devel (#18)
by
unknown
38:28
created

RefreshTokenService::delete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
rs 9.7998
cc 2
nc 2
nop 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\mySql
13
 */
14
15
namespace sweelix\oauth2\server\services\mySql;
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
use yii\db\Expression;
24
use yii\db\Query;
25
26
/**
27
 * This is the refresh token service for mySql
28
 *  database structure
29
 *    * oauth2:refreshTokens:<rid> : hash (RefreshToken)
30
 *    * oauth2:users:<uid>:refreshTokens : set (RefreshTokens for user)
31
 *    * oauth2:clients:<cid>:refreshTokens : set (RefreshTokens for client)
32
 *
33
 * @author Philippe Gaultier <[email protected]>
34
 * @copyright 2010-2017 Philippe Gaultier
35
 * @license http://www.sweelix.net/license license
36
 * @version 1.2.0
37
 * @link http://www.sweelix.net
38
 * @package sweelix\oauth2\server\services\mySql
39
 * @since 1.0.0
40
 */
41
class RefreshTokenService extends BaseService implements RefreshTokenServiceInterface
42
{
43
    /**
44
     * @var string sql refreshTokens table
45
     */
46
    public $refreshTokensTable = null;
47
48
    /**
49
     * @var string sql scope refreshToken table
50
     */
51
    public $scopeRefreshTokenTable = null;
52
53
    /**
54
     * Save Refresh Token
55
     * @param RefreshTokenModelInterface $refreshToken
56
     * @param null|array $attributes attributes to save
57
     * @return bool
58
     * @throws DatabaseException
59
     * @throws DuplicateIndexException
60
     * @throws DuplicateKeyException
61
     * @since 1.0.0
62
     */
63
    protected function insert(RefreshTokenModelInterface $refreshToken, $attributes)
64
    {
65
        $result = false;
66
        if (!$refreshToken->beforeSave(true)) {
67
            return $result;
68
        }
69
        $refreshTokenKey = $refreshToken->getKey();
70
        $entity = (new Query())
71
            ->select('*')
72
            ->from($this->refreshTokensTable)
73
            ->where('id = :id', [':id' => $refreshTokenKey])
74
            ->one($this->db);
75
        if ($entity !== false) {
76
            throw new DuplicateKeyException('Duplicate key "' . $refreshTokenKey . '"');
77
        }
78
        $values = $refreshToken->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 63 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...
79
        $refreshTokenParameters = [];
80
        $this->setAttributesDefinitions($refreshToken->attributesDefinition());
81
        foreach ($values as $key => $value) {
82
            if (($value !== null) && ($key !== 'scopes')) {
83
                $refreshTokenParameters[$key] = $this->convertToDatabase($key, $value);
84
            }
85
        }
86
        $refreshTokenParameters['dateCreated'] = new Expression('NOW()');
87
        $refreshTokenParameters['dateUpdated'] = new Expression('NOW()');
88
        try {
89
            $this->db->createCommand()
90
                ->insert($this->refreshTokensTable, $refreshTokenParameters)
91
                ->execute();
92
            if (!empty($values['scopes'])) {
93
                $values['scopes'] = array_unique($values['scopes']);
94
                foreach ($values['scopes'] as $scope) {
95
                    $scopeAccessTokenParams = [
96
                        'scopeId' => $scope,
97
                        'refreshTokenId' => $refreshTokenKey
98
                    ];
99
                    $this->db->createCommand()
100
                        ->insert($this->scopeRefreshTokenTable, $scopeAccessTokenParams)
101
                        ->execute();
102
                }
103
            }
104
        } catch (DatabaseException $e) {
105
            // @codeCoverageIgnoreStart
106
            // we have a MYSQL exception, we should not discard
107
            Yii::debug('Error while inserting entity', __METHOD__);
108
            throw $e;
109
            // @codeCoverageIgnoreEnd
110
        }
111
        $changedAttributes = array_fill_keys(array_keys($values), null);
112
        $refreshToken->setOldAttributes($values);
113
        $refreshToken->afterSave(true, $changedAttributes);
114
        $result = true;
115
        return $result;
116
    }
117
118
    /**
119
     * Update Refresh Token
120
     * @param RefreshTokenModelInterface $refreshToken
121
     * @param null|array $attributes attributes to save
122
     * @return bool
123
     * @throws DatabaseException
124
     * @throws DuplicateIndexException
125
     * @throws DuplicateKeyException
126
     */
127
    protected function update(RefreshTokenModelInterface $refreshToken, $attributes)
128
    {
129
        if (!$refreshToken->beforeSave(false)) {
130
            return false;
131
        }
132
133
        $values = $refreshToken->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 127 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...
134
        $modelKey = $refreshToken->key();
135
        if (isset($values[$modelKey]) === true) {
136
            $entity = (new Query())
137
                ->select('*')
138
                ->from($this->refreshTokensTable)
139
                ->where('id = :id', [':id' => $values[$modelKey]])
140
                ->one($this->db);
141
            if ($entity !== false) {
142
                throw new DuplicateKeyException('Duplicate key "' . $values[$modelKey] . '"');
143
            }
144
        }
145
        $refreshTokenKey = isset($values[$modelKey]) ? $values[$modelKey] : $refreshToken->getKey();
146
147
        $refreshTokenParameters = [];
148
        $this->setAttributesDefinitions($refreshToken->attributesDefinition());
149
        foreach ($values as $key => $value) {
150
            if ($key !== 'scopes') {
151
                $refreshTokenParameters[$key] = ($value !== null) ? $this->convertToDatabase($key, $value) : null;
152
            }
153
        }
154
        $refreshTokenParameters['dateUpdated'] = new Expression('NOW()');
155
        try {
156
            if (array_key_exists($modelKey, $values) === true) {
157
                $oldRefreshTokenKey = $refreshToken->getOldKey();
158
                $this->db->createCommand()
159
                    ->update($this->refreshTokensTable, $refreshTokenParameters, 'id = :id', [':id' => $oldRefreshTokenKey])
160
                    ->execute();
161
            } else {
162
                $this->db->createCommand()
163
                    ->update($this->refreshTokensTable, $refreshTokenParameters, 'id = :id', [':id' => $refreshTokenKey])
164
                    ->execute();
165
            }
166
            if (isset($values['scopes'])) {
167
                $values['scopes'] = array_unique($values['scopes']);
168
                $scopeRefreshTokens = (new Query())
169
                    ->select('*')
170
                    ->from($this->scopeRefreshTokenTable)
171
                    ->where('refreshTokenId = :refreshTokenId', [':refreshTokenId' => $refreshTokenKey])
172
                    ->all($this->db);
173
                foreach ($scopeRefreshTokens as $scopeRefreshToken) {
174
                    if (($index = array_search($scopeRefreshToken['scopeId'], $values['scopes'])) === false) {
175
                        $this->db->createCommand()
176
                            ->delete($this->scopeRefreshTokenTable,
177
                                'refreshTokenId = :refreshTokenId AND scopeId = :scopeId',
178
                                [':refreshTokenId' => $refreshTokenKey, ':scopeId' => $scopeRefreshToken['scopeId']])
179
                            ->execute();
180
                    } else {
181
                        unset($values['scopes'][$index]);
182
                    }
183
                }
184
                foreach ($values['scopes'] as $scope) {
185
                    $scopeRefreshTokenParams = [
186
                        'scopeId' => $scope,
187
                        'refreshTokenId' => $refreshTokenKey
188
                    ];
189
                    $this->db->createCommand()
190
                        ->insert($this->scopeRefreshTokenTable, $scopeRefreshTokenParams)
191
                        ->execute();
192
                }
193
            }
194
        } catch (DatabaseException $e) {
195
            // @codeCoverageIgnoreStart
196
            // we have a MYSQL exception, we should not discard
197
            Yii::debug('Error while updating entity', __METHOD__);
198
            throw $e;
199
            // @codeCoverageIgnoreEnd
200
        }
201
202
        $changedAttributes = [];
203
        foreach ($values as $name => $value) {
204
            $oldAttributes = $refreshToken->getOldAttributes();
205
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
206
            $refreshToken->setOldAttribute($name, $value);
207
        }
208
        $refreshToken->afterSave(false, $changedAttributes);
209
        return true;
210
    }
211
212
    /**
213
     * @inheritdoc
214
     */
215
    public function save(RefreshTokenModelInterface $refreshToken, $attributes)
216
    {
217
        if ($refreshToken->getIsNewRecord()) {
218
            $result = $this->insert($refreshToken, $attributes);
219
        } else {
220
            $result = $this->update($refreshToken, $attributes);
221
        }
222
        return $result;
223
    }
224
225
    /**
226
     * @inheritdoc
227
     */
228
    public function findOne($key)
229
    {
230
        $record = null;
231
        $refreshTokenData = (new Query())
232
            ->select('*')
233
            ->from($this->refreshTokensTable)
234
            ->where('id = :id', [':id' => $key])
235
            ->one($this->db);
236
237
        if ($refreshTokenData !== false) {
238
            $refreshTokenData['scopes'] = [];
239
            $tmpScopes = (new Query())
240
                ->select('scopeId')
241
                ->from($this->scopeRefreshTokenTable)
242
                ->all($this->db);
243
            foreach ($tmpScopes as $scope) {
244
                $refreshTokenData['scopes'][] = $scope['scopeId'];
245
            }
246
247
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\RefreshTokenModelInterface');
248
            /** @var RefreshTokenModelInterface $record */
249
            $properties = $record->attributesDefinition();
250
            $this->setAttributesDefinitions($properties);
251
            $attributes = [];
252
            foreach ($refreshTokenData as $key => $value) {
253
                if (isset($properties[$key]) === true) {
254
                    $refreshTokenData[$key] = $this->convertToModel($key, $value);
255
                    $record->setAttribute($key, $refreshTokenData[$key]);
256
                    $attributes[$key] = $refreshTokenData[$key];
257
                    // @codeCoverageIgnoreStart
258
                } elseif ($record->canSetProperty($key)) {
259
                    // TODO: find a way to test attribute population
260
                    $record->{$key} = $value;
261
                }
262
                // @codeCoverageIgnoreEnd
263
            }
264
            if (empty($attributes) === false) {
265
                $record->setOldAttributes($attributes);
266
            }
267
            $record->afterFind();
268
        }
269
        return $record;
270
    }
271
272
    /**
273
     * @inheritdoc
274
     */
275
    public function delete(RefreshTokenModelInterface $refreshToken)
276
    {
277
        $result = false;
278
        if ($refreshToken->beforeDelete()) {
279
            //TODO: check results to return correct information
280
            $this->db->createCommand()
281
                ->delete($this->refreshTokensTable, 'id = :id', [':id' => $refreshToken->getKey()])
282
                ->execute();
283
            $refreshToken->setIsNewRecord(true);
284
            $refreshToken->afterDelete();
285
            $result = true;
286
        }
287
        return $result;
288
    }
289
290
    /**
291
     * @inheritdoc
292
     */
293
    public function findAllByUserId($userId)
294
    {
295
        $refreshTokensList = (new Query())
296
            ->select('*')
297
            ->from($this->refreshTokensTable)
298
            ->where('userId = :userId', [':userId' => $userId])
299
            ->all($this->db);
300
        $refreshTokens = [];
301
        foreach ($refreshTokensList as $refreshToken) {
302
            $result = $this->findOne($refreshToken['id']);
303
            if ($result instanceof RefreshTokenModelInterface) {
304
                $refreshTokens[] = $result;
305
            }
306
        }
307
        return $refreshTokens;
308
    }
309
310
    /**
311
     * @inheritdoc
312
     */
313
    public function deleteAllByUserId($userId)
314
    {
315
        $this->db->createCommand()
316
            ->delete($this->refreshTokensTable, 'userId = :userId', [':userId' => $userId])
317
            ->execute();
318
        return true;
319
    }
320
321
    /**
322
     * @inheritdoc
323
     */
324
    public function findAllByClientId($clientId)
325
    {
326
        $refreshTokensList = (new Query())
327
            ->select('*')
328
            ->from($this->refreshTokensTable)
329
            ->where('clientId = :clientId', [':clientId' => $clientId])
330
            ->all($this->db);
331
        $refreshTokens = [];
332
        foreach ($refreshTokensList as $refreshToken) {
333
            $result = $this->findOne($refreshToken['id']);
334
            if ($result instanceof RefreshTokenModelInterface) {
335
                $refreshTokens[] = $result;
336
            }
337
        }
338
        return $refreshTokens;
339
    }
340
341
    /**
342
     * @inheritdoc
343
     */
344
    public function deleteAllByClientId($clientId)
345
    {
346
        $this->db->createCommand()
347
            ->delete($this->refreshTokensTable, 'clientId = :clientId', [':clientId' => $clientId])
348
            ->execute();
349
        return true;
350
    }
351
}