Passed
Push — master ( 5f41ad...3af61e )
by Dāvis
03:43
created

QuickInsertRepository::getTable()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 2
nop 4
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
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 $entityManager;
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::$entityManager = self::$container->get('doctrine')->getManager($manager);
26
        self::$connection = self::$entityManager->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
        self::init(false);
60
        $data = self::extractExt($object, self::$entityManager);
61
62
        self::$mock = $data['mock'];
63
        self::$tableName = $data['table'];
64
        self::$metadata[$data['table']] = $data['meta'];
65
    }
66
67
    public static function extractExt($object, $entityManager)
68
    {
69
        $metadata = $entityManager->getClassMetadata(get_class($object));
70
71
        $fields = $metadata->getFieldNames();
72
        $columns = $metadata->getColumnNames();
73
        $table = $metadata->getTableName();
74
75
        $result = [];
76
        foreach ($fields as $key => $field) {
77
            foreach ($columns as $key2 => $column) {
78
                if ($key === $key2) {
79
                    $result[$table][$field] = $column;
80
                }
81
            }
82
        }
83
84
        $data = [
85
            'mock' => $result,
86
            'table' => $table,
87
            'meta' => $metadata,
88
        ];
89
90
        return $data;
91
    }
92
93
    private static function buildExtra($extra)
94
    {
95
        $methods = [
96
            'GROUP BY',
97
            'HAVING',
98
            'ORDER BY',
99
        ];
100
        $sql = '';
101
102
        foreach ($methods as $method) {
103
            if (isset($extra[$method])) {
104
                $sql .= ' '.$method.' ';
105
                if (is_array($extra[$method])) {
106
                    foreach ($extra[$method] as $group) {
107
                        $sql .= $group.' ';
108
                    }
109
                } else {
110
                    $sql .= $extra[$method].' ';
111
                }
112
            }
113
        }
114
115
        if (isset($extra['LIMIT'])) {
116
            if (is_array($extra['LIMIT'])) {
117
                if (isset($extra['LIMIT'][1])) {
118
                    $offset = $extra['LIMIT'][0];
119
                    $limit = $extra['LIMIT'][1];
120
                } else {
121
                    $offset = 0;
122
                    $limit = $extra['LIMIT'][0];
123
                }
124
                $sql .= 'LIMIT '.$offset.', '.$limit;
125
            }
126
        }
127
128
        $sql = str_replace('  ', ' ', $sql);
129
130
        return $sql;
131
    }
132
133
    private static function buildWhere($tableName, $where)
134
    {
135
        $whereSql = $fvalue = $fkey = '';
136
        if ($where && is_array($where)) {
137
            $skip = false;
138
            foreach ($where as $key => $value) {
139
                $fkey = $key;
140
                if (is_array($value)) {
141
                    $skip = true;
142
                    $fvalue = trim($value[0]);
143
                } else {
144
                    $fvalue = trim($value);
145
                }
146
                break;
147
            }
148 View Code Duplication
            if (!$skip && isset(self::$mock[$tableName][$fkey])) {
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...
149
                if (is_numeric($fvalue)) {
150
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fkey]." = $fvalue";
151
                } else {
152
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fkey]." = '".addslashes(trim($fvalue))."'";
153
                }
154
            } else {
155
                if (!$skip && is_numeric($fvalue)) {
156
                    $whereSql .= ' WHERE '.$fkey." = $fvalue";
157
                } elseif (!$skip && !is_numeric($fvalue)) {
158
                    $whereSql .= ' WHERE '.$fkey." = '".addslashes(trim($fvalue))."'";
159
                } elseif ($skip && is_numeric($fkey)) {
160
                    $whereSql .= " WHERE $fvalue";
161
                }
162
            }
163
            unset($where[$fkey]);
164
            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...
165
                foreach ($where as $key => $value) {
166
                    $skip = is_array($value);
167 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...
168
                        if (is_numeric($value)) {
169
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = $value";
170
                        } else {
171
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = '".addslashes(trim($value))."'";
172
                        }
173
                    } else {
174
                        if (!$skip && is_numeric($value)) {
175
                            $whereSql .= ' AND '.$key." = $value";
176
                        } elseif (!$skip && !is_numeric($value)) {
177
                            $whereSql .= ' AND '.$key." = '".addslashes(trim($value))."'";
178
                        } elseif ($skip && is_numeric($key)) {
179
                            $whereSql .= " AND {$value[0]}";
180
                        }
181
                    }
182
                }
183
            }
184
        }
185
186
        return $whereSql;
187
    }
188
189
    public static function findNextId($tableName, &$out = null)
190
    {
191
        $sql = "
192
            SELECT
193
                AUTO_INCREMENT
194
            FROM
195
                information_schema.tables
196
            WHERE
197
                table_name = '".$tableName."'
198
            AND
199
                table_schema = DATABASE()
200
        ";
201
        if ($out) {
202
            $out = $sql;
203
        }
204
        $sth = self::$connection->prepare($sql);
205
        $sth->execute();
206
        $result = $sth->fetch();
207
208
        if (isset($result['AUTO_INCREMENT'])) {
209
            return (int)$result['AUTO_INCREMENT'];
210
        }
211
212
        return 1;
213
    }
214
215
    public static function findNextIdExt($object, $entityManager, &$out = null)
216
    {
217
        self::init(true);
218
        $data = self::extractExt($object, $entityManager);
219
220
        return self::findNextId($data['table'], $out);
221
    }
222
223
    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...
224
    {
225
        self::init($noFkCheck, $manager);
226
        self::getTable($object, $tableName, $columns, $type);
227
228
        $whereSql = self::buildWhere($tableName, $where);
229
        $select = (isset($extra['MODE']) ? 'SELECT '.$extra['MODE'] : 'SELECT').' ';
230
        if (!$fields) {
231
            $sql = $select.'id FROM '.$tableName.' '.$whereSql;
232
        } else {
233
            $sql = $select.(implode(', ', $fields)).' FROM '.$tableName.' '.$whereSql;
234
        }
235
        if (!empty($extra)) {
236
            $extraSql = self::buildExtra($extra);
237
            $sql .= $extraSql;
238
        }
239
        if ($out) {
240
            $out = $sql;
241
        }
242
        $sth = self::$connection->prepare($sql);
243
        $sth->execute();
244
        $result = $sth->fetchAll();
245
        if ($one && $result) {
246
            if (!$fields) {
247
                return intval($result[0]['id']);
248
            } else {
249
                if (count($fields) === 1 && $fields[0] !== '*') {
250
                    return $result[0][$fields[0]];
251
                } else {
252
                    return $result[0];
253
                }
254
            }
255
        }
256
257
        self::close($noFkCheck);
258
        if ($one || !$result) {
259
            return null;
260
        }
261
262
        $field = null;
263
        if (!$fields) {
264
            $field = 'id';
265
        } elseif (count($fields) === 1 && $fields[0] !== '*') {
266
            $field = $fields[0];
267
        }
268
269
        if ($field) {
270
            foreach ($result as &$res) {
271
                $res = $res[$field];
272
            }
273
        }
274
275
        return $result;
276
    }
277
278
    private static function getTable(&$object, &$tableName, &$columns, &$type)
279
    {
280
        if (is_object($object)) {
281
            self::extract($object);
282
            $tableName = self::$tableName;
283
            $columns = self::$mock[$tableName] ?: [];
284
            $type = 'object';
285
        } else {
286
            $tableName = $object['table_name'];
287
            unset($object['table_name']);
288
            $type = 'table';
289
            $columns = array_keys($object) ?: [];
290
        }
291
    }
292
293
    public static function persist($object, $full = false, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
294
    {
295
        self::init($noFkCheck, $manager);
296
        self::getTable($object, $tableName, $columns, $type);
297
298
        $id = self::findNextId($tableName);
299
        $keys = [];
300
        $values = [];
301
302 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...
303
            $columns = array_merge($columns, $extraFields[$tableName]);
304
        }
305
306
        if ($type === 'object') {
307
            foreach ($columns as $value => $key) {
308
                $variable = null;
309
                if (!is_array($key) && !is_array($value)) {
310
                    if ($object->{'get'.ucfirst($value)}() instanceof \DateTime) {
311
                        $variable = "'".addslashes(trim($object->{'get'.ucfirst($value)}()->format('Y-m-d H:i:s')))."'";
312
                    } else {
313
                        $variable = "'".addslashes(trim($object->{'get'.ucfirst($value)}()))."'";
314
                    }
315 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...
316
                        $variable = null;
317
                    }
318 View Code Duplication
                    if ($variable !== null) {
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...
319
                        $values[] = $variable;
320
                        $keys[] = $key;
321
                        if ($key === 'id') {
322
                            $idd = $object->{'get'.ucfirst($value)}();
323
                        }
324
                    }
325
                }
326
            }
327
        } else {
328
            foreach ($columns as $value => $key) {
329
                $variable = null;
330
                if (!is_array($key) && !is_array($value) && isset($object[$value])) {
331
                    if ($object[$value] instanceof \DateTime) {
332
                        $variable = "'".addslashes(trim($object[$value]->format('Y-m-d H:i:s')))."'";
333
                    } else {
334
                        $variable = "'".addslashes(trim($object[$value]))."'";
335
                    }
336 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...
337
                        $variable = null;
338
                    }
339 View Code Duplication
                    if ($variable !== null) {
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...
340
                        $values[] = $variable;
341
                        $keys[] = $key;
342
                        if ($key === 'id') {
343
                            $idd = $object[$value];
344
                        }
345
                    }
346
                }
347
            }
348
        }
349
350
        $sql = null;
351
        if (!$full && !self::isEmpty($values)) {
352
            $sql = '
353
                INSERT INTO
354
                    '.$tableName.'
355
                        (id, '.implode(',', $keys).")
356
                VALUES
357
                    ({$id},".implode(',', $values).')
358
            ';
359
        } elseif ($full && !self::isEmpty($values)) {
360
            $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...
361
            $sql = '
362
                INSERT INTO
363
                    '.$tableName.'
364
                        ('.implode(',', $keys).")
365
                VALUES
366
                    (".implode(',', $values).')
367
            ';
368
        } else {
369
            $id = null;
370
        }
371
        if ($sql !== null && $id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type null|integer is loosely compared to true; this is ambiguous if the integer can be 0. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
372
            if ($out) {
373
                $out = $sql;
374
            }
375
            $sth = self::$connection->prepare($sql);
376
            $sth->execute();
377
        }
378
379
        self::close($noFkCheck);
380
381
        return $id;
382
    }
383
384
    public static function update($id, $object, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
385
    {
386
        self::init($noFkCheck, $manager);
387
        self::getTable($object, $tableName, $columns, $type);
388
389
        $result = self::get($tableName, true, ['id' => $id], true, ['*']);
390
        unset($result['id']);
391
392
        $data = [];
393
394 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...
395
            $columns = array_merge($columns, $extraFields[$tableName]);
396
        }
397
398
        $flip = array_flip($columns);
399
        if ($type === 'object') {
400
            if ($id) {
401
                foreach ($result as $key => $value) {
402 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...
403
                        $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
404
                    }
405
                }
406
            } else {
407
                foreach ($result as $key => $value) {
408
                    if ($object->{'get'.ucfirst($flip[$key])}() !== null) {
409 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...
410
                            $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
411
                        }
412
                    }
413
                }
414
            }
415
        } else {
416
            foreach ($result as $key => $value) {
417
                if (isset($object[$key]) && $object[$key] !== $value) {
418
                    $data[$key] = $extraFields[$key];
419
                }
420
            }
421
422
        }
423
424
        if ($data) {
425
            $sql = "
426
                UPDATE
427
                    ".$tableName."
428
                SET
429
430
            ";
431
            foreach ($data as $key => $value) {
432
                $meta = self::$metadata[$tableName]->getFieldMapping($flip[$key]);
433
                $meta = $meta['type'];
434
                if (in_array($meta, [
435
                    'boolean',
436
                    'integer',
437
                    'longint',
438
                ])) {
439
                    $value = intval($value);
440
                } else {
441
                    $value = "'".addslashes(trim($value))."'";
442
                }
443
                $sql .= " ".$key." = ".$value.",";
444
            }
445
            $sql = substr($sql, 0, -1);
446
            $sql .= " WHERE id = ".$id;
447
            if ($out) {
448
                $out = $sql;
449
            }
450
451
            $sthu = self::$connection->prepare($sql);
452
            $sthu->execute();
453
        }
454
455
        self::close($noFkCheck);
456
    }
457
458
    public static function delete($object, $where = [], $noFkCheck = false, $manager = null, &$out = null)
459
    {
460
        self::init($noFkCheck, $manager);
461
        self::getTable($object, $tableName, $columns, $type);
462
463
        $whereSql = self::buildWhere($tableName, $where);
464
        $sql = 'DELETE FROM '.$tableName.' '.$whereSql;
465
        if ($out) {
466
            $out = $sql;
467
        }
468
        $sth = self::$connection->prepare($sql);
469
        $sth->execute();
470
471
        self::close($noFkCheck);
472
    }
473
474
    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...
475
    {
476
        self::init($noFkCheck, $manager);
477
        self::getTable($object, $tableName, $columns, $type);
478
479
        if ($object && $data) {
480
            $keys = $values = [];
481
            foreach ($data as $key => $value) {
482
                $keys[] = $key;
483
                $values[] = $value;
484
            }
485
            $sql = "
486
                INSERT IGNORE INTO
487
                    ".$tableName."
488
                        (".implode(',', $keys).")
489
                VALUES
490
                    (".implode(',', $values).")
491
            ";
492
            if ($out) {
493
                $out = $sql;
494
            }
495
            $sth = self::$connection->prepare($sql);
496
            $sth->execute();
497
        }
498
499
        self::close($noFkCheck);
500
    }
501
}
502