Completed
Pull Request — devel (#18)
by
unknown
37:50
created

AuthCodeService::findOne()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 43
rs 8.2986
cc 7
nc 3
nop 1
1
<?php
2
/**
3
 * AuthCodeService.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\AuthCodeModelInterface;
20
use sweelix\oauth2\server\interfaces\AuthCodeServiceInterface;
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 auth code service for mySql
28
 *  database structure
29
 *    * oauth2:authCodes:<aid> : hash (AuthCode)
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\mySql
37
 * @since 1.0.0
38
 */
39
class AuthCodeService extends BaseService implements AuthCodeServiceInterface
40
{
41
    /**
42
     * @var string sql authorizationCodes table
43
     */
44
    public $authorizationCodesTable = null;
45
46
    /**
47
     * @var string sql scope authorizationCode table
48
     */
49
    public $scopeAuthorizationCodeTable = null;
50
51
    /**
52
     * Save Auth Code
53
     * @param AuthCodeModelInterface $authCode
54
     * @param null|array $attributes attributes to save
55
     * @return bool
56
     * @throws DatabaseException
57
     * @throws DuplicateIndexException
58
     * @throws DuplicateKeyException
59
     * @since 1.0.0
60
     */
61
    protected function insert(AuthCodeModelInterface $authCode, $attributes)
62
    {
63
        $result = false;
64
        if (!$authCode->beforeSave(true)) {
65
            return $result;
66
        }
67
        $authCodeKey = $authCode->getKey();
68
        $entity = (new Query())
69
            ->select('*')
70
            ->from($this->authorizationCodesTable)
71
            ->where('id = :id', [':id' => $authCodeKey])
72
            ->one($this->db);
73
        if ($entity !== false) {
74
            throw new DuplicateKeyException('Duplicate key "' . $authCodeKey . '"');
75
        }
76
        $values = $authCode->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 61 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...
77
        $authCodeParameters = [];
78
        $this->setAttributesDefinitions($authCode->attributesDefinition());
79
        foreach ($values as $key => $value) {
80
            if (($value !== null) && ($key !== 'scopes')) {
81
                $authCodeParameters[$key] = $this->convertToDatabase($key, $value);
82
            }
83
        }
84
        $authCodeParameters['dateCreated'] = new Expression('NOW()');
85
        $authCodeParameters['dateUpdated'] = new Expression('NOW()');
86
        try {
87
            $this->db->createCommand()
88
                ->insert($this->authorizationCodesTable, $authCodeParameters)
89
                ->execute();
90
            if (!empty($values['scopes'])) {
91
                $values['scopes'] = array_unique($values['scopes']);
92
                foreach ($values['scopes'] as $scope) {
93
                    $scopeAuthCodeParams = [
94
                        'scopeId' => $scope,
95
                        'authorizationCodeId' => $authCodeKey
96
                    ];
97
                    $this->db->createCommand()
98
                        ->insert($this->scopeAuthorizationCodeTable, $scopeAuthCodeParams)
99
                        ->execute();
100
                }
101
            }
102
        } catch (DatabaseException $e) {
103
            // @codeCoverageIgnoreStart
104
            // we have a MYSQL exception, we should not discard
105
            Yii::debug('Error while inserting entity', __METHOD__);
106
            throw $e;
107
            // @codeCoverageIgnoreEnd
108
        }
109
        $changedAttributes = array_fill_keys(array_keys($values), null);
110
        $authCode->setOldAttributes($values);
111
        $authCode->afterSave(true, $changedAttributes);
112
        $result = true;
113
        return $result;
114
    }
115
116
    /**
117
     * Update Auth Code
118
     * @param AuthCodeModelInterface $authCode
119
     * @param null|array $attributes attributes to save
120
     * @return bool
121
     * @throws DatabaseException
122
     * @throws DuplicateIndexException
123
     * @throws DuplicateKeyException
124
     */
125
    protected function update(AuthCodeModelInterface $authCode, $attributes)
126
    {
127
        if (!$authCode->beforeSave(false)) {
128
            return false;
129
        }
130
131
        $values = $authCode->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 125 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...
132
        $modelKey = $authCode->key();
133
        if (isset($values[$modelKey]) === true) {
134
            $entity = (new Query())
135
                ->select('*')
136
                ->from($this->authorizationCodesTable)
137
                ->where('id = :id', [':id' => $values[$modelKey]])
138
                ->one($this->db);
139
            if ($entity !== false) {
140
                throw new DuplicateKeyException('Duplicate key "' . $values[$modelKey] . '"');
141
            }
142
        }
143
        $authCodeKey = isset($values[$modelKey]) ? $values[$modelKey] : $authCode->getKey();
144
145
        $authCodeParameters = [];
146
        $this->setAttributesDefinitions($authCode->attributesDefinition());
147
        foreach ($values as $key => $value) {
148
            if ($key !== 'scopes') {
149
                $authCodeParameters[$key] = ($value !== null) ? $this->convertToDatabase($key, $value) : null;
150
            }
151
        }
152
        $authCodeParameters['dateUpdated'] = new Expression('NOW()');
153
        try {
154
            if (array_key_exists($modelKey, $values) === true) {
155
                $oldAuthCodeKey = $authCode->getOldKey();
156
                $this->db->createCommand()
157
                    ->update($this->authorizationCodesTable, $authCodeParameters, 'id = :id', [':id' => $oldAuthCodeKey])
158
                    ->execute();
159
            } else {
160
                $this->db->createCommand()
161
                    ->update($this->authorizationCodesTable, $authCodeParameters, 'id = :id', [':id' => $authCodeKey])
162
                    ->execute();
163
            }
164
            if (isset($values['scopes'])) {
165
                $values['scopes'] = array_unique($values['scopes']);
166
                $scopeAuthCodes = (new Query())
167
                    ->select('*')
168
                    ->from($this->scopeAuthorizationCodeTable)
169
                    ->where('authorizationCodeId = :authorizationCodeId', [':authorizationCodeId' => $authCodeKey])
170
                    ->all($this->db);
171
                foreach ($scopeAuthCodes as $scopeAuthCode) {
172
                    if (($index = array_search($scopeAuthCode['scopeId'], $values['scopes'])) === false) {
173
                        $this->db->createCommand()
174
                            ->delete($this->scopeAuthorizationCodeTable,
175
                                'authorizationCodeId = :authorizationCodeId AND scopeId = :scopeId',
176
                                [':authorizationCodeId' => $authCodeKey, ':scopeId' => $scopeAuthCode['scopeId']])
177
                            ->execute();
178
                    } else {
179
                        unset($values['scopes'][$index]);
180
                    }
181
                }
182
                foreach ($values['scopes'] as $scope) {
183
                    $scopeAuthCodeParams = [
184
                        'scopeId' => $scope,
185
                        'authorizationCodeId' => $authCodeKey
186
                    ];
187
                    $this->db->createCommand()
188
                        ->insert($this->scopeAuthorizationCodeTable, $scopeAuthCodeParams)
189
                        ->execute();
190
                }
191
            }
192
        } catch (DatabaseException $e) {
193
            // @codeCoverageIgnoreStart
194
            // we have a MYSQL exception, we should not discard
195
            Yii::debug('Error while updating entity', __METHOD__);
196
            throw $e;
197
            // @codeCoverageIgnoreEnd
198
        }
199
200
        $changedAttributes = [];
201
        foreach ($values as $name => $value) {
202
            $oldAttributes = $authCode->getOldAttributes();
203
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
204
            $authCode->setOldAttribute($name, $value);
205
        }
206
        $authCode->afterSave(false, $changedAttributes);
207
        return true;
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213
    public function save(AuthCodeModelInterface $authCode, $attributes)
214
    {
215
        if ($authCode->getIsNewRecord()) {
216
            $result = $this->insert($authCode, $attributes);
217
        } else {
218
            $result = $this->update($authCode, $attributes);
219
        }
220
        return $result;
221
    }
222
223
    /**
224
     * @inheritdoc
225
     */
226
    public function findOne($key)
227
    {
228
        $record = null;
229
        $authCodeData = (new Query())
230
            ->select('*')
231
            ->from($this->authorizationCodesTable)
232
            ->where('id = :id', [':id' => $key])
233
            ->one($this->db);
234
235
        if ($authCodeData !== false) {
236
            $authCodeData['scopes'] = [];
237
            $tmpScopes = (new Query())
238
                ->select('scopeId')
239
                ->from($this->scopeAuthorizationCodeTable)
240
                ->all($this->db);
241
            foreach ($tmpScopes as $scope) {
242
                $authCodeData['scopes'][] = $scope['scopeId'];
243
            }
244
245
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\AuthCodeModelInterface');
246
            /** @var AuthCodeModelInterface $record */
247
            $properties = $record->attributesDefinition();
248
            $this->setAttributesDefinitions($properties);
249
            $attributes = [];
250
            foreach ($authCodeData as $key => $value) {
251
                if (isset($properties[$key]) === true) {
252
                    $authCodeData[$key] = $this->convertToModel($key, $value);
253
                    $record->setAttribute($key, $authCodeData[$key]);
254
                    $attributes[$key] = $authCodeData[$key];
255
                    // @codeCoverageIgnoreStart
256
                } elseif ($record->canSetProperty($key)) {
257
                    // TODO: find a way to test attribute population
258
                    $record->{$key} = $value;
259
                }
260
                // @codeCoverageIgnoreEnd
261
            }
262
            if (empty($attributes) === false) {
263
                $record->setOldAttributes($attributes);
264
            }
265
            $record->afterFind();
266
        }
267
        return $record;
268
    }
269
270
    /**
271
     * @inheritdoc
272
     */
273
    public function delete(AuthCodeModelInterface $authCode)
274
    {
275
        $result = false;
276
        if ($authCode->beforeDelete()) {
277
            //TODO: check results to return correct information
278
            $this->db->createCommand()
279
                ->delete($this->authorizationCodesTable, 'id = :id', [':id' => $authCode->getKey()])
280
                ->execute();
281
            $authCode->setIsNewRecord(true);
282
            $authCode->afterDelete();
283
            $result = true;
284
        }
285
        return $result;
286
    }
287
}