Completed
Pull Request — devel (#18)
by
unknown
61:36 queued 21:23
created

AccessTokenService::deleteAllByClientId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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