GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — dev ( 15c1ec...2240d0 )
by James Ekow Abaka
01:47
created

DataOperations::saveRecord()   C

Complexity

Conditions 10
Paths 74

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 10.8627

Importance

Changes 0
Metric Value
dl 0
loc 76
ccs 31
cts 39
cp 0.7949
rs 6.6569
c 0
b 0
f 0
cc 10
nc 74
nop 2
crap 10.8627

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
/*
4
 * The MIT License
5
 *
6
 * Copyright 2014-2018 James Ekow Abaka Ainooson
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace ntentan\nibii;
28
29
use ntentan\atiaa\Driver;
30
use ntentan\utils\Validator;
31
32
/**
33
 * Description of DataOperations.
34
 *
35
 * @author ekow
36
 */
37
class DataOperations
38
{
39
    /**
40
     * @var RecordWrapper
41
     */
42
    private $wrapper;
43
44
    /**
45
     * Private instance of driver adapter.
46
     *
47
     * @var DriverAdapter
48
     */
49
    private $adapter;
50
51
    /**
52
     * Copy of data to be manipulated in the operations.
53
     *
54
     * @var array
55
     */
56
    private $data;
57
58
    /**
59
     * Fields that contained errors after save or update operations were performed.
60
     *
61
     * @var array
62
     */
63
    private $invalidFields = [];
64
65
    /**
66
     * Set to true when the model holds multiple records.
67
     *
68
     * @var bool
69
     */
70
    private $hasMultipleData;
71
72
    /**
73
     * An instance of the atiaa driver.
74
     *
75
     * @var Driver
76
     */
77
    private $driver;
78
79
    /**
80
     * Used to indicate save operation is in save mode to create new items.
81
     */
82
    const MODE_SAVE = 0;
83
84
    /**
85
     * Used to indicate save operation is in update mode to update existing items.
86
     */
87
    const MODE_UPDATE = 1;
88
89
    /**
90
     * Create a new instance.
91
     *
92
     * @param \ntentan\nibii\RecordWrapper $wrapper
93
     * @param Driver                       $driver
94
     */
95 30
    public function __construct(RecordWrapper $wrapper, Driver $driver)
96
    {
97 30
        $this->wrapper = $wrapper;
98 30
        $this->adapter = $wrapper->getAdapter();
99 30
        $this->driver = $driver;
100 30
    }
101
102
    /**
103
     * Perform the model save command.
104
     *
105
     * @param bool $hasMultipleData
106
     *
107
     * @return bool
108
     * @throws \ReflectionException
109
     * @throws \ntentan\atiaa\exceptions\ConnectionException
110
     * @throws exceptions\NibiiException
111
     */
112 10
    public function doSave(bool $hasMultipleData): bool
113
    {
114 10
        $this->hasMultipleData = $hasMultipleData;
115 10
        $invalidFields = [];
116 10
        $data = $this->wrapper->getData();
117
118 10
        $primaryKey = $this->wrapper->getDescription()->getPrimaryKey();
119 10
        $succesful = true;
120
121
        // Assign an empty array to force a validation error for empty models
122 10
        if (empty($data)) {
123 2
            $data = [[]];
124
        }
125
126 10
        $this->driver->beginTransaction();
127
128 10
        foreach ($data as $i => $datum) {
129 10
            $status = $this->saveRecord($datum, $primaryKey);
130 10
            $data[$i] = $datum;
131
132 10
            if (!$status['success']) {
133 4
                $succesful = false;
134 4
                $invalidFields[$i] = $status['invalid_fields'];
135 4
                $this->driver->rollback();
136 4
                break;
137
            }
138
        }
139
140 10
        if ($succesful) {
141 6
            $this->driver->commit();
142
        } else {
143 4
            $this->assignValue($this->invalidFields, $invalidFields);
144
        }
145
146 10
        $this->wrapper->setData($hasMultipleData ? $data : $data[0]);
147
148 10
        return $succesful;
149
    }
150
151
    /**
152
     * @return bool|array
153
     */
154
    public function doValidate()
155
    {
156
        $record = $this->wrapper->getData()[0];
157
        $primaryKey = $this->wrapper->getDescription()->getPrimaryKey();
158
        $pkSet = $this->isPrimaryKeySet($primaryKey, $record);
159
160
        return $this->validate($pkSet ? self::MODE_UPDATE : self::MODE_SAVE);
161
    }
162
163
    /**
164
     * Save an individual record.
165
     *
166
     * @param array $record The record to be saved
167
     * @param array $primaryKey The primary keys of the record
168
     *
169
     * @return array
170
     * @throws \ReflectionException
171
     * @throws \ntentan\atiaa\exceptions\ConnectionException
172
     * @throws exceptions\NibiiException
173
     */
174 10
    private function saveRecord(array &$record, array $primaryKey): array
175
    {
176
        $status = [
177 10
            'success'        => true,
178
            'pk_assigned'    => null,
179
            'invalid_fields' => [],
180
        ];
181
182
        // Determine if the primary key of the record is set.
183 10
        $pkSet = $this->isPrimaryKeySet($primaryKey, $record);
184
185
        // Reset the data in the model to contain only the data to be saved
186 10
        $this->wrapper->setData($record);
187
188
        // Execute all callbacks on the model
189 10
        $this->wrapper->preSaveCallback();
190 10
        if ($pkSet) {
191 2
            $this->wrapper->preUpdateCallback();
192
        } else {
193 8
            $this->wrapper->preCreateCallback();
194
        }
195
196
        // Validate the data
197 10
        $validity = $this->validate($pkSet ? self::MODE_UPDATE : self::MODE_SAVE);
198
199
        // Exit if data is invalid
200 10
        if ($validity !== true) {
201 4
            $status['invalid_fields'] = $validity;
202 4
            $status['success'] = false;
203
204 4
            return $status;
205
        }
206
207 6
        $record = $this->wrapper->getData();
208 6
        $record = reset($record) === false ? [] : reset($record);
209
210
        // Save any relationships that are attached to the data
211 6
        $relationships = $this->wrapper->getDescription()->getRelationships();
212 6
        $relationshipsWithData = [];
213
214 6
        foreach ($relationships ?? [] as $model => $relationship) {
215 6
            if (isset($record[$model])) {
216
                $relationship->runSetup();
217
                $relationship->preSave($record, $record[$model]);
218
                $relationshipsWithData[$model] = $relationship;
219
            }
220
        }
221
222
        // Assign the data to the wrapper again
223 6
        $this->wrapper->setData($record);
224
225
        // Update or save the data and run post callbacks
226 6
        if ($pkSet) {
227 2
            $this->adapter->update($record);
228 2
            $this->wrapper->postUpdateCallback();
229
        } else {
230 4
            $this->adapter->insert($record);
231 4
            $keyValue = $this->driver->getLastInsertId();
232 4
            $this->wrapper->{$primaryKey[0]} = $keyValue;
233 4
            $this->wrapper->postCreateCallback($keyValue);
234
        }
235 6
        $this->wrapper->postSaveCallback();
236
237
        // Reset the data so it contains any modifications made by callbacks
238 6
        $record = $this->wrapper->getData()[0];
239 6
        foreach ($relationshipsWithData as $model => $relationship) {
240
            $relationship->postSave($record);
241
            $invalidRelatedFields = $relationship->getInvalidFields();
242
            if(!empty($invalidRelatedFields)) {
243
                $status['success'] = false;
244
                $status['invalid_fields'][$model] = $invalidRelatedFields;
245
            }
246
        }
247
248 6
        return $status;
249
    }
250
251
    /**
252
     * @param int $mode
253
     *
254
     * @return bool|array
255
     */
256 10
    private function validate(int $mode)
257
    {
258 10
        $validator = ORMContext::getInstance()->getModelValidatorFactory()->createModelValidator($this->wrapper, $mode);
259 10
        $mainValidatorErrors = [];
260 10
        $modelValidatorErrors = [];
261
262 10
        $data = $this->wrapper->toArray();
263
264 10
        if (!$validator->validate($data)) {
265 4
            $mainValidatorErrors = $validator->getInvalidFields();
266
        }
267
268 10
        if(!empty($this->wrapper->getValidationRules())) {
269
            $modelValidator = new Validator();
270
            $modelValidator->setRules($this->wrapper->getValidationRules());
271
            if(!$modelValidator->validate($data)) {
272
                $modelValidatorErrors = $modelValidator->getInvalidFields();
273
            }
274
        }
275
276 10
        $customValidatorErrors = $this->wrapper->onValidate($mainValidatorErrors);
277 10
        $errors = array_merge_recursive($mainValidatorErrors, $customValidatorErrors, $modelValidatorErrors);
278
279 10
        return empty($errors) ? true : $errors;
280
    }
281
282
    /**
283
     * @param string|array $primaryKey
284
     * @param array        $data
285
     *
286
     * @return bool
287
     */
288 10
    private function isPrimaryKeySet($primaryKey, array $data) : bool
289
    {
290 10
        if (is_string($primaryKey) && ($data[$primaryKey] !== null || $data[$primaryKey] !== '')) {
291
            return true;
292
        }
293 10
        foreach ($primaryKey as $keyField) {
294 10
            if (!isset($data[$keyField]) || $data[$keyField] === null || $data[$keyField] === '') {
295 8
                return false;
296
            }
297
        }
298
299 2
        return true;
300
    }
301
302
    /**
303
     * @param mixed $property
304
     * @param mixed $value
305
     */
306 4
    private function assignValue(&$property, $value) : void
307
    {
308 4
        if ($this->hasMultipleData) {
309
            $property = $value;
310
        } else {
311 4
            $property = $value[0];
312
        }
313 4
    }
314
315
    /**
316
     * @return array
317
     */
318
    public function getData() : array
319
    {
320
        return $this->data;
321
    }
322
323
    /**
324
     * @return array
325
     */
326 10
    public function getInvalidFields() : array
327
    {
328 10
        return $this->invalidFields;
329
    }
330
331
    /**
332
     * @param string $primaryKey
333
     * @param array  $data
334
     *
335
     * @return bool
336
     */
337
    public function isItemDeletable(string $primaryKey, array $data) : bool
338
    {
339
        if ($this->isPrimaryKeySet($primaryKey, $data)) {
340
            return true;
341
        } else {
342
            return false;
343
        }
344
    }
345
}
346