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

ClientService   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 375
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 51
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 375
rs 7.92

9 Methods

Rating   Name   Duplication   Size   Complexity  
C insert() 0 66 12
F update() 0 113 21
A save() 0 9 2
B findOne() 0 51 8
A delete() 0 14 2
A hasUser() 0 10 1
A addUser() 0 11 1
A removeUser() 0 9 1
A findAllByUserId() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like ClientService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ClientService, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * ClientService.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\ClientModelInterface;
20
use sweelix\oauth2\server\interfaces\ClientServiceInterface;
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 client 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 ClientService extends BaseService implements ClientServiceInterface
38
{
39
    /**
40
     * @var string sql client grantType junction table
41
     */
42
    public $clientGrantTypeTable = null;
43
44
    /**
45
     * @var string sql clients table
46
     */
47
    public $clientsTable = null;
48
49
    /**
50
     * @var string sql client user table
51
     */
52
    public $clientUserTable = null;
53
54
    /**
55
     * @var string sql scope client junction table
56
     */
57
    public $scopeClientTable = null;
58
59
    /**
60
     * @var string sql scopes table
61
     */
62
    public $scopesTable = null;
63
64
    /**
65
     * Save Client
66
     * @param ClientModelInterface $client
67
     * @param null|array $attributes attributes to save
68
     * @return bool
69
     * @throws DatabaseException
70
     * @throws DuplicateIndexException
71
     * @throws DuplicateKeyException
72
     * @since 1.0.0
73
     */
74
    protected function insert(ClientModelInterface $client, $attributes)
75
    {
76
        $result = false;
77
        if (!$client->beforeSave(true)) {
78
            return $result;
79
        }
80
        $clientKey = $client->getKey();
81
        $entity = (new Query())
82
            ->select('*')
83
            ->from($this->clientsTable)
84
            ->where('id = :id', [':id' => $clientKey])
85
            ->one($this->db);
86
        if ($entity !== false) {
87
            throw new DuplicateKeyException('Duplicate key "' . $clientKey . '"');
88
        }
89
        $values = $client->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 74 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...
90
        $clientParameters = [];
91
        $this->setAttributesDefinitions($client->attributesDefinition());
92
        foreach ($values as $key => $value) {
93
            if (($value !== null) && ($key !== 'grantTypes') && ($key !== 'scopes')) {
94
                $clientParameters[$key] = $this->convertToDatabase($key, $value);
95
            }
96
        }
97
        $clientParameters['dateCreated'] = new Expression('NOW()');
98
        $clientParameters['dateUpdated'] = new Expression('NOW()');
99
        try {
100
            $this->db->createCommand()
101
                ->insert($this->clientsTable, $clientParameters)
102
                ->execute();
103
            if (!empty($values['grantTypes'])) {
104
                $values['grantTypes'] = array_unique($values['grantTypes']);
105
                foreach ($values['grantTypes'] as $grantType) {
106
                    $clientGrantTypeParams = [
107
                        'clientId' => $clientKey,
108
                        'grantTypeId' => $grantType,
109
                    ];
110
                    $this->db->createCommand()
111
                        ->insert($this->clientGrantTypeTable, $clientGrantTypeParams)
112
                        ->execute();
113
                }
114
            }
115
            if (!empty($values['scopes'])) {
116
                $values['scopes'] = array_unique($values['scopes']);
117
                foreach ($values['scopes'] as $scope) {
118
                    $scopeClientParams = [
119
                        'scopeId' => $scope,
120
                        'clientId' => $clientKey
121
                    ];
122
                    $this->db->createCommand()
123
                        ->insert($this->scopeClientTable, $scopeClientParams)
124
                        ->execute();
125
                }
126
            }
127
        } catch (DatabaseException $e) {
128
            // @codeCoverageIgnoreStart
129
            // we have a MYSQL exception, we should not discard
130
            Yii::debug('Error while inserting entity', __METHOD__);
131
            throw $e;
132
            // @codeCoverageIgnoreEnd
133
        }
134
        $changedAttributes = array_fill_keys(array_keys($values), null);
135
        $client->setOldAttributes($values);
136
        $client->afterSave(true, $changedAttributes);
137
        $result = true;
138
        return $result;
139
    }
140
141
    /**
142
     * Update Client
143
     * @param ClientModelInterface $client
144
     * @param null|array $attributes attributes to save
145
     * @return bool
146
     * @throws DatabaseException
147
     * @throws DuplicateIndexException
148
     * @throws DuplicateKeyException
149
     */
150
    protected function update(ClientModelInterface $client, $attributes)
151
    {
152
        if (!$client->beforeSave(false)) {
153
            return false;
154
        }
155
156
        $values = $client->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 150 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...
157
        $modelKey = $client->key();
158
        if (isset($values[$modelKey]) === true) {
159
            $entity = (new Query())
160
                ->select('*')
161
                ->from($this->clientsTable)
162
                ->where('id = :id', [':id' => $values[$modelKey]])
163
                ->one($this->db);
164
            if ($entity !== false) {
165
                throw new DuplicateKeyException('Duplicate key "' . $values[$modelKey] . '"');
166
            }
167
        }
168
        $clientKey = isset($values[$modelKey]) ? $values[$modelKey] : $client->getKey();
169
170
        $clientParameters = [];
171
        $this->setAttributesDefinitions($client->attributesDefinition());
172
        foreach ($values as $key => $value) {
173
            if (($key !== 'grantTypes') && ($key !== 'scopes')) {
174
                $clientParameters[$key] = ($value !== null) ? $this->convertToDatabase($key, $value) : null;
175
            }
176
        }
177
        $clientParameters['dateUpdated'] = new Expression('NOW()');
178
        try {
179
            if (array_key_exists($modelKey, $values) === true) {
180
                $oldClientKey = $client->getOldKey();
181
                $this->db->createCommand()
182
                    ->update($this->clientsTable, $clientParameters, 'id = :id', [':id' => $oldClientKey])
183
                    ->execute();
184
            } else {
185
                $this->db->createCommand()
186
                    ->update($this->clientsTable, $clientParameters, 'id = :id', [':id' => $clientKey])
187
                    ->execute();
188
            }
189
            if (isset($values['grantTypes'])) {
190
                $values['grantTypes'] = array_unique($values['grantTypes']);
191
                $clientGrantTypes = (new Query())
192
                    ->select('*')
193
                    ->from($this->clientGrantTypeTable)
194
                    ->where('clientId = :clientId', [':clientId' => $clientKey])
195
                    ->all($this->db);
196
                foreach ($clientGrantTypes as $clientGrantType) {
197
                    if (($index = array_search($clientGrantType['grantTypeId'], $values['grantTypes'])) === false) {
198
                        $this->db->createCommand()
199
                            ->delete($this->clientGrantTypeTable,
200
                                ['clientId = :clientId', 'grantTypeId = :grantTypeId'],
201
                                [':clientId' => $clientKey, ':grantTypeId' => $clientGrantType['grantTypeId']])
202
                            ->execute();
203
                    } else {
204
                        unset($values['grantTypes'][$index]);
205
                    }
206
                }
207
                foreach ($values['grantTypes'] as $grantType) {
208
                    $clientGrantTypeParams = [
209
                        'clientId' => $clientKey,
210
                        'grantTypeId' => $grantType,
211
                    ];
212
                    $this->db->createCommand()
213
                        ->insert($this->clientGrantTypeTable, $clientGrantTypeParams)
214
                        ->execute();
215
                }
216
            }
217
            if (isset($values['scopes'])) {
218
                $values['scopes'] = array_unique($values['scopes']);
219
                $scopeClients = (new Query())
220
                    ->select('*')
221
                    ->from($this->scopeClientTable)
222
                    ->where('clientId = :clientId', [':clientId' => $clientKey])
223
                    ->all($this->db);
224
                foreach ($scopeClients as $scopeClient) {
225
                    if (($index = array_search($scopeClient['scopeId'], $values['scopes'])) === false) {
226
                        $this->db->createCommand()
227
                            ->delete($this->scopeClientTable,
228
                                'clientId = :clientId AND scopeId = :scopeId',
229
                                [':clientId' => $clientKey, ':scopeId' => $scopeClient['scopeId']])
230
                            ->execute();
231
                    } else {
232
                        unset($values['scopes'][$index]);
233
                    }
234
                }
235
                foreach ($values['scopes'] as $scope) {
236
                    $scopeClientParams = [
237
                        'scopeId' => $scope,
238
                        'clientId' => $clientKey
239
                    ];
240
                    $this->db->createCommand()
241
                        ->insert($this->scopeClientTable, $scopeClientParams)
242
                        ->execute();
243
                }
244
            }
245
246
        } catch (DatabaseException $e) {
247
            // @codeCoverageIgnoreStart
248
            // we have a MYSQL exception, we should not discard
249
            Yii::debug('Error while updating entity', __METHOD__);
250
            throw $e;
251
            // @codeCoverageIgnoreEnd
252
        }
253
254
        $changedAttributes = [];
255
        foreach ($values as $name => $value) {
256
            $oldAttributes = $client->getOldAttributes();
257
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
258
            $client->setOldAttribute($name, $value);
259
        }
260
        $client->afterSave(false, $changedAttributes);
261
        return true;
262
    }
263
264
    /**
265
     * @inheritdoc
266
     */
267
    public function save(ClientModelInterface $client, $attributes)
268
    {
269
        if ($client->getIsNewRecord()) {
270
            $result = $this->insert($client, $attributes);
271
        } else {
272
            $result = $this->update($client, $attributes);
273
        }
274
        return $result;
275
    }
276
277
    /**
278
     * @inheritdoc
279
     */
280
    public function findOne($key)
281
    {
282
        $record = null;
283
        $clientData = (new Query())
284
            ->select('*')
285
            ->from($this->clientsTable)
286
            ->where('id = :id', [':id' => $key])
287
            ->one($this->db);
288
289
        if ($clientData !== false) {
290
            $clientData['grantTypes'] = [];
291
            $clientData['scopes'] = [];
292
            $tmpGrantTypes = (new Query())
293
                ->select('grantTypeId')
294
                ->from($this->clientGrantTypeTable)
295
                ->all($this->db);
296
            foreach ($tmpGrantTypes as $grantType) {
297
                $clientData['grantTypes'][] = $grantType['grantTypeId'];
298
            }
299
            $tmpScopes = (new Query())
300
                ->select('scopeId')
301
                ->from($this->scopeClientTable)
302
                ->all($this->db);
303
            foreach ($tmpScopes as $scope) {
304
                $clientData['scopes'][] = $scope['scopeId'];
305
            }
306
307
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\ClientModelInterface');
308
            /** @var ClientModelInterface $record */
309
            $properties = $record->attributesDefinition();
310
            $this->setAttributesDefinitions($properties);
311
            $attributes = [];
312
            foreach ($clientData as $key => $value) {
313
                if (isset($properties[$key]) === true) {
314
                    $clientData[$key] = $this->convertToModel($key, $value);
315
                    $record->setAttribute($key, $clientData[$key]);
316
                    $attributes[$key] = $clientData[$key];
317
                    // @codeCoverageIgnoreStart
318
                } elseif ($record->canSetProperty($key)) {
319
                    // TODO: find a way to test attribute population
320
                    $record->{$key} = $value;
321
                }
322
                // @codeCoverageIgnoreEnd
323
            }
324
            if (empty($attributes) === false) {
325
                $record->setOldAttributes($attributes);
326
            }
327
            $record->afterFind();
328
        }
329
        return $record;
330
    }
331
332
    /**
333
     * @inheritdoc
334
     */
335
    public function delete(ClientModelInterface $client)
336
    {
337
        $result = false;
338
        if ($client->beforeDelete()) {
339
            //TODO: check results to return correct information
340
            $this->db->createCommand()
341
                ->delete($this->clientsTable, 'id = :id', [':id' => $client->getKey()])
342
                ->execute();
343
            $client->setIsNewRecord(true);
344
            $client->afterDelete();
345
            $result = true;
346
        }
347
        return $result;
348
    }
349
350
    /**
351
     * @inheritdoc
352
     */
353
    public function hasUser(ClientModelInterface $client, $userId)
354
    {
355
        $entity = (new Query())
356
            ->select('*')
357
            ->from($this->clientUserTable)
358
            ->where('clientId = :clientId', [':clientId' => $client->getKey()])
359
            ->andWhere('userId = :userId', [':userId' => $userId])
360
            ->one($this->db);
361
        return ($entity !== false);
362
    }
363
364
    /**
365
     * @inheritdoc
366
     */
367
    public function addUser(ClientModelInterface $client, $userId)
368
    {
369
        $params = [
370
            'clientId' => $client->getKey(),
371
            'userId' => $userId
372
        ];
373
        $this->db->createCommand()
374
            ->insert($this->clientUserTable, $params)
375
            ->execute();
376
        return true;
377
    }
378
379
    /**
380
     * @inheritdoc
381
     */
382
    public function removeUser(ClientModelInterface $client, $userId)
383
    {
384
        $this->db->createCommand()
385
            ->delete($this->clientUserTable,
386
                'clientId = :clientId AND userId = :userId',
387
                [':clientId' => $client->getKey(), ':userId' => $userId])
388
            ->execute();
389
        return true;
390
    }
391
392
    /**
393
     * @inheritdoc
394
     */
395
    public function findAllByUserId($userId)
396
    {
397
        $clientsList = (new Query())
398
            ->select('*')
399
            ->from($this->clientUserTable)
400
            ->where('userId = :userId', [':userId' => $userId])
401
            ->all($this->db);
402
        $clients = [];
403
        foreach ($clientsList as $client) {
404
            $result = $this->findOne($client['clientId']);
405
            if ($result instanceof ClientModelInterface) {
406
                $clients[] = $result;
407
            }
408
        }
409
        return $clients;
410
    }
411
}
412