AccessTokenService::findAll()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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