223 lines
7.8 KiB
PHP
223 lines
7.8 KiB
PHP
<?php
|
|
|
|
defined('ROOT_DIR') || exit;
|
|
|
|
class Search {
|
|
public array $query;
|
|
private string $sql_query = "";
|
|
private array $variables = array();
|
|
public int $count = 0;
|
|
|
|
public function __construct($query)
|
|
{
|
|
$this->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);
|
|
}
|
|
} |