query = $query; list($sql_query, $variables) = $this->query_construct(); $this->sql_query = $sql_query; $this->variables = $variables; } // Извлечение данных из базы public function collect($fill = true, $new = true) { global $b; $result = $b->db_query($this->sql_query, $this->variables, $new); if(!$fill) return $result; $this->get_count(); $items = array(); foreach ($result as $key => $item) { $class = new $item["item_class"]($item["item_id"]); $class->fill_main_parent($item["item_parent"]); $class->props_values = $this->search_props($item, $class); $items[] = $class; } return $items; } // Поиск параметров private function search_props($item, $class): array { $props = explode("-+-", $item["properties"]); $values = explode("-+-", $item["values"]); $result = array(); for ($i = 0; $i < count($props); $i++) { $prop = $props[$i]; $value = $values[$i]; if(!isset($class->props[$prop])) continue; $result[$prop] = $value; } return $result; } // Получить количество элементов public function get_count(){ global $b; list($query_count, $variables) = $this->query_construct(true); $result = $b->db_query($query_count, $variables, false); $this->count = $result[0]["count"]; return $this; } // Создание запроса private function query_construct($count = false): array { $variables = array(); $props = $this->query["props"]; $params = $this->query["terms"] ?? array(); if(isset($this->query["class"])) $params["item_class"] = $this->query["class"]; if(isset($this->query["parent_id"])) $params["item_parent"] = $this->query["parent_id"]; $limit = intval($this->query["limit"] ?? 184467440737); $offset = intval($this->query["offset"] ?? 0); $order = $this->query_order($this->query["order"]); $order_inner = $this->query_order_inner($this->query["order"]); $where_list = array(); list($where_props, $props_var) = $this->query_props($props); $variables = array_merge($variables, $props_var); list($where, $where_var) = $this->query_where($params); $variables = array_merge($variables, $where_var); if($where_props) $where_list[] = $where_props; if($where) $where_list[] = $where; $return_fields = "COUNT(*) as count"; $group_by = $join_props = $limit_query = $offset_query = ""; if(!$count){ $return_fields = " `bive_items`.* "; $group_by = " GROUP BY `bive_items`.`item_id` "; $limit_query = " LIMIT $limit "; $offset_query = " OFFSET $offset "; if(isset($params["item_class"])) { $return_fields = "`bive_items`.*, GROUP_CONCAT(p.prop_key SEPARATOR '-+-') AS properties, GROUP_CONCAT(p.prop_value SEPARATOR '-+-') AS `values`"; $join_props = " JOIN `bive_items_props` p ON `bive_items`.`item_id` = p.`item_id` "; $class = new $params["item_class"](0); if(!count($class->props)) { $return_fields = "`bive_items`.*"; $group_by = ""; $join_props = ""; } } } $where_collect = $this->query_binary($where_list); $result_query = "SELECT $return_fields FROM `bive_items` $join_props $order_inner WHERE $where_collect $group_by $order $limit_query $offset_query;"; return array($result_query, $variables); } // Соединение таблиц для сортировки private function query_order_inner($order): string { if(!isset($order) || !isset($order["key"])) return ""; $key = $order["key"]; return "INNER JOIN `bive_items_props` AS `bip` ON `bive_items`.`item_id` = `bip`.`item_id` AND `bip`.`prop_key` = '$key'"; } // Сортировка private function query_order($order): string { if(!isset($order) || !isset($order["key"])) return ""; $direction = $order["direction"] ?? "ASC"; $type = $order["direction"] == "numeric" ? "CAST(`bip`.`prop_value` AS SIGNED)" : "`bip`.`prop_value`"; return " ORDER BY $type $direction "; } private function query_binary($array, $operator = "AND"): string { return "(" . implode(" " . mb_strtoupper($operator) . " ", $array) . ")"; } // Условия поиска по свойствам private function query_props($props, $operator = "and"): array { if(!$props || !count($props)) return array("", array()); $sql = array(); $variables = array(); foreach ($props as $key => $prop) { if($key == "and") { list($query, $var) = $this->query_props($prop, "and"); $sql[] = $query; $variables[] = $var; }else if($key == "or") { list($query, $var) = $this->query_props($prop, "or"); $sql[] = $query; $variables[] = $var; } else { list($key, $prop, $not, $op) = $this->query_operators($key, $prop); $sql[] = $not . "EXISTS ( SELECT 1 FROM bive_items_props WHERE bive_items.item_id = bive_items_props.item_id AND bive_items_props.prop_key = '$key' AND bive_items_props.prop_value $op ? )"; $variables[] = $prop; } } $string_query = $this->query_binary($sql, $operator); return array($string_query, $variables); } // Условия поиска по предметам private function query_where($where, $operator = "and"): array { if(!$where || !count($where)) return array("", array()); $sql = array(); $variables = array(); foreach ($where as $key => $prop) { if($key == "and") { list($query, $var) = $this->query_where($prop, "and"); $sql[] = $query; $variables = array(...$variables, ...$var); }else if($key == "or") { list($query, $var) = $this->query_where($prop, "or"); $sql[] = $query; $variables[] = array(...$variables, ...$var); } else { list($key, $prop, $not, $op) = $this->query_operators($key, $prop); $sql[] = "$not`bive_items`.`$key` $op ?"; $variables[] = $prop; } } $string_query = $this->query_binary($sql, $operator); return array($string_query, $variables); } private function query_operators($key, $prop): array { $not = ""; $op = " = "; // Добавление отрицания if(mb_substr($key, 0, 1) == "!") { $key = substr($key, 1); $not = " NOT "; } // Добавление конструкции LIKE if(mb_substr($key, 0, 1) == "%") { $prop = "%" . $prop; $key = substr($key, 1); $op = " LIKE "; } // Добавление конструкции LIKE if(mb_substr($key, -1) == "%") { $prop = $prop . "%"; $key = substr($key, 0, -1); $op = " LIKE "; } return array($key, $prop, $not, $op); } }