lifeeka /
jsql
| 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 | * @param Json $json |
||||
| 26 | * @param $mainTableName |
||||
| 27 | */ |
||||
| 28 | public function __construct(Json $json, $mainTableName) |
||||
| 29 | { |
||||
| 30 | $this->json = $json; |
||||
| 31 | $this->main_table_name = $mainTableName; |
||||
| 32 | } |
||||
| 33 | |||||
| 34 | /** |
||||
| 35 | * @return array |
||||
| 36 | */ |
||||
| 37 | public function getTablesArray() |
||||
| 38 | { |
||||
| 39 | return $this->table; |
||||
| 40 | } |
||||
| 41 | |||||
| 42 | /** |
||||
| 43 | * @return array |
||||
| 44 | */ |
||||
| 45 | public function getForeignKeyArray() |
||||
| 46 | { |
||||
| 47 | return $this->foreign; |
||||
| 48 | } |
||||
| 49 | |||||
| 50 | /** |
||||
| 51 | * @return array |
||||
| 52 | */ |
||||
| 53 | public function getDataArray() |
||||
| 54 | { |
||||
| 55 | return $this->data; |
||||
| 56 | } |
||||
| 57 | |||||
| 58 | |||||
| 59 | /** |
||||
| 60 | * @param bool $data |
||||
| 61 | * @param string $prefix |
||||
| 62 | */ |
||||
| 63 | public function toMysqlTables($data = false, $prefix = '') |
||||
| 64 | { |
||||
| 65 | if (!$data) {//if this is not a recursive |
||||
| 66 | $data = $this->json->toObject(); |
||||
| 67 | } |
||||
| 68 | |||||
| 69 | foreach ($data as $key => $value) {//loop the data |
||||
| 70 | |||||
| 71 | $table_name = is_numeric($key) ? $this->main_table_name : $key; |
||||
| 72 | |||||
| 73 | |||||
| 74 | if (is_array($value) && is_object($value[0])) {//check whether it's a array and it's firs element is a object |
||||
| 75 | |||||
| 76 | $table_data = $this->getTable($prefix . $table_name, $value); //get table sql |
||||
| 77 | $this->table[$table_data['name']] = $table_data['column']; |
||||
| 78 | |||||
| 79 | $this->toMysqlTables($this->getHighestColumnArray($value), $prefix . $table_name . "_"); //get it inside tables |
||||
| 80 | } elseif (is_array($value) || is_object($value)) {//if it's a array and firs element is not a object |
||||
| 81 | |||||
| 82 | $table_data = $this->getTable($prefix . $table_name, $value); |
||||
| 83 | $this->table[$table_data['name']] = $table_data['column']; |
||||
| 84 | } |
||||
| 85 | } |
||||
| 86 | } |
||||
| 87 | |||||
| 88 | |||||
| 89 | /** |
||||
| 90 | * @param bool $data |
||||
| 91 | * @param string $prefix |
||||
| 92 | */ |
||||
| 93 | public function toMysqlData($data = false, $prefix = '') |
||||
| 94 | { |
||||
| 95 | if (!$data) {//if this is not a recursive |
||||
| 96 | $data = $this->json->toObject(); |
||||
| 97 | } |
||||
| 98 | foreach ($data as $table_name => $value) { |
||||
| 99 | if ($this->snake_case_table) { |
||||
| 100 | $table_name = $this->snakeCase($prefix . $table_name); |
||||
| 101 | } |
||||
| 102 | if (is_array($value) && !empty($value) && is_object($value[0])) {//if it's a array and firs element is not a object |
||||
| 103 | $this->toMysqlData($value, $table_name . '_'); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 104 | } elseif (is_object($value) || is_array($value)) { |
||||
| 105 | $this->toMysqlData($value, $table_name . '_'); |
||||
|
0 ignored issues
–
show
$value of type array|object 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
Loading history...
|
|||||
| 106 | $this->getTableData($table_name, $value); |
||||
| 107 | } |
||||
| 108 | } |
||||
| 109 | } |
||||
| 110 | |||||
| 111 | |||||
| 112 | /** |
||||
| 113 | * @param $table_name |
||||
| 114 | * @param $value |
||||
| 115 | */ |
||||
| 116 | public function getTableData($table_name, $value) |
||||
| 117 | { |
||||
| 118 | if (isset($this->table[$table_name])) { |
||||
| 119 | $ColumnList = $this->table[$table_name]; |
||||
| 120 | |||||
| 121 | $DataItem = []; |
||||
| 122 | |||||
| 123 | if (is_object($value)) { |
||||
| 124 | foreach ($ColumnList as $ColumnItem) { |
||||
| 125 | if ($this->isPropertyExist($value, $ColumnItem['name'])) { |
||||
| 126 | $CurrentItem = $this->snake_case_column ? $this->objectToSnakeCase($value) : $value; |
||||
| 127 | $column_name = $ColumnItem['name']; |
||||
| 128 | $DataItem[$column_name] = $CurrentItem->{$ColumnItem['name']}; |
||||
| 129 | } else { |
||||
| 130 | $column_name = $ColumnItem['name']; |
||||
| 131 | $DataItem[$column_name] = null; |
||||
| 132 | } |
||||
| 133 | } |
||||
| 134 | $this->data[$table_name][] = $DataItem; |
||||
| 135 | } elseif (is_array($value)) {//reference table |
||||
| 136 | foreach ($value as $item_value) { |
||||
| 137 | $DataItem[] = ['value' => $item_value]; |
||||
| 138 | } |
||||
| 139 | |||||
| 140 | $this->data[$table_name] = array_merge(($this->data[$table_name] ?? []), $DataItem); |
||||
| 141 | } |
||||
| 142 | } |
||||
| 143 | } |
||||
| 144 | |||||
| 145 | /** |
||||
| 146 | * @param $table |
||||
| 147 | * @param $data |
||||
| 148 | * @return array |
||||
| 149 | */ |
||||
| 150 | public function getTable($table, $data) |
||||
| 151 | { |
||||
| 152 | $column = $this->getColumn($this->getHighestColumnArray($data), $table); |
||||
| 153 | |||||
| 154 | if ($this->snake_case_table) { |
||||
| 155 | $table = $this->snakeCase($table); |
||||
| 156 | } |
||||
| 157 | |||||
| 158 | if ($this->snake_case_column) { |
||||
| 159 | return [ |
||||
| 160 | 'name' => $table, |
||||
| 161 | 'column' => array_map(function ($item) { |
||||
| 162 | return [ |
||||
| 163 | 'name' => $this->snakeCase($item['name']), |
||||
| 164 | 'type' => $item['type'], |
||||
| 165 | 'ref' => $item['ref'] ?? null |
||||
| 166 | ]; |
||||
| 167 | }, $column) |
||||
| 168 | ]; |
||||
| 169 | } else { |
||||
| 170 | return [ |
||||
| 171 | 'name' => $table, |
||||
| 172 | 'column' => $column |
||||
| 173 | ]; |
||||
| 174 | } |
||||
| 175 | } |
||||
| 176 | |||||
| 177 | |||||
| 178 | /** |
||||
| 179 | * @param $data |
||||
| 180 | * @param $table |
||||
| 181 | * @return array |
||||
| 182 | */ |
||||
| 183 | public function getColumn($data, $table) |
||||
| 184 | { |
||||
| 185 | $ForeignKeys = $this->json->getForeignKeys(); |
||||
| 186 | |||||
| 187 | $Columns = []; |
||||
| 188 | |||||
| 189 | if (is_object($data)) { |
||||
| 190 | foreach ($data ?? [] as $Column => $Value) { |
||||
| 191 | if (!is_array($Value) && !is_object($Value) && !empty($Column) && !is_numeric($Column)) { |
||||
| 192 | if (isset($ForeignKeys[JsonExtractor::snakeCase($table)]) && $ForeignKeys[JsonExtractor::snakeCase($table)]['name'] == JsonExtractor::snakeCase($Column)) { |
||||
| 193 | $Columns[] = ['name' => $Column, 'type' => 'foreign_key', 'ref' => $ForeignKeys[JsonExtractor::snakeCase($table)]['ref']]; |
||||
| 194 | } elseif ($Column == 'id') { |
||||
| 195 | $Columns[] = ['name' => $Column, 'type' => 'primary_key']; |
||||
| 196 | } else { |
||||
| 197 | $Columns[] = ['name' => $Column, 'type' => gettype($this->getActualDataType($Value, ""))]; |
||||
| 198 | } |
||||
| 199 | } |
||||
| 200 | } |
||||
| 201 | } elseif (is_array($data)) { |
||||
| 202 | $Columns[] = ['name' => 'value', 'type' => gettype($this->getActualDataType($data[0], ""))]; |
||||
| 203 | } |
||||
| 204 | return $Columns; |
||||
| 205 | } |
||||
| 206 | |||||
| 207 | /** |
||||
| 208 | * @param $data |
||||
| 209 | * @param $column |
||||
| 210 | * @return array |
||||
| 211 | */ |
||||
| 212 | public function getData($data, $column) |
||||
| 213 | { |
||||
| 214 | $values = []; |
||||
| 215 | |||||
| 216 | $index = 0; |
||||
| 217 | foreach ($data as $row_item) { |
||||
| 218 | foreach ($column as $column_item) { |
||||
| 219 | switch (is_object($row_item)) { |
||||
| 220 | case true: |
||||
| 221 | $values[$index][$column_item['name']] = $this->getActualDataType(($row_item->{$column_item['name']}) ?? null, null); |
||||
| 222 | break; |
||||
| 223 | case false: |
||||
| 224 | $values[$index][$column_item['name']] = $this->getActualDataType(($data->{$column_item['name']}) ?? null, null); |
||||
| 225 | break; |
||||
| 226 | } |
||||
| 227 | } |
||||
| 228 | $index++; |
||||
| 229 | } |
||||
| 230 | |||||
| 231 | |||||
| 232 | return $values; |
||||
| 233 | } |
||||
| 234 | |||||
| 235 | /** |
||||
| 236 | * @param $input |
||||
| 237 | * |
||||
| 238 | * @return string |
||||
| 239 | */ |
||||
| 240 | public static function snakeCase($input) |
||||
| 241 | { |
||||
| 242 | preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); |
||||
| 243 | $ret = $matches[0]; |
||||
| 244 | |||||
| 245 | foreach ($ret as &$match) { |
||||
| 246 | $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); |
||||
| 247 | } |
||||
| 248 | |||||
| 249 | return implode('_', $ret); |
||||
| 250 | } |
||||
| 251 | |||||
| 252 | /** |
||||
| 253 | * @param $Object |
||||
| 254 | * @return \stdClass |
||||
| 255 | */ |
||||
| 256 | public static function objectToSnakeCase($Object) |
||||
| 257 | { |
||||
| 258 | $ReturnObject = new \stdClass(); |
||||
| 259 | |||||
| 260 | foreach ($Object as $ObjectAttribute => $ObjectItem) { |
||||
| 261 | $ReturnObject->{JsonExtractor::snakeCase($ObjectAttribute)} = $ObjectItem; |
||||
| 262 | } |
||||
| 263 | return $ReturnObject; |
||||
| 264 | } |
||||
| 265 | |||||
| 266 | |||||
| 267 | /** |
||||
| 268 | * @param Object $Object |
||||
| 269 | * @param $Attribute |
||||
| 270 | * @return bool |
||||
| 271 | */ |
||||
| 272 | public function isPropertyExist($Object, $Attribute) |
||||
| 273 | { |
||||
| 274 | foreach (array_keys(get_object_vars($Object)) as $CurrentAttributeName) { |
||||
| 275 | if ($this->snake_case_column && $this->snakeCase($CurrentAttributeName) == $Attribute) { |
||||
| 276 | return true; |
||||
| 277 | } elseif ($CurrentAttributeName === $Attribute) { |
||||
| 278 | return true; |
||||
| 279 | } |
||||
| 280 | } |
||||
| 281 | |||||
| 282 | return false; |
||||
| 283 | } |
||||
| 284 | |||||
| 285 | |||||
| 286 | /** |
||||
| 287 | * @param $array |
||||
| 288 | * @return bool|mixed |
||||
| 289 | */ |
||||
| 290 | public static function getHighestColumnArray($array) |
||||
| 291 | { |
||||
| 292 | if (is_object($array) || (is_array($array) && !is_object($array[0]) && !is_array($array[0]))) { |
||||
| 293 | return $array; |
||||
| 294 | } |
||||
| 295 | |||||
| 296 | $Highest = false; |
||||
| 297 | $ColumnCount = false; |
||||
| 298 | $HighestSubCount = false; |
||||
| 299 | |||||
| 300 | foreach ($array as $array_item) { |
||||
| 301 | $current_sub = 0; |
||||
| 302 | //check how many array/object have |
||||
| 303 | foreach ($array_item as $SubArrayItem) { |
||||
| 304 | if (is_array($SubArrayItem) || is_object($SubArrayItem)) { |
||||
| 305 | $current_sub = $current_sub + 2; |
||||
| 306 | } |
||||
| 307 | } |
||||
| 308 | //check how many column have |
||||
| 309 | if ($ColumnCount <= @count($array_item) || !$Highest) { |
||||
| 310 | if ($current_sub > $HighestSubCount || !$Highest) { |
||||
| 311 | $Highest = $array_item; |
||||
| 312 | $HighestSubCount = $current_sub; |
||||
| 313 | $ColumnCount = @count($array_item); |
||||
| 314 | } |
||||
| 315 | } |
||||
| 316 | } |
||||
| 317 | |||||
| 318 | |||||
| 319 | return $Highest; |
||||
| 320 | } |
||||
| 321 | |||||
| 322 | /** |
||||
| 323 | * @param $array |
||||
| 324 | * @return string |
||||
| 325 | */ |
||||
| 326 | public static function getStringFromData($array) |
||||
| 327 | { |
||||
| 328 | $String = []; |
||||
| 329 | |||||
| 330 | foreach ($array as $item_row) { |
||||
| 331 | $value = []; |
||||
| 332 | foreach ($item_row as $item) { |
||||
| 333 | if (empty($item) && !is_numeric($item)) { |
||||
| 334 | $value[] = "null"; |
||||
| 335 | } elseif (is_numeric($item)) { |
||||
| 336 | $value[] = $item; |
||||
| 337 | } else { |
||||
| 338 | $value[] = '"' . addcslashes($item, "W") . '"'; |
||||
| 339 | } |
||||
| 340 | } |
||||
| 341 | $String[] = '(' . implode(",", $value) . ')'; |
||||
| 342 | } |
||||
| 343 | |||||
| 344 | return "values" . implode(", ", $String); |
||||
| 345 | } |
||||
| 346 | |||||
| 347 | /** |
||||
| 348 | * @param $array |
||||
| 349 | * @return string |
||||
| 350 | */ |
||||
| 351 | public static function getStringFromColumns($array) |
||||
| 352 | { |
||||
| 353 | $String = []; |
||||
| 354 | foreach ($array as $column) { |
||||
| 355 | $String[] = "`" . JsonExtractor::snakeCase($column['name']) . "`"; |
||||
| 356 | } |
||||
| 357 | |||||
| 358 | return implode(",", $String); |
||||
| 359 | } |
||||
| 360 | |||||
| 361 | |||||
| 362 | /** |
||||
| 363 | * @param $Data |
||||
| 364 | * @param $empty_val |
||||
| 365 | * @return int|string |
||||
| 366 | */ |
||||
| 367 | public static function getActualDataType($Data, $empty_val) |
||||
| 368 | { |
||||
| 369 | $Data = trim($Data); |
||||
| 370 | if (is_numeric($Data)) { |
||||
| 371 | return $Data + 0; |
||||
| 372 | } elseif (empty($Data)) { |
||||
| 373 | return $empty_val; |
||||
| 374 | } else { |
||||
| 375 | return (string)$Data; |
||||
| 376 | } |
||||
| 377 | } |
||||
| 378 | } |
||||
| 379 |