Passed
Push — main ( 7af8ef...b09946 )
by Pranjal
02:54
created

Model::set()   D

Complexity

Conditions 20
Paths 68

Size

Total Lines 63
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 20
eloc 41
c 3
b 1
f 0
nc 68
nop 2
dl 0
loc 63
rs 4.1666

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
declare(strict_types=1);
3
namespace Scrawler\Arca;
4
5
use Scrawler\Arca\Connection;
6
use Doctrine\DBAL\Types\Type;
7
8
9
/**
10
 * Model class that represents single record in database
11
 */
12
class Model
13
{
14
    /**
15
     * Store all properties of model
16
     * @var array<string,mixed>
17
     */
18
    private array $__properties = array();
19
20
    /**
21
     * Store all properties with all relation
22
     * @var array<string,mixed>
23
     */
24
    private array $__props = array();
25
26
27
    /**
28
     * Store all types of properties
29
     * @var array<string,mixed>
30
     */
31
    private array $__types = array();
32
33
    /**
34
     * Store the table name of model
35
     * @var string
36
     */
37
    private string $table;
38
    /**
39
     * Store the metadata of model
40
     * @var array<string,mixed>
41
     */
42
    private array $__meta = [];
43
    /**
44
     * Store the connection
45
     * @var Connection
46
     */
47
    private Connection $connection;
48
49
50
    /**
51
     * Create a new model
52
     * @param string $name
53
     * @param Connection $connection
54
     */
55
    public function __construct(string $name,Connection $connection)
56
    {
57
58
        $this->table = $name;
59
        $this->connection = $connection;
60
        $this->__meta['has_foreign']['oto'] = false;
61
        $this->__meta['has_foreign']['otm'] = false;
62
        $this->__meta['has_foreign']['mtm'] = false;
63
        $this->__meta['is_loaded'] = false;
64
        $this->__meta['id_error'] = false;
65
        $this->__meta['foreign_models']['otm'] = [];
66
        $this->__meta['foreign_models']['oto'] = [];
67
        $this->__meta['foreign_models']['mtm'] = [];
68
        $this->__meta['id'] = 0;
69
    }
70
71
    /**
72
     * adds the key to properties
73
     * @param string $key
74
     * @param mixed $val
75
     * @return void
76
     */
77
    public function __set(string $key, mixed $val): void
78
    {
79
        $this->set($key, $val);
80
    }
81
82
    /**
83
     * Adds the key to properties
84
     * @param string $key
85
     * @param mixed $val
86
     * @return void
87
     */
88
    public function set(string $key, mixed $val): void
89
    {
90
        if ($key === 'id') {
91
            $this->__meta['id'] = $val;
92
            $this->__meta['id_error'] = true;
93
        }
94
95
96
        if (\Safe\preg_match('/[A-Z]/', $key)) {
97
            $parts = \Safe\preg_split('/(?=[A-Z])/', $key, -1, PREG_SPLIT_NO_EMPTY);
98
            if (strtolower($parts[0]) === 'own') {
99
                if (gettype($val) === 'array' || $val instanceof Collection) {
100
                    $this->checkModelArray($val);
101
                    array_push($this->__meta['foreign_models']['otm'], $val);
102
                    $this->__meta['has_foreign']['otm'] = true;
103
                    if(is_array($val) && !($val instanceof Collection)){
104
                        $val = Collection::fromIterable($val);
105
                    }
106
                    $this->__props[$key] = $val;
107
                }
108
                return;
109
            }
110
            if (strtolower($parts[0]) === 'shared') {
111
                if (gettype($val) ==='array' || $val instanceof Collection) {
112
                    $this->checkModelArray($val);
113
                    array_push($this->__meta['foreign_models']['mtm'], $val);
114
                    $this->__meta['has_foreign']['mtm'] = true;
115
                    if(is_array($val) && !($val instanceof Collection)){
116
                        $val = Collection::fromIterable($val);
117
                    }
118
                    $this->__props[$key] = $val;
119
                }
120
                return;
121
            }
122
        }
123
        if ($val instanceof Model) {
124
            if(isset($this->__props[$key.'_id'])){
125
                unset($this->__props[$key.'_id']);
126
            }
127
            $this->__meta['has_foreign']['oto'] = true;
128
            array_push($this->__meta['foreign_models']['oto'], $val);
129
            $this->__props[$key] = $val;
130
            return;
131
        }
132
133
        $type = gettype($val);
134
135
        if (gettype($val) == 'boolean') {
136
            ($val) ? $val = 1 : $val = 0;
137
        }
138
139
        if($type == 'array' || $type == 'object'){
140
            $val = Type::getType('json_document')->convertToDatabaseValue($val, $this->connection->getDatabasePlatform());
0 ignored issues
show
Bug introduced by
The method getDatabasePlatform() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

140
            $val = Type::getType('json_document')->convertToDatabaseValue($val, $this->connection->/** @scrutinizer ignore-call */ getDatabasePlatform());
Loading history...
141
            $type = 'json_document';
142
        }
143
144
        if($type == 'string'){
145
            $type = 'text';
146
        }
147
148
        $this->__properties[$key] = $val;
149
        $this->__props[$key] = $val;
150
        $this->__types[$key] = $type;
151
152
    }
153
154
    /**
155
     * Check if array passed is instance of model
156
     * @param array<mixed>|Collection $models
157
     * @throws \Scrawler\Arca\Exception\InvalidModelException
158
     * @return void
159
     */
160
    private function checkModelArray(array|Collection $models):void{
161
        if($models instanceof Collection){
0 ignored issues
show
introduced by
$models is never a sub-type of Scrawler\Arca\Collection.
Loading history...
162
            return;
163
        }
164
165
        if (count(array_filter($models, fn($d) => !$d instanceof Model)) > 0) {
166
            throw new Exception\InvalidModelException();
167
        }
168
    }
169
170
    /**
171
     * Get a key from properties, keys can be relational
172
     * like sharedList,ownList or foreign table
173
     * @param string $key
174
     * @return mixed
175
     */
176
    public function __get(string $key): mixed
177
    {
178
        return $this->get($key);
179
    }
180
181
    /**
182
     * Get a key from properties, keys can be relational
183
     * like sharedList,ownList or foreign table
184
     * @param string $key
185
     * @return mixed
186
     */
187
    public function get(string $key) : mixed
188
    {
189
        if (\Safe\preg_match('/[A-Z]/', $key)) {
190
            $parts = \Safe\preg_split('/(?=[A-Z])/', $key, -1, PREG_SPLIT_NO_EMPTY);
191
            if (strtolower($parts[0]) == 'own') {
192
                if (strtolower($parts[2]) == 'list') {
193
                    $result = $this->connection->getRecordManager()->find(strtolower($parts[1]))->where($this->getName() . '_id = "' . $this->__meta['id'] . '"')->get();
194
                    $this->set($key, $result);
195
                    return $result;
196
                }
197
            }
198
            if (strtolower($parts[0]) == 'shared') {
199
                if (strtolower($parts[2]) == 'list') {
200
                    $rel_table = $this->connection->getTableManager()->tableExists($this->table . '_' . strtolower($parts[1])) ? $this->table . '_' . strtolower($parts[1]) : strtolower($parts[1]) . '_' . $this->table;
201
                    $relations = $this->connection->getRecordManager()->find($rel_table)->where($this->getName() . '_id = "' . $this->__meta['id'] . '"')->get();
202
                    $rel_ids = '';
203
                    foreach ($relations as $relation) {
204
                        $key = strtolower($parts[1]) . '_id';
205
                        $rel_ids .= "'" . $relation->$key . "',";
206
                    }
207
                    $rel_ids = substr($rel_ids, 0, -1);
208
                    $result = $this->connection->getRecordManager()->find(strtolower($parts[1]))->where('id IN (' . $rel_ids . ')')->get();
209
                    $this->set($key, $result);
210
                    return $result;
211
                }
212
            }
213
        }
214
215
        if (array_key_exists($key . '_id', $this->__properties)) {
216
            $result = $this->connection->getRecordManager()->getById($key, $this->__properties[$key . '_id']);
217
            $this->set($key, $result);
218
            return $result;
219
        }
220
221
        if (array_key_exists($key, $this->__properties)) {
222
            $type = Type::getType($this->connection->getTableManager()->getTable($this->table)->getColumn($key)->getComment());
223
            $result = $type->convertToPHPValue($this->__properties[$key], $this->connection->getDatabasePlatform());
224
            $this->set($key, $result);
225
            return $result;
226
        }
227
228
        throw new Exception\KeyNotFoundException();
229
    }
230
231
    /**
232
     * Eager Load relation variable
233
     * @param array<string> $relations
234
     * @return Model
235
     */
236
    public function with(array $relations) : Model
237
    {
238
        foreach ($relations as $relation) {
239
            $this->get($relation);
240
        }
241
        return $this;
242
    }
243
244
245
    /**
246
     * Unset a property from model
247
     * @param string $key
248
     * @return void
249
     */
250
    public function __unset(string $key): void
251
    {
252
        $this->unset($key);
253
    }
254
255
    /**
256
     * Unset a property from model
257
     * @param string $key
258
     * @return void
259
     */
260
    public function unset(string $key): void
261
    {
262
        unset($this->__properties[$key]);
263
        unset($this->__props[$key]);
264
    }
265
266
    /**
267
     * Check if property exists
268
     * @param string $key
269
     * @return bool
270
     */
271
    public function __isset(string $key): bool
272
    {
273
        return $this->isset($key);
274
    }
275
276
    /**
277
     * Check if property exists
278
     *
279
     * @param string $key
280
     * @return bool
281
     */
282
    public function isset(string $key): bool
283
    {
284
        return array_key_exists($key, $this->__props);
285
    }
286
287
    /**
288
     * Set all properties of model via array
289
     * @param array<mixed> $properties
290
     * @return Model
291
     */
292
    public function setProperties(array $properties): Model
293
    {
294
        foreach ($properties as $key => $value) {
295
            $this->set($key, $value);
296
        }
297
        return $this;
298
    }
299
300
    /**
301
     * Set all properties of model loaded via database
302
     * @param array<mixed> $properties
303
     * @return Model
304
     */
305
    public function setLoadedProperties(array $properties): Model
306
    {
307
        $this->__properties = $properties;
308
        $this->__props = $properties;
309
        foreach ($properties as $key => $value) {
310
            $this->__types[$key] = $this->connection->getTableManager()->getTable($this->table)->getColumn($key)->getComment();
311
        }
312
        $this->__meta['id'] = $properties['id'];
313
        return $this;
314
    }
315
316
317
    /**
318
     * Get all properties with relational models in array form
319
     * @return array<mixed>
320
     */
321
    public function getProperties(): array
322
    {
323
        return $this->__props;
324
    }
325
326
    /**
327
     * Get self properties without relations in array form
328
     * @return array<mixed>
329
     */
330
    public function getSelfProperties(): array
331
    {
332
        return $this->__properties;
333
    }
334
335
    /**
336
     * Get all property types in array form
337
     * @return array<mixed>
338
     */
339
    public function getTypes(): array
340
    {
341
        return $this->__types;
342
    }
343
344
345
    /**
346
     * Get all properties in array form
347
     * @return array<mixed>
348
     */
349
    public function toArray(): array
350
    {
351
        $props = $this->getProperties();
352
        foreach ($props as $key => $value) {
353
            if ($value instanceof Model) {
354
                $props[$key] = $value->toArray();
355
            }
356
            if ($value instanceof Collection) {
357
                $props[$key] = $value->toArray();
358
            }
359
        }
360
        return $props;
361
    }
362
363
    /**
364
     * check if model loaded from db
365
     * @return bool
366
     */
367
    public function isLoaded(): bool
368
    {
369
        return $this->__meta['is_loaded'];
370
    }
371
372
    /**
373
     * call when model is loaded from database
374
     * @return Model
375
     */
376
    public function setLoaded(): Model
377
    {
378
        $this->__meta['is_loaded'] = true;
379
        $this->__meta['id_error'] = false;
380
        return $this;
381
    }
382
383
    /**
384
     * Get current table name of model
385
     * @return string
386
     */
387
    public function getName(): string
388
    {
389
        return $this->table;
390
    }
391
392
    /**
393
     * Get current model Id or UUID
394
     * @return mixed
395
     */
396
    public function getId(): mixed
397
    {
398
        return $this->__meta['id'];
399
    }
400
401
    /**
402
     * Check if model has id error
403
     * @return bool
404
     */
405
    public function hasIdError(): bool
406
    {
407
        return $this->__meta['id_error'];
408
    }
409
410
411
    /**
412
     * Save model to database
413
     * @return mixed
414
     */
415
    public function save(): mixed
416
    {
417
        Event::dispatch('__arca.model.save.'.$this->connection->getConnectionId(), [$this]);
418
419
        return $this->getId();
420
    }
421
422
    /**
423
     * Cleans up model internal state to be consistent after save
424
     * @return void
425
     */
426
    public function cleanModel(){
427
        $this->__props = $this->__properties;
428
        $this->__meta['has_foreign']['oto'] = false;
429
        $this->__meta['has_foreign']['otm'] = false;
430
        $this->__meta['has_foreign']['mtm'] = false;
431
        $this->__meta['id_error'] = false;
432
        $this->__meta['foreign_models']['otm'] = [];
433
        $this->__meta['foreign_models']['oto'] = [];
434
        $this->__meta['foreign_models']['mtm'] = [];
435
436
    }
437
438
    /**
439
     * Delete model data
440
     * @return void
441
     */
442
    public function delete(): void
443
    {
444
        Event::dispatch('__arca.model.delete.'.$this->connection->getConnectionId(), [$this]);
445
    }
446
447
    /**
448
     * Converts model into json object
449
     * @return string
450
     */
451
    public function toString(): string
452
    {
453
        return \Safe\json_encode($this->toArray());
454
    }
455
456
    /**
457
     * Converts model into json object
458
     * @return string
459
     */
460
    public function __toString(): string
461
    {
462
        return $this->toString();
463
    }
464
465
466
    /**
467
     * Function used to compare to models
468
     * @param Model $other
469
     * @return bool
470
     */
471
    public function equals(self $other): bool
472
    {
473
        return ($this->getId() === $other->getId() && $this->toString() === $other->toString());
474
    }
475
476
    /**
477
     * Check if model has any relations
478
     * @param string $type
479
     * @return bool
480
     */
481
    public function hasForeign(string $type): bool
482
    {
483
        return $this->__meta['has_foreign'][$type];
484
    }
485
486
    /**
487
     * returns all relational models
488
     * @param string $type
489
     * @return mixed[]
490
     */
491
    public function getForeignModels(string $type): array
492
    {
493
        return $this->__meta['foreign_models'][$type];
494
    }
495
}