Completed
Push — master ( 03c10c...407786 )
by Supun
10s
created

JsonExtractor   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 269
rs 6
c 0
b 0
f 0
wmc 55

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getActualDataType() 0 9 3
A getStringFromColumns() 0 8 2
C toMysqlTables() 0 24 8
B getStringFromData() 0 18 6
A getDataArray() 0 3 1
A snakeCase() 0 10 3
B getTable() 0 27 4
A __construct() 0 3 1
B getColumn() 0 15 8
C getHighestColumnArray() 0 31 13
A getTablesArray() 0 3 1
B getData() 0 22 5

How to fix   Complexity   

Complex Class

Complex classes like JsonExtractor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JsonExtractor, and based on these observations, apply Extract Interface, too.

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
17
    public $need_id = true;
18
    public $snake_case_column = true;
19
    public $snake_case_table = true;
20
    public $main_table_name = "main";
21
22
    /**
23
     * JsonExtractor constructor.
24
     *
25
     * @param Json $json
26
     */
27
    public function __construct(Json $json)
28
    {
29
        $this->json = $json;
30
    }
31
32
    /**
33
     * @return array
34
     */
35
    public function getTablesArray()
36
    {
37
        return $this->table;
38
    }
39
40
    /**
41
     * @return array
42
     */
43
    public function getDataArray()
44
    {
45
        return $this->data;
46
    }
47
48
49
    /**
50
     * @param bool $data
51
     * @param string $prefix
52
     * @return string
53
     */
54
    public function toMysqlTables($data = false, $prefix = '')
55
    {
56
        if (!$data) {//if this is not a recursive
57
            $data = $this->json->toObject();
58
        }
59
60
61
        foreach ($data as $key => $value) {//loop the data
62
63
            $table_name = is_numeric($key) ? $this->main_table_name : $key;
64
65
            if (is_array($value) && is_object($value[0])) {//check whether it's a array and it's firs element is a object
66
67
                $table_data = $this->getTable($prefix . $table_name, $value);//get table sql
68
                $this->table[$table_data['tables']['name']] = $table_data['tables']['column'];
69
                $this->data[$table_data['data']['table']] = $table_data['data']['data'];
70
71
                $this->toMysqlTables($this->getHighestColumnArray($value), $prefix . $table_name . '_');//get it inside tables
72
73
            } elseif (is_array($value) || is_object($value)) {//if it's a array and  firs element is not a object
74
75
                $table_data = $this->getTable($prefix . $table_name, $value);
76
                $this->table[$table_data['tables']['name']] = $table_data['tables']['column'];
77
                $this->data[$table_data['data']['table']] = $table_data['data']['data'];
78
            }
79
        }
80
81
    }
82
83
84
    /**
85
     * @param $table
86
     * @param $data
87
     * @return array
88
     */
89
    public function getTable($table, $data)
90
    {
91
        $column = $this->getColumn($this->getHighestColumnArray($data));
92
93
94
        if ($this->snake_case_table)
95
            $table = $this->snakeCase($table);
96
97
        $table_data = $this->getData($data, $column);
98
99
        $last_columns = $column;
100
        if ($this->need_id && array_search('id', array_column($column, 'name')) === false) {
101
102
            $last_columns[] = [
103
                'name' => "id",
104
                'type' => "int"
105
            ];
106
        }
107
108
        return [
109
            'tables' => [
110
                'name' => $table,
111
                'column' => $last_columns
112
            ],
113
            'data' => [
114
                'table' => $table,
115
                'data' => $table_data
116
            ]
117
        ];
118
    }
119
120
    /**
121
     * @param $data
122
     *
123
     * @return array
124
     */
125
    public function getColumn($data)
126
    {
127
        $Columns = [];
128
129
        if (is_object($data)) {
130
            foreach ($data ?? [] as $Column => $Value) {
131
                if (!is_array($Value) && !is_object($Value) && !empty($Column) && !is_numeric($Column)) {
132
                    $Columns[] = ['name' => $Column, 'type' => gettype($this->getActualDataType($Value, ""))];
133
                }
134
            }
135
        } elseif (is_array($data)) {
136
            $Columns[] = ['name' => 'value', 'type' => gettype($this->getActualDataType($data[0], ""))];
137
        }
138
139
        return $Columns;
140
    }
141
142
    /**
143
     * @param $data
144
     * @param $column
145
     * @return array
146
     */
147
    function getData($data, $column)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
148
    {
149
        $values = [];
150
151
        $index = 0;
152
        foreach ($data as $row_item) {
153
            foreach ($column as $column_item) {
154
                switch (is_object($row_item)) {
155
                    case true:
156
                        $values[$index][$column_item['name']] = $this->getActualDataType(($row_item->{$column_item['name']}) ?? null, null);
157
                        break;
158
                    case false:
159
                        $values[$index][$column_item['name']] = $this->getActualDataType(($data->{$column_item['name']}) ?? null, null);
160
                        break;
161
                }
162
163
            }
164
            $index++;
165
        }
166
167
168
        return $values;
169
170
    }
171
172
    /**
173
     * @param $input
174
     *
175
     * @return string
176
     */
177
    public static function snakeCase($input)
178
    {
179
        preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
180
        $ret = $matches[0];
181
182
        foreach ($ret as &$match) {
183
            $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
184
        }
185
186
        return implode('_', $ret);
187
    }
188
189
190
    /**
191
     * @param $array
192
     * @return bool|mixed
193
     */
194
    public static function getHighestColumnArray($array)
195
    {
196
        if (is_object($array) || (is_array($array) && !is_object($array[0]) && !is_array($array[0])))
197
            return $array;
198
199
        $Highest = false;
200
        $ColumnCount = false;
201
        $HighestSubCount = false;
202
203
        foreach ($array as $array_item) {
204
205
            $current_sub = 0;
206
            //check how many array/object have
207
            foreach ($array_item as $SubTableName => $SubArrayItem) {
208
                if (is_array($SubArrayItem) || is_object($SubArrayItem)) {
209
                    $current_sub = $current_sub + 2;
210
                }
211
212
            }
213
            //check how many column have
214
            if ($ColumnCount <= count($array_item) || !$Highest) {
215
                if ($current_sub > $HighestSubCount || !$Highest) {
216
                    $Highest = $array_item;
217
                    $HighestSubCount = $current_sub;
218
                    $ColumnCount = count($array_item);
219
                }
220
            }
221
        }
222
223
224
        return $Highest;
225
    }
226
227
    /**
228
     * @param $array
229
     * @return string
230
     */
231
    public static function getStringFromData($array)
232
    {
233
        $String = [];
234
235
        foreach ($array as $item_row) {
236
            $value = [];
237
            foreach ($item_row as $item) {
238
                if (empty($item) && !is_numeric($item)) {
239
                    $value[] = "null";
240
                } elseif (is_numeric($item))
241
                    $value[] = $item;
242
                else
243
                    $value[] = '"' . addcslashes($item, "W") . '"';
244
            }
245
            $String[] = '(' . implode(",", $value) . ')';
246
        }
247
248
        return "values" . implode(", ", $String);
249
    }
250
251
    /**
252
     * @param $array
253
     * @return string
254
     */
255
    public static function getStringFromColumns($array)
256
    {
257
        $String = [];
258
        foreach ($array as $column) {
259
            $String[] = "`" . JsonExtractor::snakeCase($column['name']) . "`";
260
        }
261
262
        return implode(",", $String);
263
    }
264
265
    /**
266
     * @param $Data
267
     * @param null $empty_val
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $empty_val is correct as it would always require null to be passed?
Loading history...
268
     * @return int|null|string
269
     */
270
    public static function getActualDataType($Data, $empty_val = null)
271
    {
272
        $Data = trim($Data);
273
        if (is_numeric($Data)) {
274
            return $Data + 0;
275
        } elseif (empty($Data))
276
            return $empty_val;
277
        else
278
            return (string)$Data;
279
    }
280
}
281