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

ScopeService::update()   C

Complexity

Conditions 11
Paths 122

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 54
rs 6.7103
cc 11
nc 122
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * ScopeService.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\ScopeModelInterface;
20
use sweelix\oauth2\server\interfaces\ScopeServiceInterface;
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 scope service for mySql
28
 *  database structure
29
 *    * oauth2:scopes:<sid> : hash (Scope)
30
 *    * oauth2:scopes:keys : set scopeIds
31
 *    * oauth2:scopes:defaultkeys : set default scopeIds
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 ScopeService extends BaseService implements ScopeServiceInterface
42
{
43
    /**
44
     * @var string sql scope client table
45
     */
46
    public $scopeClientTable = null;
47
48
    /**
49
     * @var string sql scopes table
50
     */
51
    public $scopesTable = null;
52
53
    /**
54
     * Save Scope
55
     * @param ScopeModelInterface $scope
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(ScopeModelInterface $scope, $attributes)
64
    {
65
        $result = false;
66
        if (!$scope->beforeSave(true)) {
67
            return $result;
68
        }
69
        $entity = (new Query())
70
            ->select('*')
71
            ->from($this->scopesTable)
72
            ->where('id = :id', [':id' => $scope->id])
0 ignored issues
show
Bug introduced by
Accessing id on the interface sweelix\oauth2\server\in...ces\ScopeModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
73
            ->one($this->db);
74
        if ($entity !== false) {
75
            throw new DuplicateKeyException('Duplicate key "' . $scope->id . '"');
0 ignored issues
show
Bug introduced by
Accessing id on the interface sweelix\oauth2\server\in...ces\ScopeModelInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
76
        }
77
        $values = $scope->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...
78
        $scopeParameters = [];
79
        $this->setAttributesDefinitions($scope->attributesDefinition());
80
        foreach ($values as $key => $value) {
81
            if ($value !== null) {
82
                $scopeParameters[$key] = $this->convertToDatabase($key, $value);
83
            }
84
        }
85
        $scopeParameters['dateCreated'] = new Expression('NOW()');
86
        $scopeParameters['dateUpdated'] = new Expression('NOW()');
87
        try {
88
            $this->db->createCommand()
89
                ->insert($this->scopesTable, $scopeParameters)
90
                ->execute();
91
        } catch (DatabaseException $e) {
92
            // @codeCoverageIgnoreStart
93
            // we have a MYSQL exception, we should not discard
94
            Yii::debug('Error while inserting entity', __METHOD__);
95
            throw $e;
96
            // @codeCoverageIgnoreEnd
97
        }
98
        $changedAttributes = array_fill_keys(array_keys($values), null);
99
        $scope->setOldAttributes($values);
100
        $scope->afterSave(true, $changedAttributes);
101
        $result = true;
102
        return $result;
103
    }
104
105
    /**
106
     * Update ScopeModelInterface
107
     * @param ScopeModelInterface $scope
108
     * @param null|array $attributes attributes to save
109
     * @return bool
110
     * @throws DatabaseException
111
     * @throws DuplicateIndexException
112
     * @throws DuplicateKeyException
113
     */
114
    protected function update(ScopeModelInterface $scope, $attributes)
115
    {
116
        if (!$scope->beforeSave(false)) {
117
            return false;
118
        }
119
120
        $values = $scope->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 114 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...
121
        $modelKey = $scope->key();
122
        if (isset($values[$modelKey]) === true) {
123
            $entity = (new Query())
124
                ->select('*')
125
                ->from($this->scopesTable)
126
                ->where('id = :id', [':id' => $values[$modelKey]])
127
                ->one($this->db);
128
            if ($entity !== false) {
129
                throw new DuplicateKeyException('Duplicate key "' . $values[$modelKey] . '"');
130
            }
131
        }
132
        $scopeKey = isset($values[$modelKey]) ? $values[$modelKey] : $scope->getKey();
133
134
        $scopeParameters = [];
135
        $this->setAttributesDefinitions($scope->attributesDefinition());
136
        foreach ($values as $key => $value) {
137
            $scopeParameters[$key] = ($value !== null) ? $this->convertToDatabase($key, $value) : null;
138
        }
139
        $scopeParameters['dateUpdated'] = new Expression('NOW()');
140
        try {
141
            if (array_key_exists($modelKey, $values) === true) {
142
                $oldScopeKey = $scope->getOldKey();
143
                $this->db->createCommand()
144
                    ->update($this->scopesTable, $scopeParameters, 'id = :id', [':id' => $oldScopeKey])
145
                    ->execute();
146
            } else {
147
                $this->db->createCommand()
148
                    ->update($this->scopesTable, $scopeParameters, 'id = :id', [':id' => $scopeKey])
149
                    ->execute();
150
            }
151
        } catch (DatabaseException $e) {
152
            // @codeCoverageIgnoreStart
153
            // we have a MYSQL exception, we should not discard
154
            Yii::debug('Error while updating entity', __METHOD__);
155
            throw $e;
156
            // @codeCoverageIgnoreEnd
157
        }
158
159
        $changedAttributes = [];
160
        foreach ($values as $name => $value) {
161
            $oldAttributes = $scope->getOldAttributes();
162
            $changedAttributes[$name] = isset($oldAttributes[$name]) ? $oldAttributes[$name] : null;
163
            $scope->setOldAttribute($name, $value);
164
        }
165
        $scope->afterSave(false, $changedAttributes);
166
        return true;
167
    }
168
169
    /**
170
     * @inheritdoc
171
     */
172
    public function save(ScopeModelInterface $scope, $attributes)
173
    {
174
        if ($scope->getIsNewRecord()) {
175
            $result = $this->insert($scope, $attributes);
176
        } else {
177
            $result = $this->update($scope, $attributes);
178
        }
179
        return $result;
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185
    public function findOne($key)
186
    {
187
        $record = null;
188
        $scopeData = (new Query())
189
            ->select('*')
190
            ->from($this->scopesTable)
191
            ->where('id = :id', [':id' => $key])
192
            ->one($this->db);
193
        if ($scopeData !== false) {
194
            $record = Yii::createObject('sweelix\oauth2\server\interfaces\ScopeModelInterface');
195
            /** @var ScopeModelInterface $record */
196
            $properties = $record->attributesDefinition();
197
            $this->setAttributesDefinitions($properties);
198
            $attributes = [];
199
            foreach ($scopeData as $key => $value) {
200
                if (isset($properties[$key]) === true) {
201
                    $scopeData[$key] = $this->convertToModel($key, $value);
202
                    $record->setAttribute($key, $scopeData[$key]);
203
                    $attributes[$key] = $scopeData[$key];
204
                    // @codeCoverageIgnoreStart
205
                } elseif ($record->canSetProperty($key)) {
206
                    // TODO: find a way to test attribute population
207
                    $record->{$key} = $value;
208
                }
209
                // @codeCoverageIgnoreEnd
210
            }
211
            if (empty($attributes) === false) {
212
                $record->setOldAttributes($attributes);
213
            }
214
            $record->afterFind();
215
        }
216
        return $record;
217
    }
218
219
    /**
220
     * @inheritdoc
221
     */
222
    public function delete(ScopeModelInterface $scope)
223
    {
224
        $result = false;
225
        if ($scope->beforeDelete()) {
226
            //TODO: check results to return correct information
227
            $this->db->createCommand()
228
                ->delete($this->scopesTable, 'id = :id', [':id' => $scope->getKey()])
229
                ->execute();
230
            $scope->setIsNewRecord(true);
231
            $scope->afterDelete();
232
            $result = true;
233
        }
234
        return $result;
235
    }
236
237
    /**
238
     * @inheritdoc
239
     */
240
    public function findAvailableScopeIds()
241
    {
242
        $tmpScopes = (new Query())
243
            ->select('id')
244
            ->from($this->scopesTable)
245
            ->all($this->db);
246
        $scopes = [];
247
        foreach ($tmpScopes as $scope) {
248
            $scopes[] = $scope['id'];
249
        }
250
        return $scopes;
251
    }
252
253
    /**
254
     * @inheritdoc
255
     */
256
    public function findDefaultScopeIds($clientId = null)
257
    {
258
        //TODO: add default scopes for clients
259
        $defaultScopeIds = [];
260
        if ($clientId !== null) {
261
            $tmpScopeIds = (new Query())
262
                ->select('scopeId as ID')
263
                ->from($this->scopeClientTable)
264
                ->where('clientId = :clientId', [':clientId' => $clientId])
265
                ->all($this->db);
266
        } else {
267
            $tmpScopeIds = (new Query())
268
                ->select('id as ID')
269
                ->from($this->scopesTable)
270
                ->where('isDefault = :isDefault', [':isDefault' => true])
271
                ->all($this->db);
272
        }
273
        foreach ($tmpScopeIds as $tmpScopeId) {
274
            $defaultScopeIds[] = $tmpScopeId['ID'];
275
        }
276
        return $defaultScopeIds;
277
    }
278
}
279