Passed
Branch master (a0cc06)
by Dāvis
17:06
created

QuickInsertRepository::persist()   F

Complexity

Conditions 35
Paths 1008

Size

Total Lines 99
Code Lines 67

Duplication

Lines 34
Ratio 34.34 %

Importance

Changes 0
Metric Value
cc 35
eloc 67
nc 1008
nop 6
dl 34
loc 99
rs 2
c 0
b 0
f 0

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
namespace Sludio\HelperBundle\Script\Repository;
4
5
class QuickInsertRepository
6
{
7
    private static $mock = [];
8
    private static $metadata = [];
9
    private static $tableName;
10
11
    public static $em;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $em. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
12
    public static $connection;
13
    public static $container;
14
15
    public static function init($noFkCheck = false, $manager = null)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 5 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
16
    {
17
        global $kernel;
18
19
        if ('AppCache' === get_class($kernel)) {
20
            $kernel = $kernel->getKernel();
21
        }
22
        self::$container = $kernel->getContainer();
23
24
        $manager = $manager ?: self::$container->getParameter('sludio_helper.entity.manager');
25
        self::$em = self::$container->get('doctrine')->getManager($manager);
26
        self::$connection = self::$em->getConnection();
27
28
        if (!$noFkCheck) {
29
            $sth = self::$connection->prepare('SET FOREIGN_KEY_CHECKS = 0');
30
            $sth->execute();
31
        }
32
    }
33
34
    public static function close($noFkCheck = false)
35
    {
36
        if (!$noFkCheck) {
37
            $sth = self::$connection->prepare('SET FOREIGN_KEY_CHECKS = 1');
38
            $sth->execute();
39
        }
40
    }
41
42
    public static function isEmpty($variable)
43
    {
44
        $result = true;
45
46
        if (is_array($variable) && count($variable) > 0) {
47
            foreach ($variable as $value) {
48
                $result = $result && self::isEmpty($value);
49
            }
50
        } else {
51
            $result = empty($variable);
52
        }
53
54
        return $result;
55
    }
56
57
    private static function extract($object)
58
    {
59
        $data = self::extractExt($object, self::$em);
60
61
        self::$mock = $data['mock'];
62
        self::$tableName = $data['table'];
63
        self::$metadata[$data['table']] = $data['meta'];
64
    }
65
66
    public static function extractExt($object, $em)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $em. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
67
    {
68
        $metadata = $em->getClassMetadata(get_class($object));
69
70
        $fields = $metadata->getFieldNames();
71
        $columns = $metadata->getColumnNames();
72
        $table = $metadata->getTableName();
73
74
        $result = [];
75
        foreach ($fields as $key => $field) {
76
            foreach ($columns as $key2 => $column) {
77
                if ($key === $key2) {
78
                    $result[$table][$field] = $column;
79
                }
80
            }
81
        }
82
83
        $data = [
84
            'mock' => $result,
85
            'table' => $table,
86
            'meta' => $metadata,
87
        ];
88
89
        return $data;
90
    }
91
92
    private static function buildExtra($tableName, $extra)
93
    {
94
        $methods = [
95
            'GROUP BY',
96
            'HAVING',
97
            'ORDER BY',
98
        ];
99
        $sql = '';
100
101
        foreach ($methods as $method) {
102
            if (isset($extra[$method])) {
103
                $sql .= ' '.$method.' ';
104
                if (is_array($extra[$method])) {
105
                    foreach ($extra[$method] as $group) {
106
                        $sql .= $group.' ';
107
                    }
108
                } else {
109
                    $sql .= $extra[$method].' ';
110
                }
111
            }
112
        }
113
114
        if (isset($extra['LIMIT'])) {
115
            if (is_array($extra['LIMIT'])) {
116
                if (isset($extra['LIMIT'][1])) {
117
                    $offset = $extra['LIMIT'][0];
118
                    $limit = $extra['LIMIT'][1];
119
                } else {
120
                    $offset = 0;
121
                    $limit = $extra['LIMIT'][0];
122
                }
123
                $sql .= 'LIMIT '.$offset.', '.$limit;
124
            }
125
        }
126
127
        $sql = str_replace('  ', ' ', $sql);
128
129
        return $sql;
130
    }
131
132
    private static function buildWhere($tableName, $where)
133
    {
134
        $whereSql = '';
135
        if ($where && is_array($where)) {
136
            $skip = false;
137
            foreach ($where as $key => $value) {
138
                $fk = $key;
139
                if (is_array($value)) {
140
                    $skip = true;
141
                    $f = trim($value[0]);
142
                } else {
143
                    $f = trim($value);
144
                }
145
                break;
146
            }
147 View Code Duplication
            if (!$skip && isset(self::$mock[$tableName][$fk])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fk does not seem to be defined for all execution paths leading up to this point.
Loading history...
Duplication introduced by
This code seems to be duplicated across 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...
148
                if (is_numeric($f)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $f does not seem to be defined for all execution paths leading up to this point.
Loading history...
149
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fk]." = $f";
150
                } else {
151
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fk]." = '".addslashes(trim($f))."'";
152
                }
153
            } else {
154
                if (!$skip && is_numeric($f)) {
155
                    $whereSql .= ' WHERE '.$fk." = $f";
156
                } elseif (!$skip && !is_numeric($f)) {
157
                    $whereSql .= ' WHERE '.$fk." = '".addslashes(trim($f))."'";
158
                } elseif ($skip && is_numeric($fk)) {
159
                    $whereSql .= " WHERE $f";
160
                }
161
            }
162
            unset($where[$fk]);
163
            if ($where && is_array($where)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $where of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
164
                foreach ($where as $key => $value) {
165
                    $skip = is_array($value);
166 View Code Duplication
                    if (!$skip && isset(self::$mock[$tableName][$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
167
                        if (is_numeric($value)) {
168
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = $value";
169
                        } else {
170
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = '".addslashes(trim($value))."'";
171
                        }
172
                    } else {
173
                        if (!$skip && is_numeric($value)) {
174
                            $whereSql .= ' AND '.$key." = $value";
175
                        } elseif (!$skip && !is_numeric($f)) {
176
                            $whereSql .= ' AND '.$key." = '".addslashes(trim($value))."'";
177
                        } elseif ($skip && is_numeric($key)) {
178
                            $whereSql .= " AND {$value[0]}";
179
                        }
180
                    }
181
                }
182
            }
183
        }
184
185
        return $whereSql;
186
    }
187
188 View Code Duplication
    public static function findNextId($tableName, &$out = 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...
189
    {
190
        $sql = "
191
            SELECT
192
                AUTO_INCREMENT
193
            FROM
194
                information_schema.tables
195
            WHERE
196
                table_name = '".$tableName."'
197
            AND
198
                table_schema = DATABASE()
199
        ";
200
        if ($out) {
201
            $out = $sql;
202
        }
203
        $sth = self::$connection->prepare($sql);
204
        $sth->execute();
205
        $result = $sth->fetch();
206
207
        if (isset($result['AUTO_INCREMENT'])) {
208
            return (int)$result['AUTO_INCREMENT'];
209
        }
210
211
        return 1;
212
    }
213
214
    public static function get($object, $one = false, $where = [], $noFkCheck = true, $fields = [], $manager = null, $extra = [], &$out = null)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 5 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
215
    {
216
        self::init($noFkCheck, $manager);
217
        if (is_object($object)) {
218
            self::extract($object);
219
            $tableName = self::$tableName;
220
        } else {
221
            $tableName = $object;
222
        }
223
        $whereSql = self::buildWhere($tableName, $where);
224
        $select = (isset($extra['MODE']) ? 'SELECT '.$extra['MODE'] : 'SELECT').' ';
225
        if (!$fields) {
226
            $sql = $select.'id FROM '.$tableName.' '.$whereSql;
227
        } else {
228
            $sql = $select.(implode(', ', $fields)).' FROM '.$tableName.' '.$whereSql;
229
        }
230
        if (!empty($extra)) {
231
            $extraSql = self::buildExtra($tableName, $extra);
232
            $sql .= $extraSql;
233
        }
234
        if ($out) {
235
            $out = $sql;
236
        }
237
        $sth = self::$connection->prepare($sql);
238
        $sth->execute();
239
        $result = $sth->fetchAll();
240
        if ($one && $result) {
241
            if (!$fields) {
242
                return intval($result[0]['id']);
243
            } else {
244
                if (count($fields) === 1 && $fields[0] !== '*') {
245
                    return $result[0][$fields[0]];
246
                } else {
247
                    return $result[0];
248
                }
249
            }
250
        }
251
252
        self::close($noFkCheck);
253
        if ($one || !$result) {
254
            return null;
255
        }
256
257
        $field = null;
258
        if (!$fields) {
259
            $field = 'id';
260
        } elseif (count($fields) === 1 && $fields[0] !== '*') {
261
            $field = $fields[0];
262
        }
263
264
        if ($field) {
265
            foreach ($result as &$res) {
266
                $res = $res[$field];
267
            }
268
        }
269
270
        return $result;
271
    }
272
273
    public static function persist($object, $full = false, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
274
    {
275
        self::init($noFkCheck, $manager);
276 View Code Duplication
        if (is_object($object)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
277
            self::extract($object);
278
            $tableName = self::$tableName;
279
            $columns = self::$mock[$tableName] ?: [];
280
            $type = 'object';
281
        } else {
282
            $tableName = $object['table_name'];
283
            unset($object['table_name']);
284
            $type = 'table';
285
            $columns = array_keys($object) ?: [];
286
        }
287
288
        $id = self::findNextId($tableName);
289
        $keys = [];
290
        $values = [];
291
292 View Code Duplication
        if (!empty($extraFields) && isset($extraFields[$tableName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
293
            $columns = array_merge($columns, $extraFields[$tableName]);
294
        }
295
296
        if ($type === 'object') {
297
            foreach ($columns as $value => $key) {
298
                $variable = null;
299
                if (!is_array($key) && !is_array($value)) {
300
                    if ($object->{'get'.ucfirst($value)}() instanceof \DateTime) {
301
                        $variable = "'".addslashes(trim($object->{'get'.ucfirst($value)}()->format('Y-m-d H:i:s')))."'";
302
                    } else {
303
                        $variable = "'".addslashes(trim($object->{'get'.ucfirst($value)}()))."'";
304
                    }
305 View Code Duplication
                    if (trim($variable) === '' || trim($variable) === "''" || (is_numeric($variable) && $variable === 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
306
                        $variable = null;
307
                    }
308 View Code Duplication
                    if ($variable) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $variable of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Duplication introduced by
This code seems to be duplicated across 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...
309
                        $values[] = $variable;
310
                        $keys[] = $key;
311
                        if ($key === 'id') {
312
                            $idd = $object->{'get'.ucfirst($value)}();
313
                        }
314
                    }
315
                }
316
            }
317
        } else {
318
            foreach ($columns as $value => $key) {
319
                $variable = null;
320
                if (!is_array($key) && !is_array($value) && isset($object[$value])) {
321
                    if ($object[$value] instanceof \DateTime) {
322
                        $variable = "'".addslashes(trim($object[$value]->format('Y-m-d H:i:s')))."'";
323
                    } else {
324
                        $variable = "'".addslashes(trim($object[$value]))."'";
325
                    }
326 View Code Duplication
                    if (trim($variable) === '' || trim($variable) === "''" || (is_numeric($variable) && $variable === 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
327
                        $variable = null;
328
                    }
329 View Code Duplication
                    if ($variable) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $variable of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Duplication introduced by
This code seems to be duplicated across 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...
330
                        $values[] = $variable;
331
                        $keys[] = $key;
332
                        if ($key === 'id') {
333
                            $idd = $object[$value];
334
                        }
335
                    }
336
                }
337
            }
338
        }
339
340
        $sql = null;
341
        if (!$full && !self::isEmpty($values)) {
342
            $sql = '
343
                INSERT INTO
344
                    '.$tableName.'
345
                        (id, '.implode(',', $keys).")
346
                VALUES
347
                    ({$id},".implode(',', $values).')
348
            ';
349
        } elseif ($full && !self::isEmpty($values)) {
350
            $id = $idd;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $idd does not seem to be defined for all execution paths leading up to this point.
Loading history...
351
            $sql = '
352
                INSERT INTO
353
                    '.$tableName.'
354
                        ('.implode(',', $keys).")
355
                VALUES
356
                    (".implode(',', $values).')
357
            ';
358
        } else {
359
            $id = null;
360
        }
361
        if ($sql && $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sql of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
362
            if ($out) {
363
                $out = $sql;
364
            }
365
            $sth = self::$connection->prepare($sql);
366
            $sth->execute();
367
        }
368
369
        self::close($noFkCheck);
370
371
        return $id;
372
    }
373
374
    public static function update($id, $object, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
375
    {
376
        self::init($noFkCheck, $manager);
377
378 View Code Duplication
        if (is_object($object)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
379
            self::extract($object);
380
            $tableName = self::$tableName;
381
            $columns = self::$mock[$tableName] ?: [];
382
            $type = 'object';
383
        } else {
384
            $tableName = $object['table_name'];
385
            unset($object['table_name']);
386
            $type = 'table';
387
            $columns = array_keys($object) ?: [];
388
        }
389
390
        $result = self::get($tableName, true, ['id' => $id], true, ['*']);
391
        unset($result['id']);
392
393
        $data = [];
394
395 View Code Duplication
        if (!empty($extraFields) && isset($extraFields[$tableName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
396
            $columns = array_merge($columns, $extraFields[$tableName]);
397
        }
398
399
        $flip = array_flip($columns);
400
        if ($type === 'object') {
401
            if ($object->getId()) {
402
                foreach ($result as $key => $value) {
403 View Code Duplication
                    if ($object->{'get'.ucfirst($flip[$key])}() !== $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
404
                        $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
405
                    }
406
                }
407
            } else {
408
                foreach ($result as $key => $value) {
409
                    if ($object->{'get'.ucfirst($flip[$key])}() !== null) {
410 View Code Duplication
                        if ($object->{'get'.ucfirst($flip[$key])}() !== $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
411
                            $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
412
                        }
413
                    }
414
                }
415
            }
416
        } else {
417
            foreach ($result as $key => $value) {
418
                if (isset($object[$key]) && $object[$key] !== $value) {
419
                    $data[$key] = $extraFields[$key];
420
                }
421
            }
422
423
        }
424
425
        if ($data) {
426
            $sqlu = "
427
                UPDATE
428
                    ".$tableName."
429
                SET
430
431
            ";
432
            foreach ($data as $key => $value) {
433
                $meta = self::$metadata[$tableName]->getFieldMapping($flip[$key]);
434
                $meta = $meta['type'];
435
                if (in_array($meta, [
436
                    'boolean',
437
                    'integer',
438
                    'longint',
439
                ])) {
440
                    $value = intval($value);
441
                } else {
442
                    $value = "'".addslashes(trim($value))."'";
443
                }
444
                $sqlu .= " ".$key." = ".$value.",";
445
            }
446
            $sqlu = substr($sqlu, 0, -1);
447
            $sqlu .= " WHERE id = ".$id;
448
            if ($out) {
449
                $out = $sql;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sql does not exist. Did you maybe mean $sqlu?
Loading history...
450
            }
451
452
            $sthu = self::$connection->prepare($sqlu);
453
            $sthu->execute();
454
        }
455
456
        self::close($noFkCheck);
457
    }
458
459
    public static function delete($object, $where = [], $noFkCheck = false, $manager = null, &$out = null)
460
    {
461
        self::init($noFkCheck, $manager);
462
        if (is_object($object)) {
463
            self::extract($object);
464
            $tableName = self::$tableName;
465
        } else {
466
            $tableName = $object;
467
        }
468
        $whereSql = self::buildWhere($tableName, $where);
469
        $sql = 'DELETE FROM '.$tableName.' '.$whereSql;
470
        if ($out) {
471
            $out = $sql;
472
        }
473
        $sth = self::$connection->prepare($sql);
474
        $sth->execute();
475
476
        self::close($noFkCheck);
477
    }
478
479
    public static function link($object, $data, $noFkCheck = false, $manager = null, &$out = null)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 5 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
480
    {
481
        self::init($noFkCheck, $manager);
482
        if (is_object($object)) {
483
            self::extract($object);
484
            $tableName = self::$tableName;
485
        } else {
486
            $tableName = $object;
487
        }
488
        if ($object && $data) {
489
            $keys = $values = [];
490
            foreach ($data as $key => $value) {
491
                $keys[] = $key;
492
                $values[] = $value;
493
            }
494
            $sql = "
495
                INSERT IGNORE INTO
496
                    ".$tableName."
497
                        (".implode(',', $keys).")
498
                VALUES
499
                    (".implode(',', $values).")
500
            ";
501
            if ($out) {
502
                $out = $sql;
503
            }
504
            $sth = self::$connection->prepare($sql);
505
            $sth->execute();
506
        }
507
508
        self::close($noFkCheck);
509
    }
510
}
511