Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/classes/general/sql_util.php |
<?php /* * SQL Helper */ class CSqlUtil { public static function GetCount($tableName, $tableAlias, &$arFields, &$arFilter) { $tableName = strval($tableName); if($tableName === '') { return false; } global $DB; $sql = "SELECT COUNT(*) AS QTY FROM {$tableName}"; if(is_array($arFilter) && !empty($arFilter)) { if(!is_array($arFields)) { return false; } $arJoins = array(); $condition = self::PrepareWhere($arFields, $arFilter, $arJoins); if($condition !== '') { $tableAlias = strval($tableAlias); if($tableAlias !== '') { $sql .= " AS {$tableAlias}"; } $sql .= " WHERE {$condition}"; } } $dbResult = $DB->Query($sql); $arResult = $dbResult ? $dbResult->Fetch() : null; return $arResult !== null && isset($arResult['QTY']) ? intval($arResult['QTY']) : 0; } public static function GetFilterOperation($key) { $strNegative = "N"; if (mb_substr($key, 0, 1) == "!") { $key = mb_substr($key, 1); $strNegative = "Y"; } $strOrNull = "N"; if (mb_substr($key, 0, 1) == "+") { $key = mb_substr($key, 1); $strOrNull = "Y"; } if (mb_substr($key, 0, 2) == ">=") { $key = mb_substr($key, 2); $strOperation = ">="; } elseif (mb_substr($key, 0, 1) == ">") { $key = mb_substr($key, 1); $strOperation = ">"; } elseif (mb_substr($key, 0, 2) == "<=") { $key = mb_substr($key, 2); $strOperation = "<="; } elseif (mb_substr($key, 0, 1) == "<") { $key = mb_substr($key, 1); $strOperation = "<"; } elseif (mb_substr($key, 0, 1) == "@") { $key = mb_substr($key, 1); $strOperation = "IN"; } elseif (mb_substr($key, 0, 2) == "=%") { $key = mb_substr($key, 2); $strOperation = "RLIKE"; } elseif (mb_substr($key, 0, 2) == "%=") { $key = mb_substr($key, 2); $strOperation = "LLIKE"; } elseif (mb_substr($key, 0, 1) == "%") { $key = mb_substr($key, 1); $strOperation = "LIKE"; } elseif (mb_substr($key, 0, 1) == "?") { $key = mb_substr($key, 1); $strOperation = "QUERY"; } elseif (mb_substr($key, 0, 2) == "*=") { $key = mb_substr($key, 2); $strOperation = "FTI"; } elseif (mb_substr($key, 0, 2) == "*%") { $key = mb_substr($key, 2); $strOperation = "FTL"; } elseif (mb_substr($key, 0, 1) == "*") { $key = mb_substr($key, 1); $strOperation = "FT"; } elseif (mb_substr($key, 0, 1) == "=") { $key = mb_substr($key, 1); $strOperation = "="; } else { $strOperation = "="; } return array("FIELD" => $key, "NEGATIVE" => $strNegative, "OPERATION" => $strOperation, "OR_NULL" => $strOrNull); } private static function AddToSelect($fieldKey, $arField, &$strSqlSelect) { global $DB; if ($strSqlSelect <> '') $strSqlSelect .= ", "; if ($arField["TYPE"] == "datetime") { $strSqlSelect .= $DB->DateToCharFunction($arField["FIELD"], "FULL")." as ".$fieldKey; } elseif ($arField["TYPE"] == "date") { $strSqlSelect .= $DB->DateToCharFunction($arField["FIELD"], "SHORT")." as ".$fieldKey; } else { $strSqlSelect .= $arField["FIELD"]." as ".$fieldKey; } } private static function AddToFrom($arField, &$arJoined, &$strSqlFrom) { if (isset($arField["FROM"]) && $arField["FROM"] <> '' && !in_array($arField["FROM"], $arJoined)) { if ($strSqlFrom <> '') $strSqlFrom .= " "; $strSqlFrom .= $arField["FROM"]; $arJoined[] = $arField["FROM"]; } } private static function PrepareDefaultFields($arFields, &$arJoined, &$strSqlSelect, &$strSqlFrom) { $arFieldsKeys = array_keys($arFields); $qty = count($arFieldsKeys); for ($i = 0; $i < $qty; $i++) { if (isset($arFields[$arFieldsKeys[$i]]["WHERE_ONLY"]) && $arFields[$arFieldsKeys[$i]]["WHERE_ONLY"] == "Y") { continue; } if (isset($arFields[$arFieldsKeys[$i]]["DEFAULT"]) && $arFields[$arFieldsKeys[$i]]["DEFAULT"] == "N") { continue; } self::AddToSelect($arFieldsKeys[$i], $arFields[$arFieldsKeys[$i]], $strSqlSelect); self::AddToFrom($arFields[$arFieldsKeys[$i]], $arJoined, $strSqlFrom); } } public static function PrepareSql(&$arFields, $arOrder, $arFilter, $arGroupBy, $arSelectFields, $arOptions = array()) { global $DB; if(!is_array($arOptions)) { $arOptions = array(); } $strSqlSelect = ''; $strSqlFrom = ''; $strSqlFromWhere = ''; $strSqlGroupBy = ''; $arGroupByFunct = array("COUNT", "AVG", "MIN", "MAX", "SUM"); $arAlreadyJoined = array(); // GROUP BY --> if (is_array($arGroupBy) && !empty($arGroupBy)) { $arSelectFields = $arGroupBy; foreach ($arGroupBy as $key => $val) { $val = mb_strtoupper($val); $key = mb_strtoupper($key); if (array_key_exists($val, $arFields) && !in_array($key, $arGroupByFunct)) { if ($strSqlGroupBy <> '') $strSqlGroupBy .= ", "; $strSqlGroupBy .= $arFields[$val]["FIELD"]; if (isset($arFields[$val]["FROM"]) && $arFields[$val]["FROM"] <> '' && !in_array($arFields[$val]["FROM"], $arAlreadyJoined)) { if ($strSqlFrom <> '') $strSqlFrom .= " "; $strSqlFrom .= $arFields[$val]["FROM"]; $arAlreadyJoined[] = $arFields[$val]["FROM"]; } } } } // <-- GROUP BY // SELECT --> $arFieldsKeys = array_keys($arFields); if (is_array($arGroupBy) && empty($arGroupBy)) { $strSqlSelect = "COUNT(%%_DISTINCT_%% ".$arFields[$arFieldsKeys[0]]["FIELD"].") as CNT "; } else { if (isset($arSelectFields) && is_string($arSelectFields) && $arSelectFields <> '' && array_key_exists($arSelectFields, $arFields)) $arSelectFields = array($arSelectFields); if (empty($arSelectFields) || !is_array($arSelectFields)) { self::PrepareDefaultFields($arFields, $arAlreadyJoined, $strSqlSelect, $strSqlFrom); } else { foreach ($arSelectFields as $key => $val) { if($val === '*') { self::PrepareDefaultFields($arFields, $arAlreadyJoined, $strSqlSelect, $strSqlFrom); } $val = mb_strtoupper($val); $key = mb_strtoupper($key); if (!array_key_exists($val, $arFields)) { continue; } if (in_array($key, $arGroupByFunct)) { if ($strSqlSelect <> '') $strSqlSelect .= ", "; $strSqlSelect .= $key."(".$arFields[$val]["FIELD"].") as ".$val; } else { self::AddToSelect($val, $arFields[$val], $strSqlSelect); } self::AddToFrom($arFields[$val], $arAlreadyJoined, $strSqlFrom); } } if($strSqlGroupBy === '') { $strSqlSelect = "%%_DISTINCT_%% ".$strSqlSelect; } elseif(!isset($arOptions['ENABLE_GROUPING_COUNT']) || $arOptions['ENABLE_GROUPING_COUNT'] === true) { if ($strSqlSelect <> '') $strSqlSelect .= ", "; $strSqlSelect .= "COUNT(%%_DISTINCT_%% ".$arFields[$arFieldsKeys[0]]["FIELD"].") as CNT"; } } // <-- SELECT // WHERE --> $arJoins = array(); $strSqlWhere = self::PrepareWhere($arFields, $arFilter, $arJoins); foreach($arJoins as $join) { if($join === '') { continue; } if ($strSqlFromWhere !== '') { $strSqlFromWhere .= ' '; } $strSqlFromWhere .= $join; if(!in_array($join, $arAlreadyJoined)) { if ($strSqlFrom !== '') { $strSqlFrom .= ' '; } $strSqlFrom .= $join; $arAlreadyJoined[] = $join; } } // <-- WHERE // ORDER BY --> $arSqlOrder = array(); $dbType = $DB->type; $nullsLast = isset($arOptions['NULLS_LAST']) ? (bool)$arOptions['NULLS_LAST'] : false; foreach ($arOrder as $by => $order) { $by = mb_strtoupper($by); $order = mb_strtoupper($order); if ($order != "ASC") $order = "DESC"; if (array_key_exists($by, $arFields)) { if(!$nullsLast) { if($dbType !== "ORACLE") { $arSqlOrder[] = $arFields[$by]["FIELD"]." ".$order; } else { if($order === 'ASC') $arSqlOrder[] = $arFields[$by]["FIELD"]." ".$order." NULLS FIRST"; else $arSqlOrder[] = $arFields[$by]["FIELD"]." ".$order." NULLS LAST"; } } else { if($dbType === "MYSQL") { //Use MySql feature for sort in 'NULLS_LAST' mode if($order === 'ASC') $arSqlOrder[] = "-".$arFields[$by]["FIELD"]." DESC"; else $arSqlOrder[] = $arFields[$by]["FIELD"]." ".$order; } } if (isset($arFields[$by]["FROM"]) && $arFields[$by]["FROM"] <> '' && !in_array($arFields[$by]["FROM"], $arAlreadyJoined)) { if ($strSqlFrom <> '') $strSqlFrom .= " "; $strSqlFrom .= $arFields[$by]["FROM"]; $arAlreadyJoined[] = $arFields[$by]["FROM"]; } } } $strSqlOrderBy = ''; DelDuplicateSort($arSqlOrder); $sqlOrderQty = count($arSqlOrder); for ($i = 0; $i < $sqlOrderQty; $i++) { if ($strSqlOrderBy <> '') $strSqlOrderBy .= ", "; $strSqlOrderBy .= $arSqlOrder[$i]; } // <-- ORDER BY return array( "SELECT" => $strSqlSelect, "FROM" => $strSqlFrom, "WHERE" => $strSqlWhere, "FROM_WHERE" => $strSqlFromWhere, "GROUPBY" => $strSqlGroupBy, "ORDERBY" => $strSqlOrderBy ); } public static function PrepareWhere(&$arFields, &$arFilter, &$arJoins) { global $DB; $arSqlSearch = Array(); if (!is_array($arFilter)) $arFilter = Array(); foreach ($arFilter as $filterKey => $vals) { if (!is_array($vals)) $vals = array($vals); if(str_starts_with($filterKey, '__INNER_FILTER')) { $innerFilterSql = self::PrepareWhere($arFields, $vals, $arJoins); if(is_string($innerFilterSql) && $innerFilterSql !== '') { $arSqlSearch[] = '('.$innerFilterSql.')'; } continue; } $key_res = self::GetFilterOperation($filterKey); $key = $key_res["FIELD"]; $strNegative = $key_res["NEGATIVE"]; $strOperation = $key_res["OPERATION"]; $strOrNull = $key_res["OR_NULL"]; if (array_key_exists($key, $arFields)) { $arSqlSearch_tmp = array(); if (!empty($vals)) { if ($strOperation == "IN") { if (isset($arFields[$key]["WHERE"])) { $arSqlSearch_tmp1 = call_user_func_array( $arFields[$key]["WHERE"], array($vals, $key, $strOperation, $strNegative, $arFields[$key]["FIELD"], &$arFields, &$arFilter) ); if ($arSqlSearch_tmp1 !== false) $arSqlSearch_tmp[] = $arSqlSearch_tmp1; } else { if ($arFields[$key]["TYPE"] == "int") { array_walk( $vals, function (&$item) { $item = (int)$item; } ); $vals = array_unique($vals); $val = implode(",", $vals); if (empty($vals)) $arSqlSearch_tmp[] = "(1 = 2)"; else $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." IN (".$val."))"; } elseif ($arFields[$key]["TYPE"] == "double") { array_walk( $vals, function (&$item) { $item = (float)$item; } ); $vals = array_unique($vals); $val = implode(",", $vals); if (empty($vals)) $arSqlSearch_tmp[] = "(1 = 2)"; else $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))"; } elseif ($arFields[$key]["TYPE"] == "string" || $arFields[$key]["TYPE"] == "char") { array_walk( $vals, function (&$item) { $item = "'".$GLOBALS["DB"]->ForSql($item)."'"; } ); $vals = array_unique($vals); $val = implode(",", $vals); if (empty($vals)) $arSqlSearch_tmp[] = "(1 = 2)"; else $arSqlSearch_tmp[] = (($strNegative == "Y") ? " NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))"; } elseif ($arFields[$key]["TYPE"] == "datetime") { array_walk( $vals, function (&$item) { $item = $GLOBALS["DB"]->CharToDateFunction($item, "FULL"); } ); $vals = array_unique($vals); $val = implode(",", $vals); if (empty($vals)) $arSqlSearch_tmp[] = "1 = 2"; else $arSqlSearch_tmp[] = ($strNegative=="Y"?" NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))"; } elseif ($arFields[$key]["TYPE"] == "date") { array_walk( $vals, function (&$item) { $item = $GLOBALS["DB"]->CharToDateFunction($item, "SHORT"); } ); $vals = array_unique($vals); $val = implode(",", $vals); if (empty($vals)) $arSqlSearch_tmp[] = "1 = 2"; else $arSqlSearch_tmp[] = ($strNegative=="Y"?" NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." (".$val."))"; } } } else { foreach ($vals as $val) { if (isset($arFields[$key]["WHERE"])) { $arSqlSearch_tmp1 = call_user_func_array( $arFields[$key]["WHERE"], array($val, $key, $strOperation, $strNegative, $arFields[$key]["FIELD"], &$arFields, &$arFilter) ); if ($arSqlSearch_tmp1 !== false) $arSqlSearch_tmp[] = $arSqlSearch_tmp1; } else { $fieldType = $arFields[$key]["TYPE"]; $fieldName = $arFields[$key]["FIELD"]; if ($strOperation === "QUERY" && $fieldType !== "string" && $fieldType !== "char") { // Ignore QUERY operation for not character types - QUERY is supported only for character types. $strOperation = '='; } if (($strOperation === "LIKE" || $strOperation === "RLIKE" || $strOperation === "LLIKE") && ($fieldType === "int" || $fieldType === "double")) { // Ignore LIKE operation for numeric types. $strOperation = '='; } if ($fieldType === "int") { if ((intval($val) === 0) && (str_contains($strOperation, "="))) $arSqlSearch_tmp[] = "(".$arFields[$key]["FIELD"]." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND" : "OR")." ".(($strNegative == "Y") ? "NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." 0)"; else { $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$arFields[$key]["FIELD"]." IS NULL OR NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".intval($val)." )"; } } elseif ($fieldType === "double") { $val = str_replace(",", ".", $val); if ((doubleval($val) == 0) && (str_contains($strOperation, "="))) $arSqlSearch_tmp[] = "(".$arFields[$key]["FIELD"]." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND" : "OR")." ".(($strNegative == "Y") ? "NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." 0)"; else $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$arFields[$key]["FIELD"]." IS NULL OR NOT " : "")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".DoubleVal($val)." )"; } elseif ($fieldType === "string" || $fieldType === "char") { if ($strOperation === "QUERY") { $arSqlSearch_tmp[] = GetFilterQuery($fieldName, $val, "Y"); } else { if (($val == '') && (str_contains($strOperation, "="))) { $arSqlSearch_tmp[] = "(".$fieldName." IS ".(($strNegative == "Y") ? "NOT " : "")."NULL) ".(($strNegative == "Y") ? "AND NOT" : "OR")." (".$DB->Length($fieldName)." <= 0) ".(($strNegative == "Y") ? "AND NOT" : "OR")." (".$fieldName." ".$strOperation." '".$DB->ForSql($val)."' )"; } else { if($strOperation === "LIKE") { if(is_array($val)) $arSqlSearch_tmp[] = "(".$fieldName." LIKE '%".implode("%' ESCAPE '!' OR ".$fieldName." LIKE '%", self::ForLike($val))."%' ESCAPE '!')"; elseif($val == '') $arSqlSearch_tmp[] = $fieldName; else $arSqlSearch_tmp[] = $fieldName." LIKE '%".self::ForLike($val)."%' ESCAPE '!'"; } elseif($strOperation === "RLIKE" || $strOperation === "LLIKE") { if(is_array($val)) $arSqlSearch_tmp[] = "(".$fieldName." LIKE '".implode("' OR ". $fieldName." LIKE '", $DB->ForSql($val))."')"; elseif($val == '') $arSqlSearch_tmp[] = $fieldName; else $arSqlSearch_tmp[] = $fieldName." LIKE '".$DB->ForSql($val)."'"; } elseif($strOperation === "FT" || $strOperation === "FTI" || $strOperation === "FTL") { $queryWhere = new CSQLWhere(); $queryWhere->SetFields( array( $key => array( 'FIELD_NAME' => $fieldName, 'FIELD_TYPE' => 'string', 'JOIN' => false ) ) ); $query = $queryWhere->GetQuery(array($filterKey => $val)); if($query !== '') { $arSqlSearch_tmp[] = $query; } } else $arSqlSearch_tmp[] = (($strNegative == "Y") ? " ".$fieldName." IS NULL OR NOT " : "")."(".$fieldName." ".$strOperation." '".$DB->ForSql($val)."' )"; } } } elseif ($fieldType === "datetime") { if(!in_array($strOperation, array('=', '<', '>', '<=', '>='), true)) { $strOperation = '='; } if ($val == '') $arSqlSearch_tmp[] = ($strNegative=="Y"?"NOT":"")."(".$arFields[$key]["FIELD"]." IS NULL)"; elseif (mb_strtoupper($val) === "NOW") $arSqlSearch_tmp[] = ($strNegative=="Y"?" ".$arFields[$key]["FIELD"]." IS NULL OR NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".$DB->GetNowFunction().")"; else $arSqlSearch_tmp[] = ($strNegative=="Y"?" ".$arFields[$key]["FIELD"]." IS NULL OR NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".$DB->CharToDateFunction($DB->ForSql($val), "FULL").")"; } elseif ($fieldType === "date") { if(!in_array($strOperation, array('=', '<', '>', '<=', '>='), true)) { $strOperation = '='; } if ($val == '') $arSqlSearch_tmp[] = ($strNegative=="Y"?"NOT":"")."(".$arFields[$key]["FIELD"]." IS NULL)"; else $arSqlSearch_tmp[] = ($strNegative=="Y"?" ".$arFields[$key]["FIELD"]." IS NULL OR NOT ":"")."(".$arFields[$key]["FIELD"]." ".$strOperation." ".$DB->CharToDateFunction($DB->ForSql($val), "SHORT").")"; } } } } } if (isset($arFields[$key]["FROM"]) && $arFields[$key]["FROM"] <> '' && !in_array($arFields[$key]["FROM"], $arJoins)) { $arJoins[] = $arFields[$key]["FROM"]; } $strSqlSearch_tmp = ""; $sqlSearchQty = count($arSqlSearch_tmp); for ($j = 0; $j < $sqlSearchQty; $j++) { if ($j > 0) $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR "); $strSqlSearch_tmp .= self::AddBrackets($arSqlSearch_tmp[$j]); } if ($strOrNull == "Y") { if ($strSqlSearch_tmp <> '') $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR "); $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." IS ".($strNegative=="Y" ? "NOT " : "")."NULL)"; if ($arFields[$key]["TYPE"] == "int" || $arFields[$key]["TYPE"] == "double") { if ($strSqlSearch_tmp <> '') $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR "); $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." ".($strNegative=="Y" ? "<>" : "=")." 0)"; } elseif ($arFields[$key]["TYPE"] == "string" || $arFields[$key]["TYPE"] == "char") { if ($strSqlSearch_tmp <> '') $strSqlSearch_tmp .= ($strNegative=="Y" ? " AND " : " OR "); $strSqlSearch_tmp .= "(".$arFields[$key]["FIELD"]." ".($strNegative=="Y" ? "<>" : "=")." '')"; } } if ($strSqlSearch_tmp != "") { $arSqlSearch[] = $strSqlSearch_tmp; } } } $logic = 'AND'; if(isset($arFilter['LOGIC']) && $arFilter['LOGIC'] !== '') { $logic = strtoupper($arFilter['LOGIC']); if($logic !== 'AND' && $logic !== 'OR') { $logic = 'AND'; } } $strSqlWhere = ''; $logic = " $logic "; foreach ($arSqlSearch as $searchItem) { if($searchItem === '') { continue; } if ($strSqlWhere !== '') $strSqlWhere .= $logic; $strSqlWhere .= "($searchItem)"; } return $strSqlWhere; } private static function AddBrackets($str) { return preg_match('/^\(.*\)$/s', $str) > 0 ? $str : "($str)"; } public static function GetRowCount($arSql, $tableName, $tableAlias = '') { global $DB; $tableName = strval($tableName); $tableAlias = strval($tableAlias); $query = 'SELECT COUNT(\'x\') as CNT FROM '.$tableName; if($tableAlias !== '') { $query .= ' '.$tableAlias; } if (isset($arSql['FROM'][0])) { $query .= ' '.$arSql['FROM']; } if (isset($arSql['WHERE'][0])) { $query .= ' WHERE '.$arSql['WHERE']; } if (isset($arSql['GROUPBY'][0])) { $query .= ' GROUP BY '.$arSql['GROUPBY']; } $rs = $DB->Query($query); //MYSQL, MSSQL, ORACLE $result = 0; while($ary = $rs->Fetch()) { $result += intval($ary['CNT']); } return $result; } public static function PrepareSelectTop(&$sql, $top) { $sql .= ' LIMIT '.$top; } private static function ForLike($str) { global $DB; static $search = array( "!", "_", "%"); static $replace = array("!!", "!_", "!%"); return str_replace($search, $replace, $DB->ForSQL($str)); } }