• Модуль: iblock
  • Путь к файлу: ~/bitrix/modules/iblock/classes/general/iblockelement.php
  • Класс: CAllIBlockElement
  • Вызов: CAllIBlockElement::MkFilter
public function MkFilter($arFilter, &$arJoinProps, &$arAddWhereFields, $level = 0, $bPropertyLeftJoin = false)
{
	global $DB, $USER;
	$connection = BitrixMainApplication::getConnection();
	$helper = $connection->getSqlHelper();

	$catalogIncluded = Loader::includeModule('catalog');
	$catalogFields = array();

	$arSqlSearch = Array();
	$permSQL = "";

	$arSectionFilter = Array(
		"LOGIC" => "",
		"BE" => array(),
		"BS" => array(),
	);

	if (!is_array($arFilter))
		$arFilter = array();

	foreach($arFilter as $key=>$val)
	{
		$key = mb_strtoupper($key);
		$p = mb_strpos($key, "PROPERTY_");
		if($p!==false && ($p<4))
		{
			$arFilter[mb_substr($key, 0, $p)."PROPERTY"][mb_substr($key, $p + 9)] = $val;
			unset($arFilter[$key]);
		}
		else
		{
			$p = strpos($key, 'SUBQUERY');
			if ($p !== false && $p <4)
			{
				if (!empty($val) && is_array($val))
				{
					$arFilter[substr($key, 0, $p).'ID'] = static::SubQuery(
						$val['FIELD'],
						$val['FILTER']
					);
				}
				unset($arFilter[$key]);
			}
		}
	}

	if (isset($arFilter["LOGIC"]) && $arFilter["LOGIC"] == "OR")
	{
		$Logic = "OR";
		unset($arFilter["LOGIC"]);
		$bPropertyLeftJoin = true;
	}
	else
	{
		$Logic = "AND";
	}

	if ($Logic === "AND" && $level === 0 && isset($arFilter["IBLOCK_ID"]))
	{
		$f = new BitrixIblockPropertyIndexQueryBuilder($arFilter["IBLOCK_ID"]);
		if ($f->isValid())
		{
			$arJoinProps["FC"] = $f->getFilterSql($arFilter, $arSqlSearch);
			$arJoinProps["FC_DISTINCT"] = $f->getDistinct();
		}
	}

	foreach($arFilter as $orig_key => $val)
	{
		$res = CIBlock::MkOperationFilter($orig_key);
		$key = $res["FIELD"];
		$cOperationType = $res["OPERATION"];

		//it was done before $key = strtoupper($key);

		switch($key."")
		{
		case "ACTIVE":
		case "DETAIL_TEXT_TYPE":
		case "PREVIEW_TEXT_TYPE":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "string_equal", $bFullJoinTmp, $cOperationType);
			break;
		case "NAME":
		case "XML_ID":
		case "TMP_ID":
		case "DETAIL_TEXT":
		case "PREVIEW_TEXT":
		case "CODE":
		case "TAGS":
		case "WF_COMMENTS":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "string", $bFullJoinTmp, $cOperationType);
			break;
		case "SEARCHABLE_CONTENT":
			if ($DB->IndexExists("b_iblock_element", array("SEARCHABLE_CONTENT")))
			{
				$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "fulltext", $bFullJoinTmp, $cOperationType);
			}
			else
			{
				if ($cOperationType == "FT")
					$cOperationType = "FTL";
				elseif ($cOperationType == "FTI")
					$cOperationType = "E";
				$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "string", $bFullJoinTmp, $cOperationType);
			}
			break;
		case "ID":
			if(is_object($val))
			{
				/** @var CIBlockElement $val */
				$val->prepareSql(array($val->strField), $val->arFilter, false, false);
				$arSqlSearch[] = 'BE.'.$key.(mb_substr($cOperationType, 0, 1) == "N"? ' NOT': '').' IN  (
					SELECT '.$val->sSelect.'
					FROM '.$val->sFrom.'
					WHERE 1=1
						'.$val->sWhere.'
					)'
				;
			}
			else
			{
				$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "number", $bFullJoinTmp, $cOperationType);
			}
			break;
		case "SHOW_COUNTER":
		case "WF_PARENT_ELEMENT_ID":
		case "WF_STATUS_ID":
		case "SORT":
		case "CREATED_BY":
		case "MODIFIED_BY":
		case "PREVIEW_PICTURE":
		case "DETAIL_PICTURE":
		case "IBLOCK_ID":
		case "IBLOCK_SECTION_ID":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.".$key, $val, "number", $bFullJoinTmp, $cOperationType);
			break;
		case "TIMESTAMP_X":
		case "DATE_CREATE":
		case "SHOW_COUNTER_START":
			$sqlSearch = CIBlock::FilterCreateEx("BE.".$key, $val, "date", $bFullJoinTmp, $cOperationType);
			if($sqlSearch <> '')
			{
				$arSqlSearch[] = $sqlSearch;
			}
			break;
		case "EXTERNAL_ID":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.XML_ID", $val, "string", $bFullJoinTmp, $cOperationType);
			break;
		case "IBLOCK_TYPE":
			$arSqlSearch[] = CIBlock::FilterCreateEx("B.IBLOCK_TYPE_ID", $val, "string", $bFullJoinTmp, $cOperationType);
			break;
		case "CHECK_PERMISSIONS":
			if ($val == 'Y')
			{
				$arFilter['MIN_PERMISSION'] ??= CIBlockRights::PUBLIC_READ;
				$permissionsBy = null;
				if (isset($arFilter['PERMISSIONS_BY']))
				{
					$permissionsBy = (int)$arFilter['PERMISSIONS_BY'];
					if ($permissionsBy < 0)
						$permissionsBy = null;
				}
				if ($permissionsBy !== null)
					$permSQL = self::_check_rights_sql($arFilter["MIN_PERMISSION"], $permissionsBy);
				elseif (!is_object($USER) || !$USER->IsAdmin())
					$permSQL = self::_check_rights_sql($arFilter["MIN_PERMISSION"]);
				unset($permissionsBy);
			}
			break;
		case "CHECK_BP_PERMISSIONS":
			if(IsModuleInstalled('bizproc') && (!is_object($USER) || !$USER->IsAdmin()))
			{
				if(is_array($val))
				{
					$MODULE_ID = $DB->ForSQL($val["MODULE_ID"]);
					$ENTITY = $DB->ForSQL($val["ENTITY"]);
					$PERMISSION = $DB->ForSQL($val["PERMISSION"]);
					$arUserGroups = array();
					if(is_array($val["GROUPS"]))
					{
						$USER_ID = intval($val["USER_ID"]);
						foreach($val["GROUPS"] as $GROUP_ID)
						{
							$GROUP_ID = intval($GROUP_ID);
							if($GROUP_ID)
								$arUserGroups[$GROUP_ID] = $GROUP_ID;
						}
					}
					else
					{
						$USER_ID = 0;
					}
				}
				else
				{
					$MODULE_ID = "iblock";
					$ENTITY = "CIBlockDocument";
					$PERMISSION = $val;
					$arUserGroups = false;
					$USER_ID = 0;
				}

				if($PERMISSION == "read" || $PERMISSION == "write")
				{
					if(!is_array($arUserGroups) && is_object($USER))
					{
						$USER_ID = intval($USER->GetID());
						$arUserGroups = $USER->GetUserGroupArray();
					}

					if(!is_array($arUserGroups) || count($arUserGroups) <= 0)
						$arUserGroups = array(2);

					$arSqlSearch[] = "EXISTS (
						SELECT S.DOCUMENT_ID_INT
						FROM
						b_bp_workflow_state S
						INNER JOIN b_bp_workflow_permissions P ON S.ID = P.WORKFLOW_ID
						WHERE
							S.DOCUMENT_ID_INT = BE.ID
							AND S.MODULE_ID = '$MODULE_ID'
							AND S.ENTITY = '$ENTITY'
							AND P.PERMISSION = '$PERMISSION'
							AND (
								P.OBJECT_ID IN ('".implode("', '", $arUserGroups)."')
								OR (P.OBJECT_ID = 'Author' AND BE.CREATED_BY = $USER_ID)
								OR (P.OBJECT_ID = ".$DB->Concat("'USER_'", "'$USER_ID'").")
							)
					)";
				}
			}
			break;
		case "CHECK_BP_VIRTUAL_PERMISSIONS":
			if (
				IsModuleInstalled('bizproc')
				&& (!is_object($USER) || !$USER->IsAdmin())
			)
			{
				if (!in_array($val, array("read", "create", "admin")))
					$val = "admin";

				$userId = is_object($USER)? (int)$USER->GetID(): 0;
				$arUserGroups = is_object($USER)? $USER->GetUserGroupArray(): false;

				if (!is_array($arUserGroups) || empty($arUserGroups))
					$arUserGroups = array(2);

				$arSqlSearch[] = "EXISTS (
					SELECT S.DOCUMENT_ID_INT
					FROM b_bp_workflow_state S
						INNER JOIN b_bp_workflow_permissions P ON S.ID = P.WORKFLOW_ID
					WHERE S.DOCUMENT_ID_INT = BE.ID
						AND S.MODULE_ID = 'bizproc'
						AND S.ENTITY = 'CBPVirtualDocument'
						AND
							(P.PERMISSION = '".$val."'
							AND (
								P.OBJECT_ID IN ('".implode("', '", $arUserGroups)."')
								OR (P.OBJECT_ID = 'Author' AND BE.CREATED_BY = ".$userId.")
								OR (P.OBJECT_ID = ".$DB->Concat("'USER_'", "'".$userId."'").")
							)
						)
				)";
			}
			break;
		case "LID":
		case "SITE_ID":
		case "IBLOCK_LID":
		case "IBLOCK_SITE_ID":
			$flt = CIBlock::FilterCreateEx("SITE_ID", $val, "string_equal", $bFullJoinTmp, $cOperationType);
			if ($flt !== '')
				$arSqlSearch[] = ($cOperationType == "N" ? "NOT " : "")."EXISTS (
					SELECT IBLOCK_ID FROM b_iblock_site WHERE IBLOCK_ID = B.ID
					AND ".$flt."
				)";
			break;
		case "DATE_ACTIVE_FROM":
			$sqlSearch = CIBlock::FilterCreateEx("BE.ACTIVE_FROM", $val, "date", $bFullJoinTmp, $cOperationType);
			if ($sqlSearch <> '')
			{
				$arSqlSearch[] = $sqlSearch;
			}
			break;
		case "DATE_ACTIVE_TO":
			$sqlSearch = CIBlock::FilterCreateEx("BE.ACTIVE_TO", $val, "date", $bFullJoinTmp, $cOperationType);
			if ($sqlSearch <> '')
			{
				$arSqlSearch[] = $sqlSearch;
			}
			break;
		case "IBLOCK_ACTIVE":
			$arSqlSearch[] = CIBlock::FilterCreateEx("B.ACTIVE", $val, "string_equal", $bFullJoinTmp, $cOperationType);
			break;
		case "IBLOCK_CODE":
			$arSqlSearch[] = CIBlock::FilterCreateEx("B.CODE", $val, "string", $bFullJoinTmp, $cOperationType);
			break;
		case "ID_ABOVE":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.ID", $val, "number_above", $bFullJoinTmp, $cOperationType);
			break;
		case "ID_LESS":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.ID", $val, "number_less", $bFullJoinTmp, $cOperationType);
			break;
		case "ACTIVE_FROM":
			$val = (string)$val;
			if ($val !== '')
			{
				$isCorrect = CIBlock::isCorrectFullFormatDate($DB->ForSql($val));
				if ($isCorrect)
				{
					$arSqlSearch[] = "(BE.ACTIVE_FROM "
						. ($cOperationType == "N" ? "<" : ">=")
						. $DB->CharToDateFunction($DB->ForSql($val), "FULL")
						. ($cOperationType == "N" ? "" : " OR BE.ACTIVE_FROM IS NULL")
						. ")";
				}
			}
			break;
		case "ACTIVE_TO":
			$val = (string)$val;
			if ($val !== '')
			{
				$isCorrect = CIBlock::isCorrectFullFormatDate($DB->ForSql($val));
				if ($isCorrect)
				{
					$arSqlSearch[] = "(BE.ACTIVE_TO "
						. ($cOperationType == "N" ? ">" : "<=")
						. $DB->CharToDateFunction($DB->ForSql($val), "FULL")
						. ($cOperationType == "N" ? "" : " OR BE.ACTIVE_TO IS NULL")
						. ")";
				}
			}
			break;
		case "ACTIVE_DATE":
			$val = (string)$val;
			if($val !== '')
				$arSqlSearch[] = ($cOperationType=="N"?" NOT":"")."((BE.ACTIVE_TO >= ".$DB->GetNowFunction()." OR BE.ACTIVE_TO IS NULL) AND (BE.ACTIVE_FROM <= ".$DB->GetNowFunction()." OR BE.ACTIVE_FROM IS NULL))";
			break;
		case "DATE_MODIFY_FROM":
			$val = (string)$val;
			if ($val !== '')
			{
				$isCorrect = CIBlock::isCorrectFullFormatDate($DB->ForSql($val));
				if ($isCorrect)
				{
					$arSqlSearch[] = "(BE.TIMESTAMP_X " .
						($cOperationType == "N" ? "<" : ">=") . $DB->CharToDateFunction($DB->ForSql($val), "FULL") .
						($cOperationType == "N" ? "" : " OR BE.TIMESTAMP_X IS NULL") . ")";
				}
			}
			break;
		case "DATE_MODIFY_TO":
			$val = (string)$val;
			if ($val !== '')
			{
				$isCorrect = CIBlock::isCorrectFullFormatDate($DB->ForSql($val));
				if ($isCorrect)
				{
					$arSqlSearch[] = "(BE.TIMESTAMP_X " .
						($cOperationType == "N" ? ">" : "<=") . $DB->CharToDateFunction($DB->ForSql($val), "FULL") .
						($cOperationType == "N" ? "" : " OR BE.TIMESTAMP_X IS NULL") . ")";
				}
			}
			break;
		case "WF_NEW":
			if($val=="Y" || $val=="N")
				$arSqlSearch[] = CIBlock::FilterCreateEx("BE.WF_NEW", "Y", "string_equal", $bFullJoinTmp, ($val=="Y"?false:true), false);
			break;
		case "MODIFIED_USER_ID":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.MODIFIED_BY", $val, "number", $bFullJoinTmp, $cOperationType);
			break;
		case "CREATED_USER_ID":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.CREATED_BY", $val, "number", $bFullJoinTmp, $cOperationType);
			break;
		case "RATING_USER_ID":
			$arSqlSearch[] = CIBlock::FilterCreateEx("RVV.USER_ID", $val, "number", $bFullJoinTmp, $cOperationType);
			$arJoinProps["RVV"] = array(
				"bFullJoin" => $bFullJoinTmp,
			);
			break;
		case "WF_STATUS":
			$arSqlSearch[] = CIBlock::FilterCreateEx("BE.WF_STATUS_ID", $val, "number", $bFullJoinTmp, $cOperationType);
			break;
		case "WF_LOCK_STATUS":
			if($val <> '')
			{
				$USER_ID = is_object($USER)? intval($USER->GetID()): 0;
				$lockInterval = COption::GetOptionInt("workflow", "MAX_LOCK_TIME", 60) * 60;
				$arSqlSearch[] = "case when BE.WF_DATE_LOCK is null then 'green' when " . $helper->addSecondsToDateTime($lockInterval, 'BE.WF_DATE_LOCK') . " < " . $helper->getCurrentDateTimeFunction() . " then 'green' when BE.WF_LOCKED_BY = " . $USER_ID . " then 'yellow' else 'red' end) = '" . $DB->ForSql($val) . "'";
			}
			break;
		case "WF_LAST_STATUS_ID":
			$arSqlSearch[] = "exists (
				select
					history.ID
				from
					b_iblock_element history
				where
					history.WF_PARENT_ELEMENT_ID = BE.ID
					and history.WF_STATUS_ID = ".intval($val)."
					and history.ID = (
						select max(history0.ID) LAST_ID
						from b_iblock_element history0
						where history0.WF_PARENT_ELEMENT_ID = BE.ID
					)
			)
			";
			break;
		case "SECTION_ACTIVE":
			if($arFilter["INCLUDE_SUBSECTIONS"]==="Y")
				$arSectionFilter["BS"][] = "BSubS.ACTIVE = 'Y'";
			else
				$arSectionFilter["BS"][] = "BS.ACTIVE = 'Y'";
			break;
		case "SECTION_GLOBAL_ACTIVE":
			if($arFilter["INCLUDE_SUBSECTIONS"]==="Y")
				$arSectionFilter["BS"][] = "BSubS.GLOBAL_ACTIVE = 'Y'";
			else
				$arSectionFilter["BS"][] = "BS.GLOBAL_ACTIVE = 'Y'";
			break;
		case "SUBSECTION":
			if (!is_array($val))
				$val=Array($val);
			//Find out margins of sections
			$arUnknownMargins = array();
			foreach($val as $i=>$section)
			{
				if(!is_array($section))
					$arUnknownMargins[intval($section)] = intval($section);
			}
			if (!empty($arUnknownMargins))
			{
				$rs = $DB->Query("SELECT ID, LEFT_MARGIN, RIGHT_MARGIN FROM b_iblock_section WHERE ID in (".implode(", ", $arUnknownMargins).")");
				while($ar = $rs->Fetch())
				{
					$arUnknownMargins[intval($ar["ID"])] = array(
						intval($ar["LEFT_MARGIN"]),
						intval($ar["RIGHT_MARGIN"]),
					);
				}
				foreach($val as $i=>$section)
				{
					if(!is_array($section))
						$val[$i] = $arUnknownMargins[intval($section)];
				}
			}
			//Now sort them out
			$arMargins = array();
			foreach($val as $i=>$section)
			{
				if(is_array($section) && (count($section) == 2))
				{
					$left = intval($section[0]);
					$right = intval($section[1]);
					if($left > 0 && $right > 0)
						$arMargins[$left] = $right;
				}
			}
			ksort($arMargins);
			//Remove subsubsections of the sections
			$prev_right = 0;
			foreach($arMargins as $left => $right)
			{
				if($right <= $prev_right)
					unset($arMargins[$left]);
				else
					$prev_right = $right;
			}

			if(isset($arFilter["INCLUDE_SUBSECTIONS"]) && $arFilter["INCLUDE_SUBSECTIONS"] === "Y")
				$bsAlias = "BSubS";
			else
				$bsAlias = "BS";

			$res = "";
			foreach($arMargins as $left => $right)
			{
				if($res!="")
					$res .= ($cOperationType=="N"?" AND ":" OR ");
				$res .= ($cOperationType == "N"? " NOT ": " ")."($bsAlias.LEFT_MARGIN >= ".$left." AND $bsAlias.RIGHT_MARGIN <= ".$right.")n";;
			}

			if($res!="")
				$arSectionFilter["BS"][] = "(".$res.")";
			break;
		case "SECTION_ID":
			if(!is_array($val))
				$val = array($val);

			$arSections = array();
			foreach($val as $section_id)
			{
				$section_id = (int)$section_id;
				$arSections[$section_id] = $section_id;
			}

			if($cOperationType=="N")
			{
				if (isset($arSections[0]))
				{
					$arSectionFilter["BE"][] = "BE.IN_SECTIONS<>'N'";
					$arSectionFilter["LOGIC"] = "AND";
					unset($arSections[0]);
					if(!empty($arSections))
						$arSectionFilter["BS"][] = "BS.ID NOT IN (".implode(", ", $arSections).")";
				}
				elseif(!empty($arSections))
				{
					$arSectionFilter["BE"][] = "BE.IN_SECTIONS='N'";
					$arSectionFilter["LOGIC"] = "OR";
					$arSectionFilter["BS"][] = "BS.ID NOT IN (".implode(", ", $arSections).")";
				}
			}
			else
			{
				if (isset($arSections[0]))
				{
					$allSections = (
						isset($arFilter["INCLUDE_SUBSECTIONS"])
						&& $arFilter["INCLUDE_SUBSECTIONS"] === "Y"
						&& count($arSections) == 1
					);
					if (!$allSections)
					{
						$arSectionFilter["BE"][] = "BE.IN_SECTIONS='N'";
						$arSectionFilter["LOGIC"] = "OR";
					}
					unset($arSections[0]);
				}
				if(!empty($arSections))
					$arSectionFilter["BS"][] = "BS.ID IN (".implode(", ", $arSections).")";
			}
			break;
		case "SECTION_CODE":
			if(!is_array($val))
				$val = array($val);

			$arSections = array();
			foreach($val as $section_code)
			{
				$section_code = $DB->ForSql($section_code);
				$arSections[$section_code] = $section_code;
			}

			if($cOperationType=="N")
			{
				if(array_key_exists("", $arSections))
				{
					$arSectionFilter["BE"][] = "BE.IN_SECTIONS<>'N'";
					$arSectionFilter["LOGIC"] = "AND";
					unset($arSections[""]);
					if(!empty($arSections))
						$arSectionFilter["BS"][] = "BS.CODE NOT IN ('".implode("', '", $arSections)."')";
				}
				elseif(!empty($arSections))
				{
					$arSectionFilter["BE"][] = "BE.IN_SECTIONS='N'";
					$arSectionFilter["LOGIC"] = "OR";
					$arSectionFilter["BS"][] = "BS.CODE NOT IN ('".implode("', '", $arSections)."')";
				}
			}
			else
			{
				if(array_key_exists("", $arSections))
				{
					$arSectionFilter["BE"][] = "BE.IN_SECTIONS='N'";
					$arSectionFilter["LOGIC"] = "OR";
					unset($arSections[""]);
				}
				if(!empty($arSections))
					$arSectionFilter["BS"][] = "BS.CODE IN ('".implode("', '", $arSections)."')";
			}
			break;
		case "PROPERTY":
			$iblockIds = CIBlock::_MergeIBArrays(
				$arFilter["IBLOCK_ID"] ?? false,
				$arFilter["IBLOCK_CODE"] ?? false,
				$arFilter["~IBLOCK_ID"] ?? false,
				$arFilter["~IBLOCK_CODE"] ?? false
			);
			foreach($val as $propID=>$propVAL)
			{
				$res = CIBlock::MkOperationFilter($propID);
				$res["LOGIC"] = $Logic;
				$res["LEFT_JOIN"] = $bPropertyLeftJoin;

				if(preg_match("/^([^.]+)\.([^.]+)$/", $res["FIELD"], $arMatch))
				{
					$db_prop = CIBlockProperty::GetPropertyArray($arMatch[1], $iblockIds);
					if(is_array($db_prop) && $db_prop["PROPERTY_TYPE"] == "E")
					{
						$res["FIELD"] = $arMatch;
						CIBlockElement::MkPropertyFilter($res, $cOperationType, $propVAL, $db_prop, $arJoinProps, $arSqlSearch);
					}
				}
				else
				{
					$db_prop = CIBlockProperty::GetPropertyArray($res["FIELD"], $iblockIds);
					if ($db_prop)
					{
						CIBlockElement::MkPropertyFilter($res, $cOperationType, $propVAL, $db_prop, $arJoinProps, $arSqlSearch);
					}
				}
			}
			unset($iblockIds);
			break;
		default:
			if(is_numeric($orig_key))
			{
				if (is_array($val))
				{
					//Here is hint for better property resolution:
					if (!isset($val["~IBLOCK_ID"]))
					{
						if (isset($arFilter["IBLOCK_ID"]))
							$val["~IBLOCK_ID"] = $arFilter["IBLOCK_ID"];
						elseif (isset($arFilter["~IBLOCK_ID"]))
							$val["~IBLOCK_ID"] = $arFilter["~IBLOCK_ID"];
					}
					if (!isset($val["~IBLOCK_CODE"]))
					{
						if (isset($arFilter["IBLOCK_CODE"]))
							$val["~IBLOCK_CODE"] = $arFilter["IBLOCK_CODE"];
						elseif (isset($arFilter["~IBLOCK_CODE"]))
							$val["~IBLOCK_CODE"] = $arFilter["~IBLOCK_CODE"];
					}
					//Subfilter process
					$arSubSqlSearch = CIBlockElement::MkFilter($val, $arJoinProps, $arAddWhereFields, $level + 1, $bPropertyLeftJoin);
					if(trim($arSubSqlSearch[0], "nt") <> '')
					{
						$arSqlSearch[] = str_replace("nttt", "ntttt", $arSubSqlSearch[0]);
					}
				}
			}
			elseif ($catalogIncluded && CProductQueryBuilder::isValidField($key))
			{
				$catalogFields[$orig_key] = $val;
				$arAddWhereFields[$orig_key] = $val;
			}
			break;
		}
	}
	if ($catalogIncluded && !empty($catalogFields))
	{
		$catalogQueryResult = CProductQueryBuilder::makeFilter($catalogFields);
		// catalog join set in CIBlockElement::prepareSql
		if (!empty($catalogQueryResult) && !empty($catalogQueryResult['filter']))
			$arSqlSearch = array_merge($arSqlSearch, $catalogQueryResult['filter']);
		unset($catalogQueryResult);
	}
	unset($catalogFields);

	//SECTION sub filter
	$sWhere = "";
	foreach($arSectionFilter["BS"] as $strFilter)
	{
		if ($strFilter !== '')
		{
			if ($sWhere !== '')
				$sWhere .= " ".$Logic." ";
			$sWhere .= "(".$strFilter.")";
		}
	}

	$bINCLUDE_SUBSECTIONS = isset($arFilter["INCLUDE_SUBSECTIONS"]) && $arFilter["INCLUDE_SUBSECTIONS"] === "Y";

	if($sWhere !== '')
	{
		$sectionScope = "";
		if (isset($arFilter["SECTION_SCOPE"]))
		{
			if ($arFilter["SECTION_SCOPE"] == "IBLOCK")
				$sectionScope = "AND BSE.ADDITIONAL_PROPERTY_ID IS NULL";
			elseif ($arFilter["SECTION_SCOPE"] == "PROPERTY")
				$sectionScope = "AND BSE.ADDITIONAL_PROPERTY_ID IS NOT NULL";
			elseif (preg_match("/^PROPERTY_(\d+)$/", $arFilter["SECTION_SCOPE"], $match))
				$sectionScope = "AND BSE.ADDITIONAL_PROPERTY_ID = ".$match[1];
		}

		//Try to convert correlated subquery to join subquery
		if($level == 0 && $Logic == "AND" && !count($arSectionFilter["BE"]))
		{
			$arJoinProps["BES"] .= " INNER JOIN (
				SELECT DISTINCT BSE.IBLOCK_ELEMENT_ID
				FROM b_iblock_section_element BSE
				".($bINCLUDE_SUBSECTIONS? "
				INNER JOIN b_iblock_section BSubS ON BSE.IBLOCK_SECTION_ID = BSubS.ID
				INNER JOIN b_iblock_section BS ON (BSubS.IBLOCK_ID=BS.IBLOCK_ID
					AND BSubS.LEFT_MARGIN>=BS.LEFT_MARGIN
					AND BSubS.RIGHT_MARGIN<=BS.RIGHT_MARGIN)
				" : "
				INNER JOIN b_iblock_section BS ON BSE.IBLOCK_SECTION_ID = BS.ID
				")."
				WHERE (".$sWhere.")$sectionScope
				) BES ON BES.IBLOCK_ELEMENT_ID = BE.IDn";
		}
		else
		{
			$arSqlSearch[] = "(".(count($arSectionFilter["BE"])? implode(" ".$arSectionFilter["LOGIC"]." ", $arSectionFilter["BE"])." ".$arSectionFilter["LOGIC"]: "")." EXISTS (
				SELECT BSE.IBLOCK_ELEMENT_ID
				FROM b_iblock_section_element BSE
				".($bINCLUDE_SUBSECTIONS? "
				INNER JOIN b_iblock_section BSubS ON BSE.IBLOCK_SECTION_ID = BSubS.ID
				INNER JOIN b_iblock_section BS ON (BSubS.IBLOCK_ID=BS.IBLOCK_ID
					AND BSubS.LEFT_MARGIN>=BS.LEFT_MARGIN
					AND BSubS.RIGHT_MARGIN<=BS.RIGHT_MARGIN)
				" : "
				INNER JOIN b_iblock_section BS ON BSE.IBLOCK_SECTION_ID = BS.ID
				")."
				WHERE BSE.IBLOCK_ELEMENT_ID = BE.ID
				AND (".$sWhere.")$sectionScope
				))";
		}
	}
	elseif(!empty($arSectionFilter["BE"]))
	{
		foreach($arSectionFilter["BE"] as $strFilter)
			$arSqlSearch[] = $strFilter;
	}

	$sWhere = "";
	foreach($arSqlSearch as $strFilter)
	{
		if(trim($strFilter, "nt") !== '')
		{
			if ($sWhere !== '')
				$sWhere .= "ntttt".$Logic." ";
			else
				$sWhere .= "ntttt";
			$sWhere .= "(".$strFilter.")";
		}
	}

	$arSqlSearch = array("nttt".$sWhere."nttt");

	$SHOW_BP_NEW = "";
	$SHOW_NEW = isset($arFilter["SHOW_NEW"]) && $arFilter["SHOW_NEW"]=="Y"? "Y": "N";

	if(
		$SHOW_NEW == "Y"
		&& isset($arFilter["SHOW_BP_NEW"])
		&& is_array($arFilter["SHOW_BP_NEW"])
		&& IsModuleInstalled('bizproc')
		&& (!is_object($USER) || !$USER->IsAdmin())
	)
	{

		$MODULE_ID = $DB->ForSQL($arFilter["SHOW_BP_NEW"]["MODULE_ID"]);
		$ENTITY = $DB->ForSQL($arFilter["SHOW_BP_NEW"]["ENTITY"]);
		$PERMISSION = $DB->ForSQL($arFilter["SHOW_BP_NEW"]["PERMISSION"]);
		$arUserGroups = array();
		if(is_array($arFilter["SHOW_BP_NEW"]["GROUPS"]))
		{
			$USER_ID = intval($arFilter["SHOW_BP_NEW"]["USER_ID"]);
			foreach($arFilter["SHOW_BP_NEW"]["GROUPS"] as $GROUP_ID)
			{
				$GROUP_ID = intval($GROUP_ID);
				if($GROUP_ID)
					$arUserGroups[$GROUP_ID] = $GROUP_ID;
			}
		}
		else
		{
			$USER_ID = false;
			$arUserGroups = false;
		}

		if($PERMISSION == "read" || $PERMISSION == "write")
		{
			if(!is_array($arUserGroups))
			{
				$USER_ID = is_object($USER)? (int)$USER->GetID(): 0;
				if(is_object($USER))
					$arUserGroups = $USER->GetUserGroupArray();
			}
			if(!is_array($arUserGroups) || empty($arUserGroups))
				$arUserGroups = array(2);

			$SHOW_BP_NEW = " AND EXISTS (
				SELECT S.DOCUMENT_ID_INT
				FROM
				b_bp_workflow_state S
				INNER JOIN b_bp_workflow_permissions P ON S.ID = P.WORKFLOW_ID
				WHERE
					S.DOCUMENT_ID_INT = BE.ID
					AND S.MODULE_ID = '$MODULE_ID'
					AND S.ENTITY = '$ENTITY'
					AND P.PERMISSION = '$PERMISSION'
					AND (
						P.OBJECT_ID IN ('".implode("', '", $arUserGroups)."')
						OR (P.OBJECT_ID = 'Author' AND BE.CREATED_BY = $USER_ID)
						OR (P.OBJECT_ID = ".$DB->Concat("'USER_'", "'$USER_ID'").")
					)
			)";
		}
	}

	if(!isset($arFilter["SHOW_HISTORY"]) || $arFilter["SHOW_HISTORY"] != "Y")
		$arSqlSearch[] = "((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL)".($SHOW_NEW == "Y"? " OR (BE.WF_NEW='Y'".$SHOW_BP_NEW.")": "").")";

	if($permSQL)
		$arSqlSearch[] = $permSQL;

	if(isset($this) && is_object($this) && isset($this->subQueryProp))
	{
		//Subquery list value should not be null
		$this->MkPropertyFilter(
			CIBlock::MkOperationFilter("!".mb_substr($this->strField, 9))
			,"NE"
			,false
			,$this->subQueryProp, $arJoinProps, $arSqlSearch
		);
	}

	return $arSqlSearch;
}