Passed
Push — master ( f2dea1...58a092 )
by Nate
04:47
created

Model   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 551
Duplicated Lines 23.05 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 54
lcom 1
cbo 9
dl 127
loc 551
rs 7.0642
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
modelClass() 0 1 ?
A modelClassInstance() 0 4 1
A create() 23 23 3
A createFromRecord() 0 19 3
B findAll() 24 24 4
A getAll() 0 12 2
B find() 0 22 4
A get() 0 13 2
A findAllByQuery() 12 12 2
A findByQuery() 11 11 2
A findAllByCondition() 0 17 3
A getAllByCondition() 0 12 2
A findByCondition() 11 11 2
A getByCondition() 0 12 2
A findAllByCriteria() 18 18 3
A getAllByCriteria() 0 12 2
A findByCriteria() 11 11 2
A getByCriteria() 0 12 2
A findByRecord() 17 17 2
A getByRecord() 0 4 1
A findRecordByModel() 0 4 1
A getRecordByModel() 0 12 2
A findCache() 0 12 2
A findCacheByRecord() 0 4 1
A addToCache() 0 4 1
A notFoundException() 0 10 1
A notFoundByCriteriaException() 0 11 1
A notFoundByConditionException() 0 11 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Model 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 Model, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipbox/spark/blob/master/LICENSE
6
 * @link       https://github.com/flipbox/spark
7
 */
8
9
namespace flipbox\spark\services;
10
11
use craft\helpers\Json as JsonHelper;
12
use flipbox\spark\exceptions\ModelNotFoundException;
13
use flipbox\spark\exceptions\RecordNotFoundException;
14
use flipbox\spark\helpers\ArrayHelper;
15
use flipbox\spark\helpers\ModelHelper;
16
use flipbox\spark\models\Model as BaseModel;
17
use flipbox\spark\records\Record;
18
use yii\base\Component;
19
use yii\base\InvalidConfigException;
20
use yii\db\QueryInterface;
21
22
/**
23
 * @author Flipbox Factory <[email protected]>
24
 * @since 1.0.0
25
 */
26
abstract class Model extends Component
27
{
28
29
    use traits\Model;
30
31
    /**
32
     * @var BaseModel[]
33
     */
34
    protected $_cacheAll;
35
36
37
    /*******************************************
38
     * MODEL CLASSES
39
     *******************************************/
40
41
    /**
42
     * @return string
43
     */
44
    public abstract static function modelClass(): string;
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
45
46
    /**
47
     * @return string
48
     */
49
    public static function modelClassInstance(): string
50
    {
51
        return BaseModel::class;
52
    }
53
54
    /*******************************************
55
     * CREATE
56
     *******************************************/
57
58
    /**
59
     * @param array $config
60
     * @param string|null $toScenario
61
     * @throws InvalidConfigException
62
     * @return BaseModel
63
     */
64 View Code Duplication
    public function create($config = [], string $toScenario = null): BaseModel
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
65
    {
66
67
        // Treat records as known data and set via config
68
        if ($config instanceof Record) {
69
            return $this->createFromRecord($config, $toScenario);
70
        }
71
72
        // Force Array
73
        if (!is_array($config)) {
74
            $config = ArrayHelper::toArray($config, [], false);
75
        }
76
77
        // Set the model class
78
        $config['class'] = static::modelClass();
79
80
        return ModelHelper::create(
81
            $config,
82
            static::modelClassInstance(),
83
            $toScenario
84
        );
85
86
    }
87
88
    /**
89
     * @param Record $record
90
     * @param string|null $toScenario
91
     * @throws InvalidConfigException
92
     * @return BaseModel
93
     */
94
    protected function createFromRecord(Record $record, string $toScenario = null): BaseModel
95
    {
96
97
        if (null !== $toScenario) {
98
            $record->setScenario($toScenario);
99
        }
100
101
        $modelClass = static::modelClass();
102
103
        /** @var BaseModel $model */
104
        $model = new $modelClass($record);
105
106
        if (null !== $toScenario) {
107
            $model->setScenario($toScenario);
108
        }
109
110
        return $model;
111
112
    }
113
114
    /*******************************************
115
     * FIND/GET ALL
116
     *******************************************/
117
118
    /**
119
     * @param string $toScenario
120
     * @return BaseModel[]
121
     */
122 View Code Duplication
    public function findAll(string $toScenario = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
    {
124
125
        // Check addToCache
126
        if (is_null($this->_cacheAll)) {
127
128
            $this->_cacheAll = [];
129
130
            // Find record in db
131
            if ($records = $this->findAllRecords()) {
132
133
                foreach ($records as $record) {
134
135
                    $this->_cacheAll[] = $this->findByRecord($record, $toScenario);
136
137
                }
138
139
            }
140
141
        }
142
143
        return $this->_cacheAll;
144
145
    }
146
147
    /**
148
     * @param string $toScenario
149
     * @return BaseModel[]
150
     * @throws ModelNotFoundException
151
     */
152
    public function getAll(string $toScenario = null): array
153
    {
154
155
        if (!$models = $this->findAll($toScenario)) {
156
157
            $this->notFoundException();
158
159
        }
160
161
        return $models;
162
163
    }
164
165
    /*******************************************
166
     * FIND/GET
167
     *******************************************/
168
169
    /**
170
     * @param $identifier
171
     * @param string $toScenario
172
     * @return BaseModel|null
173
     */
174
    public function find($identifier, string $toScenario = null)
175
    {
176
177
        if ($identifier instanceof BaseModel) {
178
179
            $this->addToCache($identifier);
180
181
            if (null !== $toScenario) {
182
                $identifier->setScenario($toScenario);
183
            }
184
185
            return $identifier;
186
187
        } elseif ($identifier instanceof Record) {
188
189
            return $this->findByRecord($identifier, $toScenario);
190
191
        }
192
193
        return null;
194
195
    }
196
197
    /**
198
     * @param $identifier
199
     * @param string $toScenario
200
     * @return BaseModel
201
     * @throws ModelNotFoundException
202
     */
203
    public function get($identifier, string $toScenario = null): BaseModel
204
    {
205
206
        // Find model by ID
207
        if (!$model = $this->find($identifier, $toScenario)) {
208
209
            $this->notFoundException();
210
211
        }
212
213
        return $model;
214
215
    }
216
217
    /*******************************************
218
     * FIND/GET BY QUERY
219
     *******************************************/
220
221
    /**
222
     * @param QueryInterface $query
223
     * @param string $toScenario
224
     * @return BaseModel[]
225
     */
226 View Code Duplication
    public function findAllByQuery(QueryInterface $query, string $toScenario = null): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
    {
228
229
        $models = array();
230
231
        foreach ($query->all() as $record) {
232
            $models[] = $this->findByRecord($record, $toScenario);
233
        }
234
235
        return $models;
236
237
    }
238
239
    /**
240
     * @param QueryInterface $query
241
     * @param string $toScenario
242
     * @return BaseModel|null
243
     */
244 View Code Duplication
    public function findByQuery(QueryInterface $query, string $toScenario = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
    {
246
247
        /** @var Record $record */
248
        if (!$record = $query->one()) {
249
            return null;
250
        }
251
252
        return $this->findByRecord($record, $toScenario);
0 ignored issues
show
Documentation introduced by
$record is of type array|boolean, but the function expects a object<flipbox\spark\records\Record>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
253
254
    }
255
256
    /*******************************************
257
     * FIND/GET BY CONDITION
258
     *******************************************/
259
260
    /**
261
     * @param $condition
262
     * @param string $toScenario
263
     * @return BaseModel[]
264
     */
265
    public function findAllByCondition($condition, string $toScenario = null): array
266
    {
267
268
        $models = [];
269
270
        // Find record in db
271
        if ($records = $this->findAllRecordsByCondition($condition)) {
272
273
            foreach ($records as $record) {
274
                $models[] = $this->findByRecord($record, $toScenario);
275
            }
276
277
        }
278
279
        return $models;
280
281
    }
282
283
    /**
284
     * @param $condition
285
     * @param string $toScenario
286
     * @return BaseModel[]
287
     * @throws ModelNotFoundException
288
     */
289
    public function getAllByCondition($condition, string $toScenario = null): array
290
    {
291
292
        if (!$models = $this->findAllByCondition($condition, $toScenario)) {
293
294
            $this->notFoundByConditionException($condition);
295
296
        }
297
298
        return $models;
299
300
    }
301
302
    /**
303
     * @param $condition
304
     * @param string $toScenario
305
     * @return BaseModel|null
306
     */
307 View Code Duplication
    public function findByCondition($condition, string $toScenario = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
    {
309
310
        // Find record in db
311
        if ($record = $this->findRecordByCondition($condition)) {
312
            return $this->findByRecord($record, $toScenario);
313
        }
314
315
        return null;
316
317
    }
318
319
    /**
320
     * @param $condition
321
     * @param string $toScenario
322
     * @return BaseModel
323
     * @throws ModelNotFoundException
324
     */
325
    public function getByCondition($condition, string $toScenario = null): BaseModel
326
    {
327
328
        if (!$model = $this->findByCondition($condition, $toScenario)) {
329
330
            $this->notFoundByConditionException($condition);
331
332
        }
333
334
        return $model;
335
336
    }
337
338
    /*******************************************
339
     * FIND/GET BY CRITERIA
340
     *******************************************/
341
342
    /**
343
     * @param $criteria
344
     * @param string $toScenario
345
     * @return BaseModel[]
346
     */
347 View Code Duplication
    public function findAllByCriteria($criteria, string $toScenario = null): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
348
    {
349
350
        $models = [];
351
352
        // Find record in db
353
        if ($records = $this->findAllRecordsByCriteria($criteria)
354
        ) {
355
356
            foreach ($records as $record) {
357
                $models[] = $this->findByRecord($record, $toScenario);
358
            }
359
360
        }
361
362
        return $models;
363
364
    }
365
366
    /**
367
     * @param $criteria
368
     * @param string $toScenario
369
     * @return BaseModel[]
370
     * @throws ModelNotFoundException
371
     */
372
    public function getAllByCriteria($criteria, string $toScenario = null): array
373
    {
374
375
        if (!$models = $this->findAllByCriteria($criteria, $toScenario)) {
376
377
            $this->notFoundByCriteriaException($criteria);
378
379
        }
380
381
        return $models;
382
383
    }
384
385
    /**
386
     * @param $criteria
387
     * @param string $toScenario
388
     * @return BaseModel|null
389
     */
390 View Code Duplication
    public function findByCriteria($criteria, string $toScenario = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
391
    {
392
393
        // Find record in db
394
        if ($record = $this->findRecordByCriteria($criteria)) {
395
            return $this->findByRecord($record, $toScenario);
396
        }
397
398
        return null;
399
400
    }
401
402
    /**
403
     * @param $criteria
404
     * @param string $toScenario
405
     * @return BaseModel
406
     * @throws ModelNotFoundException
407
     */
408
    public function getByCriteria($criteria, string $toScenario = null): BaseModel
409
    {
410
411
        if (!$model = $this->findByCriteria($criteria, $toScenario)) {
412
413
            $this->notFoundByCriteriaException($criteria);
414
415
        }
416
417
        return $model;
418
419
    }
420
421
422
    /*******************************************
423
     * FIND/GET BY RECORD
424
     *******************************************/
425
426
    /**
427
     * @param Record $record
428
     * @param string $toScenario
429
     * @return BaseModel
430
     */
431 View Code Duplication
    public function findByRecord(Record $record, string $toScenario = null): BaseModel
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
432
    {
433
434
        // Check addToCache
435
        if (!$model = $this->findCacheByRecord($record)) {
436
437
            // New model
438
            $model = $this->createFromRecord($record, $toScenario);
439
440
            // Cache it
441
            $this->addToCache($model);
442
443
        }
444
445
        return $model;
446
447
    }
448
449
    /**
450
     * @param Record $record
451
     * @param string $toScenario
452
     * @return BaseModel
453
     */
454
    public function getByRecord(Record $record, string $toScenario = null): BaseModel
455
    {
456
        return $this->findByRecord($record, $toScenario);
457
    }
458
459
    /**
460
     * @param BaseModel $model
461
     * @return Record|null
462
     */
463
    public function findRecordByModel(BaseModel $model)
464
    {
465
        return null;
466
    }
467
468
    /**
469
     * @param BaseModel $model
470
     * @return Record
471
     * @throws RecordNotFoundException
472
     */
473
    public function getRecordByModel(BaseModel $model)
474
    {
475
476
        if (!$record = $this->findRecordByModel($model)) {
477
478
            throw new RecordNotFoundException("Record does not exist found.");
479
480
        }
481
482
        return $record;
483
484
    }
485
486
    /*******************************************
487
     * CACHE
488
     *******************************************/
489
490
    /**
491
     * @param $identifier
492
     * @return BaseModel|null
493
     */
494
    public function findCache($identifier)
495
    {
496
497
        if ($identifier instanceof Record) {
498
499
            return $this->findCacheByRecord($identifier);
500
501
        }
502
503
        return null;
504
505
    }
506
507
    /**
508
     * @param Record $record
509
     * @return BaseModel|null
510
     */
511
    public function findCacheByRecord(Record $record)
512
    {
513
        return null;
514
    }
515
516
    /**
517
     * @param BaseModel $model
518
     * @return static
519
     */
520
    public function addToCache(BaseModel $model)
521
    {
522
        return $this;
523
    }
524
525
526
    /*******************************************
527
     * EXCEPTIONS
528
     *******************************************/
529
530
    /**
531
     * @throws ModelNotFoundException
532
     */
533
    protected function notFoundException()
534
    {
535
536
        throw new ModelNotFoundException(
537
            sprintf(
538
                "Model does not exist."
539
            )
540
        );
541
542
    }
543
544
    /**
545
     * @param null $criteria
546
     * @throws ModelNotFoundException
547
     */
548
    protected function notFoundByCriteriaException($criteria = null)
549
    {
550
551
        throw new ModelNotFoundException(
552
            sprintf(
553
                'Model does not exist with the criteria "%s".',
554
                (string)JsonHelper::encode($criteria)
555
            )
556
        );
557
558
    }
559
560
    /**
561
     * @param null $condition
562
     * @throws ModelNotFoundException
563
     */
564
    protected function notFoundByConditionException($condition = null)
565
    {
566
567
        throw new ModelNotFoundException(
568
            sprintf(
569
                'Model does not exist with the condition "%s".',
570
                (string)JsonHelper::encode($condition)
571
            )
572
        );
573
574
    }
575
576
}
577