Passed
Push — master ( f42972...200c28 )
by Supun
02:29
created

JsonExtractor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
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
65
66
        if (!$data) {//if this is not a recursive
67
            $data = $this->json->toObject();
68
        }
69
70
        foreach ($data as $key => $value) {//loop the data
71
72
            $table_name = is_numeric($key) ? $this->main_table_name : $key;
73
74
75
            if (is_array($value) && is_object($value[0])) {//check whether it's a array and it's firs element is a object
76
77
                $table_data = $this->getTable($prefix . $table_name, $value); //get table sql
78
                $this->table[$table_data['name']] = $table_data['column'];
79
80
                $this->toMysqlTables($this->getHighestColumnArray($value), $prefix . $table_name . "_", $prefix . $table_name); //get it inside tables
81
            } elseif (is_array($value) || is_object($value)) {//if it's a array and  firs element is not a object
82
83
                $table_data = $this->getTable($prefix . $table_name, $value);
84
                $this->table[$table_data['name']] = $table_data['column'];
85
            }
86
        }
87
    }
88
89
90
    /**
91
     * @param bool $data
92
     * @param string $prefix
93
     */
94
    public function toMysqlData($data = false, $prefix = '')
95
    {
96
97
        if (!$data) {//if this is not a recursive
98
            $data = $this->json->toObject();
99
        }
100
        foreach ($data as $table_name => $value) {
101
            if ($this->snake_case_table) {
102
                $table_name = $this->snakeCase($prefix . $table_name);
103
            }
104
            if (is_array($value) && !empty($value) && is_object($value[0])) {//if it's a array and  firs element is not a object
105
                $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

105
                $this->toMysqlData(/** @scrutinizer ignore-type */ $value, $table_name . '_');
Loading history...
106
            } elseif (is_object($value) || is_array($value)) {
107
                $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

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