Passed
Branch master (fc6eea)
by Henri
02:26 queued 01:04
created

Datamanager   F

Complexity

Total Complexity 112

Size/Duplication

Total Lines 506
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 268
c 5
b 0
f 0
dl 0
loc 506
rs 2
wmc 112

26 Methods

Rating   Name   Duplication   Size   Complexity  
A deny() 0 6 2
D mountData() 0 73 30
A find() 0 9 2
A toEntity() 0 18 4
B remove() 0 37 6
A first() 0 3 2
B save() 0 29 7
A removeById() 0 7 1
B execute() 0 56 10
A getData() 0 3 1
A check_where_array() 0 8 4
A getCount() 0 3 1
A findById() 0 4 1
A __set() 0 17 4
A __get() 0 7 3
A create() 0 11 1
A setByDatabase() 0 19 3
A persist() 0 37 5
A result() 0 3 1
A toJson() 0 12 3
A where() 0 20 4
A orderBy() 0 12 5
A except() 0 13 4
A offset() 0 8 2
A only() 0 13 5
A limit() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Datamanager 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.

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 Datamanager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace HnrAzevedo\Datamanager;
4
5
use Exception;
6
7
abstract class Datamanager
8
{
9
    use CrudTrait;
10
11
    private ?string $table = null;
12
    private ?string $primary = null;
13
    private array $result = [];
14
    protected array $data = [];
15
    
16
    private bool $full = false;
17
    private ?string $clause = null;
18
19
20
    private array $where = [''=> ["1",'=',"1"] ];
21
    private ?string $order = null;
22
    private ?string $limit = null;
23
    private ?int $offset = null;
24
    private array $excepts = [];
25
    private int $count = 0;
26
    private array $select = [];
27
    private ?string $query = null;
28
29
30
    protected function create(string $table, string $primary): Datamanager
31
    {
32
        $this->table = $table;
33
        $this->primary = $primary;
34
        $describe = $this->describe();
35
        
36
        $this->check_fail();
37
38
        $this->mountData($describe);
0 ignored issues
show
Bug introduced by
It seems like $describe can also be of type null; however, parameter $table of HnrAzevedo\Datamanager\Datamanager::mountData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

38
        $this->mountData(/** @scrutinizer ignore-type */ $describe);
Loading history...
39
        $this->full = true;
40
        return $this;
41
    }
42
43
    private function mountData(array $table): Datamanager
44
    {
45
        foreach ($table as $column) {
46
            $field = null;
47
            foreach ($column as $propriety => $value) {
48
                switch ($propriety) {
49
                    case 'Field':
50
                        $field = $value;
51
                        $this->$field = null;
52
                        break;
53
                    case 'Type':
54
                        $type = $value;
55
56
                        if(strpos($value,'(')){
57
                            switch (substr($value,0,strpos($value,'('))) {
58
                                case 'varchar':
59
                                case 'char':
60
                                case 'text': $type = 'string'; break;
61
                                case 'tinyint':
62
                                case 'mediumint':
63
                                case 'smallint':
64
                                case 'bigint':
65
                                case 'int': $type = 'int'; break;
66
                                case 'decimal':
67
                                case 'float':
68
                                case 'double':
69
                                case 'real': $type = 'float'; break;
70
                                default: $type = $value; break;
71
                            }
72
                        }
73
74
                        switch ($type) {
75
                            case 'string':
76
                            case 'float':
77
                            case 'int':
78
                                $this->$field = ['maxlength' => substr($value,(strpos($value,'(')+1),-1) ]; 
79
                                break;
80
                            case 'date':
81
                                $this->$field = ['maxlength' => 10];
82
                                break;
83
                            case 'datetime':
84
                                $this->$field = ['maxlength' => 19];
85
                                break;
86
                            case 'boolean':
87
                                $this->$field = ['maxlength' => 1];
88
                                break;
89
                            default:
90
                                $this->$field = ['maxlength' => null];
91
                                break;
92
                        }
93
94
                        $this->$field = ['type' => $type];
95
                        break;
96
                    case 'Null':
97
                        $this->$field = ['null' => ($value === 'YES') ? 1 : 0];
98
                        break;
99
                    case 'Key':
100
                        $this->$field = ['key' => $value];
101
                        $this->$field = ['upgradeable' => ($value == 'PRI') ? 0 : 1];
102
                        break;
103
                    case 'Extra':
104
                        $this->$field = ['extra' => $value];
105
                        break;
106
                    case 'Default':
107
                        $this->$field = ['default' => $value];
108
                        $this->$field = ['value' => null];
109
                        $this->$field = ['changed' => false];
110
                        $this->select[$field] = true;
111
                        break;
112
                }
113
            }
114
        }
115
        return $this;
116
    }
117
118
    public function __set(string $prop,$value): Datamanager
119
    {
120
121
        if(is_array($value)){
122
            $attr = array_keys($value)[0];
123
            $this->data[$prop][$attr] = $value[$attr];
124
            return $this;
125
        }
126
127
        if($this->full && !array_key_exists($prop,$this->data)){
128
            throw new Exception("{$prop} field does not exist in the table {$this->table}.");
129
        }
130
131
        $this->data[$prop]['changed'] = true;
132
        $this->data[$prop]['value'] = $value;
133
        
134
        return $this;
135
    }
136
137
    public function getData(): ?array
138
    {
139
        return $this->data;
140
    }
141
142
    public function __get(string $field)
143
    {
144
        if($this->full && !array_key_exists($field,$this->data)){
145
            throw new Exception("{$field} field does not exist in the table {$this->table}.");
146
        }
147
148
        return $this->data[$field]['value'];
149
    }
150
151
    public function getCount(): int
152
    {
153
        return $this->count;
154
    }
155
156
    public function except($deniable): Datamanager
157
    {
158
        $deniable = (is_array($deniable)) ? $deniable : [$deniable];
159
160
        foreach ($deniable as $field) {
161
            if(!array_key_exists($field,$this->data)){
162
                throw new Exception("{$field} field does not exist in the table {$this->table}.");
163
            }
164
165
            $this->excepts[$field] = true;
166
        }
167
168
        return $this;
169
    }
170
171
    public function deny(): Datamanager
172
    {
173
        foreach ($this->excepts as $field => $value) {
174
            unset($this->select[$field]);
175
        }
176
        return $this;
177
    }
178
179
    public function orderBy(string $field, string $ord = 'ASC'): Datamanager
180
    {
181
        if(!array_key_exists(str_replace(['asc','ASC','desc','DESC',' '],'',$field),$this->data) && $this->full){
182
            throw new Exception("{$field} field does not exist in the table {$this->table}.");
183
        }
184
185
        if(strpos(strtolower($field),'asc') || strpos(strtolower($field),'desc')){
186
            $ord = '';
187
        }
188
189
        $this->order = " ORDER BY {$field} {$ord} ";
190
        return $this;
191
    }
192
193
    public function only($params): Datamanager
194
    {
195
        $params = (is_array($params)) ? $params : [$params];
196
        $this->select = [];
197
        foreach ($params as $field) {
198
            if(!array_key_exists($field,$this->data) && $this->full){
199
                throw new Exception("{$field} field does not exist in the table {$this->table}.");
200
            }
201
202
            $this->select[$field] = true;
203
        }
204
205
        return $this;
206
    }
207
208
    public function where(array $where): Datamanager
209
    {
210
        $this->where['AND'] = (array_key_exists('AND',$this->where)) ?? '';
211
        $w = [];
212
        foreach ($where as $condition => $values) {
213
214
            if(!is_array($values)){
215
                $w['AND'][] = $values;
216
                continue;
217
            }
218
219
            $this->check_where_array($values);
220
221
            $w[(is_int($condition) ? 'AND' : $condition)][] = $values;
222
                       
223
        }
224
225
        $this->where = array_merge($this->where,$w);
226
227
        return $this;
228
    }
229
230
    public function check_where_array(array $where)
231
    {
232
        if(count($where) != 3){
233
            throw new Exception("Condition where set incorrectly: ".implode(' ',$where));
234
        }
235
236
        if(!array_key_exists($where[0],$this->data) && $this->full){
237
            throw new Exception("{$where[0]} field does not exist in the table {$this->table}.");
238
        }
239
    }
240
241
    public function limit(string $limit): Datamanager
242
    {
243
        $this->limit = $limit;
244
        return $this;
245
    }
246
247
    public function offset(int $offset): Datamanager
248
    {
249
        if(is_null($this->limit)){
250
            throw new Exception("The limit must be set before the offset.");
251
        }
252
253
        $this->offset = $offset;
254
        return $this;
255
    }
256
257
    public function result(): array
258
    {
259
        return $this->result;
260
    }
261
262
    public function first(): Datamanager
263
    {
264
        return  (count($this->result) > 0) ? $this->setByDatabase($this->result[0]) : $this;
265
    }
266
267
    public function setByDatabase(array $arrayValues): Datamanager
268
    {
269
        $clone = clone $this;
270
        
271
        $clone->result = [
272
            0 => $this->result[0]
273
        ];
274
275
        $clone->count = 1;
276
277
        foreach ($arrayValues as $key => $value) {
278
279
            if(!array_key_exists($key,$this->data)){
280
                throw new Exception("{$key} field does not exist in the table {$this->table}.");
281
            }
282
283
            $clone->data[$key]['value'] = $value;
284
        }
285
        return $clone;
286
    }
287
288
    public function toJson(): string
289
    {
290
        $string = '';
291
        foreach ($this->data as $key => $value) {
292
293
            if(gettype($value)==='object'){
294
                $value = $value->getData()[$this->primary]['value'];
295
            }
296
297
            $string .= '"'.$key.'"'.':"'.$value.'",';
298
        }
299
        return str_replace(',}', '}', '{'.$string.'}');
300
    }
301
302
    public function remove(?bool $exec = false): Datamanager
303
    {
304
        if($exec){
305
            $this->clause = null;
306
307
            if(count($this->where) == 1){
308
                $this->removeById();
309
                return $this;
310
            }
311
312
            $where = '';
313
            $data = '';
314
            foreach($this->where as $clause => $condition){
315
                if(strlen($clause) === 0){
316
                    $where .= " {$clause} ";
317
                    $where .= " {$condition[0]} {$condition[1]} :q_{$condition[0]} ";
318
                    $data .= "q_{$condition[0]}={$condition[2]}&";
319
                    continue;
320
                }
321
                
322
                foreach($condition as $column => $value){
323
                    $where .= " {$clause} ";
324
                    $where .= " {$value[0]} {$value[1]} :q_{$value[0]} ";
325
                    $data .= "q_{$value[0]}={$value[2]}&";
326
                }
327
            }
328
329
            $this->delete($where, substr($data,0,-1) );
330
331
            $this->check_fail();
332
            
333
            return $this;
334
        }
335
336
        $this->clause = 'remove';
337
        
338
        return $this;
339
    }
340
341
    private function removeById(): bool
342
    {
343
        $delete = $this->delete("{$this->primary}=:{$this->primary}","{$this->primary}={$this->getData()[$this->primary]['value']}");
344
345
        $this->check_fail();
346
347
        return $delete;
348
    }
349
350
    public function save(): Datamanager
351
    {
352
        $data = [];
353
        foreach ($this->data as $key => $value) {
354
            if($this->data[$key]['key'] === 'PRI' || strstr($this->data[$key]['extra'],'auto_increment')){
355
                continue;
356
            }
357
358
            if($this->data[$key]['changed'] && $this->data[$key]['upgradeable']){
359
                $data[$key] = $this->data[$key]['value'];
360
            }
361
        }
362
363
        $terms = "{$this->primary}=:{$this->primary}";
364
        $params = $this->primary.'='.$this->getData()[$this->primary]['value'];
365
366
        $this->transaction('begin');
367
        try{
368
            $this->update($data, $terms, $params);
369
370
            $this->check_fail();
371
372
            $this->transaction('commit');
373
        }catch(Exception $er){
374
            $this->transaction('rollback');
375
            throw $er;
376
        }
377
378
        return $this;
379
    }
380
381
    public function persist(): Datamanager
382
    {
383
        $columns = '';
384
        $values = '';
385
        $data = [];
386
387
        foreach ($this->data as $key => $value) {
388
            if(strstr($this->data[$key]['extra'],'auto_increment')){
389
                continue;
390
            }
391
392
            if(strlen($value['value']) > $value['maxlength']){
393
                throw new Exception("The information provided for column {$key} of table {$this->table} exceeded that allowed.");
394
            }
395
396
            $columns .= $key.',';
397
            $values .= ':'.$key.',';
398
            $data[$key] = $value['value'];
399
        }
400
401
        $this->transaction('begin');
402
        try{
403
           
404
            $id = $this->insert($data);
405
406
            $this->check_fail();
407
408
            $this->getData()[$this->primary]['value'] = $id;
409
            
410
            $this->transaction('commit');
411
412
        }catch(Exception $er){
413
            $this->transaction('rollback');
414
            throw $er;
415
        }
416
417
        return $this;
418
    }
419
420
    public function toEntity()
421
    {
422
        $entity = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $entity is dead and can be removed.
Loading history...
423
424
        if($this->getCount() === 0){
425
            return null;
426
        }
427
428
        $entity = $this->setByDatabase($this->result[0]);
429
430
        if(count($this->result) > 1){
431
            $entity = [];
432
            foreach ($this->result as $key => $value) {
433
                $entity[] = $this->setByDatabase($value);
434
            }
435
        }
436
437
        return $entity;
438
    }
439
440
    public function findById($id): Datamanager
441
    {
442
        $this->where([$this->primary,'=',$id]);
443
        return $this;
444
    }
445
446
    public function execute(): Datamanager
447
    {
448
        if(!is_null($this->clause)){
449
            if($this->clause == 'remove'){
450
                return $this->remove(true);
451
            }
452
        }
453
454
        $this->deny();
455
        $select = '';
456
457
        foreach ($this->select as $key => $value) {
458
            $select .= "{$key},";
459
        }
460
        
461
        $select = substr($select,0,-1);
462
        $this->query = str_replace("*",$select,$this->query);
463
464
        $where = '';
465
        $whereData = [];
466
        foreach ($this->where as $key => $value) {
467
            $key = (!$key) ? '' : " {$key} ";
468
469
            
470
            if(is_array($value[0])){
471
                foreach ($value as $k => $v) {
472
                    $where .= " {$key} {$v[0]} {$v[1]} :q_{$v[0]} ";
473
                    $whereData["q_{$v[0]}"] = $v[2];
474
                }
475
            }else{
476
                $where .= " {$key} {$value[0]} {$value[1]} :q_{$value[0]} ";
477
                $whereData["q_{$value[0]}"] = $value[2];
478
            }
479
480
        }
481
        $where = substr($where,0,-1);
482
        $this->query .= " WHERE {$where} ";
483
484
        $this->query .= $this->order;
485
486
        if(!is_null($this->limit)){
487
            $this->query .= " LIMIT {$this->limit}";
488
        }
489
490
        if(!is_null($this->offset)){
491
            $this->query .= " OFFSET {$this->offset}";
492
        }
493
494
        $this->result = $this->select($this->query,$whereData);
495
496
        $this->check_fail();
497
498
        $this->count = count($this->result);
499
        $this->query = null;
500
501
        return $this;
502
    }
503
504
    public function find(?int $key = null): Datamanager
505
    {
506
        $this->query = " SELECT * FROM {$this->table} ";
507
508
        if(is_int($key)){
509
            return $this->findById($key);
510
        }
511
512
        return $this;
513
    }
514
515
}
516