Completed
Push — master ( 200c28...f6ac24 )
by Supun
03:34 queued 01:19
created

JsonExtractor::toMysqlTables()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 11
nc 14
nop 2
dl 0
loc 21
rs 7.1428
c 0
b 0
f 0
1
<?php
2
3
namespace Lifeeka\JSQL\Extractor;
4
5
use Lifeeka\JSQL\Helpers\Json;
6
7
/**
8
 * Class JsonExtractor.
9
 */
10
class JsonExtractor
11
{
12
    public $json;
13
14
    private $table = [];
15
    private $data = [];
16
    private $foreign = [];
17
18
    public $need_id = true;
19
    public $snake_case_column = true;
20
    public $snake_case_table = true;
21
    public $main_table_name = "main";
22
23
    /**
24
     * JsonExtractor constructor.
25
     *
26
     * @param Json $json
27
     */
28
    public function __construct(Json $json)
29
    {
30
        $this->json = $json;
31
    }
32
33
    /**
34
     * @return array
35
     */
36
    public function getTablesArray()
37
    {
38
        return $this->table;
39
    }
40
41
    /**
42
     * @return array
43
     */
44
    public function getForeignKeyArray()
45
    {
46
        return $this->foreign;
47
    }
48
49
    /**
50
     * @return array
51
     */
52
    public function getDataArray()
53
    {
54
        return $this->data;
55
    }
56
57
58
    /**
59
     * @param bool $data
60
     * @param string $prefix
61
     */
62
    public function toMysqlTables($data = false, $prefix = '')
63
    {
64
        if (!$data) {//if this is not a recursive
65
            $data = $this->json->toObject();
66
        }
67
68
        foreach ($data as $key => $value) {//loop the data
69
70
            $table_name = is_numeric($key) ? $this->main_table_name : $key;
71
72
73
            if (is_array($value) && is_object($value[0])) {//check whether it's a array and it's firs element is a object
74
75
                $table_data = $this->getTable($prefix . $table_name, $value); //get table sql
76
                $this->table[$table_data['name']] = $table_data['column'];
77
78
                $this->toMysqlTables($this->getHighestColumnArray($value), $prefix . $table_name . "_", $prefix . $table_name); //get it inside tables
79
            } elseif (is_array($value) || is_object($value)) {//if it's a array and  firs element is not a object
80
81
                $table_data = $this->getTable($prefix . $table_name, $value);
82
                $this->table[$table_data['name']] = $table_data['column'];
83
            }
84
        }
85
    }
86
87
88
    /**
89
     * @param bool $data
90
     * @param string $prefix
91
     */
92
    public function toMysqlData($data = false, $prefix = '')
93
    {
94
        if (!$data) {//if this is not a recursive
95
            $data = $this->json->toObject();
96
        }
97
        foreach ($data as $table_name => $value) {
98
            if ($this->snake_case_table) {
99
                $table_name = $this->snakeCase($prefix . $table_name);
100
            }
101
            if (is_array($value) && !empty($value) && is_object($value[0])) {//if it's a array and  firs element is not a object
102
                $this->toMysqlData($value, $table_name . '_');
0 ignored issues
show
Bug introduced by
$value of type array<mixed,object|mixed> is incompatible with the type boolean expected by parameter $data of Lifeeka\JSQL\Extractor\J...xtractor::toMysqlData(). ( Ignorable by Annotation )

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

102
                $this->toMysqlData(/** @scrutinizer ignore-type */ $value, $table_name . '_');
Loading history...
103
            } elseif (is_object($value) || is_array($value)) {
104
                $this->toMysqlData($value, $table_name . '_');
0 ignored issues
show
Bug introduced by
$value of type object|array is incompatible with the type boolean expected by parameter $data of Lifeeka\JSQL\Extractor\J...xtractor::toMysqlData(). ( Ignorable by Annotation )

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

104
                $this->toMysqlData(/** @scrutinizer ignore-type */ $value, $table_name . '_');
Loading history...
105
                $this->getTableData($table_name, $value);
106
            }
107
        }
108
    }
109
110
111
    /**
112
     * @param $table_name
113
     * @param $value
114
     */
115
    public function getTableData($table_name, $value)
116
    {
117
        if (isset($this->table[$table_name])) {
118
            $ColumnList = $this->table[$table_name];
119
120
            $DataItem = [];
121
122
            if (is_object($value)) {
123
                foreach ($ColumnList as $key => $ColumnItem) {
124
                    if ($this->isPropertyExist($value, $ColumnItem['name'])) {
125
                        $CurrentItem = $this->snake_case_column ? $this->objectToSnakeCase($value) : $value;
126
                        $column_name = $ColumnItem['name'];
127
                        $DataItem[$column_name] = $CurrentItem->{$ColumnItem['name']};
128
                    } else {
129
                        $column_name = $ColumnItem['name'];
130
                        $DataItem[$column_name] = null;
131
                    }
132
                }
133
                $this->data[$table_name][] = $DataItem;
134
            } elseif (is_array($value)) {//reference table
135
                foreach ($value as $item_value) {
136
                    $DataItem[] = ['value' => $item_value];
137
                }
138
139
                $this->data[$table_name] = array_merge(($this->data[$table_name] ?? []), $DataItem);
140
            }
141
        }
142
    }
143
144
    /**
145
     * @param $table
146
     * @param $data
147
     * @return array
148
     */
149
    public function getTable($table, $data)
150
    {
151
        $column = $this->getColumn($this->getHighestColumnArray($data), $table);
152
153
        if ($this->snake_case_table) {
154
            $table = $this->snakeCase($table);
155
        }
156
157
        if ($this->snake_case_column) {
158
            return [
159
                'name' => $table,
160
                'column' => array_map(function ($item) {
161
                    return [
162
                        'name' => $this->snakeCase($item['name']),
163
                        'type' => $item['type'],
164
                        'ref' => $item['ref'] ?? null
165
                    ];
166
                }, $column)
167
            ];
168
        } else {
169
            return [
170
                'name' => $table,
171
                'column' => $column
172
            ];
173
        }
174
    }
175
176
177
    /**
178
     * @param $data
179
     * @param $table
180
     * @return array
181
     */
182
    public function getColumn($data, $table)
183
    {
184
        $ForeignKeys = $this->json->getForeignKeys();
185
186
        $Columns = [];
187
188
        if (is_object($data)) {
189
            foreach ($data ?? [] as $Column => $Value) {
190
                if (!is_array($Value) && !is_object($Value) && !empty($Column) && !is_numeric($Column)) {
191
                    if (isset($ForeignKeys[JsonExtractor::snakeCase($table)]) && $ForeignKeys[JsonExtractor::snakeCase($table)]['name'] == JsonExtractor::snakeCase($Column)) {
192
                        $Columns[] = ['name' => $Column, 'type' => 'foreign_key', 'ref' => $ForeignKeys[JsonExtractor::snakeCase($table)]['ref']];
193
                    } elseif ($Column == 'id') {
194
                        $Columns[] = ['name' => $Column, 'type' => 'primary_key'];
195
                    } else {
196
                        $Columns[] = ['name' => $Column, 'type' => gettype($this->getActualDataType($Value, ""))];
197
                    }
198
                }
199
            }
200
        } elseif (is_array($data)) {
201
            $Columns[] = ['name' => 'value', 'type' => gettype($this->getActualDataType($data[0], ""))];
202
        }
203
        return $Columns;
204
    }
205
206
    /**
207
     * @param $data
208
     * @param $column
209
     * @return array
210
     */
211
    public function getData($data, $column)
212
    {
213
        $values = [];
214
215
        $index = 0;
216
        foreach ($data as $row_item) {
217
            foreach ($column as $column_item) {
218
                switch (is_object($row_item)) {
219
                    case true:
220
                        $values[$index][$column_item['name']] = $this->getActualDataType(($row_item->{$column_item['name']}) ?? null, null);
221
                        break;
222
                    case false:
223
                        $values[$index][$column_item['name']] = $this->getActualDataType(($data->{$column_item['name']}) ?? null, null);
224
                        break;
225
                }
226
            }
227
            $index++;
228
        }
229
230
231
        return $values;
232
    }
233
234
    /**
235
     * @param $input
236
     *
237
     * @return string
238
     */
239
    public static function snakeCase($input)
240
    {
241
        preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
242
        $ret = $matches[0];
243
244
        foreach ($ret as &$match) {
245
            $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
246
        }
247
248
        return implode('_', $ret);
249
    }
250
251
    /**
252
     * @param $Object
253
     * @return \stdClass
254
     */
255
    public static function objectToSnakeCase($Object)
256
    {
257
        $ReturnObject = new \stdClass();
258
259
        foreach ($Object as $ObjectAttribute => $ObjectItem) {
260
            $ReturnObject->{JsonExtractor::snakeCase($ObjectAttribute)} = $ObjectItem;
261
        }
262
        return $ReturnObject;
263
    }
264
265
266
    /**
267
     * @param Object $Object
268
     * @param $Attribute
269
     * @return bool
270
     */
271
    public function isPropertyExist($Object, $Attribute)
272
    {
273
        foreach ($Object as $CurrentAttributeName => $CurrentAttribute) {
274
            if ($this->snake_case_column && $this->snakeCase($CurrentAttributeName) == $Attribute) {
275
                return true;
276
            } elseif ($CurrentAttributeName === $Attribute) {
277
                return true;
278
            }
279
        }
280
281
        return false;
282
    }
283
284
285
    /**
286
     * @param $array
287
     * @return bool|mixed
288
     */
289
    public static function getHighestColumnArray($array)
290
    {
291
        if (is_object($array) || (is_array($array) && !is_object($array[0]) && !is_array($array[0]))) {
292
            return $array;
293
        }
294
295
        $Highest = false;
296
        $ColumnCount = false;
297
        $HighestSubCount = false;
298
299
        foreach ($array as $array_item) {
300
            $current_sub = 0;
301
            //check how many array/object have
302
            foreach ($array_item as $SubTableName => $SubArrayItem) {
303
                if (is_array($SubArrayItem) || is_object($SubArrayItem)) {
304
                    $current_sub = $current_sub + 2;
305
                }
306
            }
307
            //check how many column have
308
            if ($ColumnCount <= count($array_item) || !$Highest) {
309
                if ($current_sub > $HighestSubCount || !$Highest) {
310
                    $Highest = $array_item;
311
                    $HighestSubCount = $current_sub;
312
                    $ColumnCount = count($array_item);
313
                }
314
            }
315
        }
316
317
318
        return $Highest;
319
    }
320
321
    /**
322
     * @param $array
323
     * @return string
324
     */
325
    public static function getStringFromData($array)
326
    {
327
        $String = [];
328
329
        foreach ($array as $item_row) {
330
            $value = [];
331
            foreach ($item_row as $item) {
332
                if (empty($item) && !is_numeric($item)) {
333
                    $value[] = "null";
334
                } elseif (is_numeric($item)) {
335
                    $value[] = $item;
336
                } else {
337
                    $value[] = '"' . addcslashes($item, "W") . '"';
338
                }
339
            }
340
            $String[] = '(' . implode(",", $value) . ')';
341
        }
342
343
        return "values" . implode(", ", $String);
344
    }
345
346
    /**
347
     * @param $array
348
     * @return string
349
     */
350
    public static function getStringFromColumns($array)
351
    {
352
        $String = [];
353
        foreach ($array as $column) {
354
            $String[] = "`" . JsonExtractor::snakeCase($column['name']) . "`";
355
        }
356
357
        return implode(",", $String);
358
    }
359
360
361
    /**
362
     * @param $Data
363
     * @param $empty_val
364
     * @return int|string
365
     */
366
    public static function getActualDataType($Data, $empty_val)
367
    {
368
        $Data = trim($Data);
369
        if (is_numeric($Data)) {
370
            return $Data + 0;
371
        } elseif (empty($Data)) {
372
            return $empty_val;
373
        } else {
374
            return (string)$Data;
375
        }
376
    }
377
}
378