• Модуль: iblock
  • Путь к файлу: ~/bitrix/modules/iblock/lib/propertyindex/facet.php
  • Класс: BitrixIblockPropertyIndexFacet
  • Вызов: Facet::query
public function query(array $filter, array $facetTypes = array(), $facetId = 0)
{
	$connection = BitrixMainApplication::getConnection();
	$sqlHelper = $connection->getSqlHelper();

	$facetFilter = $this->getFacetFilter($facetTypes);
	if (!$facetFilter)
	{
		return false;
	}

	if ($filter)
	{
		$filter["IBLOCK_ID"] = $this->iblockId;

		$element = new CIBlockElement;
		$element->strField = "ID";
		$element->prepareSql(array("ID"), $filter, false, false);
		$elementFrom = $element->sFrom;
		$elementWhere = $element->sWhere;
	}
	else
	{
		$elementFrom = "";
		$elementWhere = "";
	}

	$facets = array();
	if ($facetId)
	{
		$facets[] = array(
			"where" => $this->getWhere($facetId),
			"facet" => array($facetId),
		);
	}
	else
	{
		foreach ($facetFilter as $facetId)
		{
			$where = $this->getWhere($facetId);

			$found = false;
			foreach ($facets as $i => $facetWhereAndFacets)
			{
				if ($facetWhereAndFacets["where"] == $where)
				{
					$facets[$i]["facet"][] = $facetId;
					$found = true;
					break;
				}
			}

			if (!$found)
			{
				$facets[] = array(
					"where" => $where,
					"facet" => array($facetId),
				);
			}
		}
	}

	$sqlUnion = array();
	foreach ($facets as $facetWhereAndFacets)
	{
		$where = $facetWhereAndFacets["where"];
		$facetFilter = $facetWhereAndFacets["facet"];

		$sqlSearch = array("1=1");

		if (empty($where))
		{
			$sqlUnion[] = "
				SELECT
					F.FACET_ID
					,F.VALUE
					,MIN(F.VALUE_NUM) MIN_VALUE_NUM
					,MAX(F.VALUE_NUM) MAX_VALUE_NUM
					".($connection instanceof BitrixMainDBMysqlCommonConnection
						?",MAX(case when LOCATE('.', F.VALUE_NUM) > 0 then LENGTH(SUBSTRING_INDEX(F.VALUE_NUM, '.', -1)) else 0 end)"
						:",MAX(".$sqlHelper->getLengthFunction("ABS(F.VALUE_NUM) - FLOOR(ABS(F.VALUE_NUM))")."+1-".$sqlHelper->getLengthFunction("0.1").")"
					)." VALUE_FRAC_LEN
					,COUNT(DISTINCT F.ELEMENT_ID) ELEMENT_COUNT
				FROM
					".($elementFrom
							?$elementFrom."
						INNER JOIN ".$this->storage->getTableName()." F ON BE.ID = F.ELEMENT_ID"
							:$this->storage->getTableName()." F"
						)."
				WHERE
					F.SECTION_ID = ".$this->sectionId."
					and F.FACET_ID in (".implode(",", $facetFilter).")
					".$elementWhere."
				GROUP BY
					F.FACET_ID, F.VALUE
			";
			continue;
		}
		elseif (count($where) == 1)
		{
			$fcJoin = "INNER JOIN ".$this->storage->getTableName()." FC on FC.ELEMENT_ID = BE.ID";
			foreach ($where as $facetWhere)
			{
				$sqlWhere = $this->whereToSql($facetWhere, "FC");
				if ($sqlWhere)
					$sqlSearch[] = $sqlWhere;
			}
		}
		elseif (count($where) <= 5)
		{
			$subJoin = "";
			$subWhere = "";
			$i = 0;
			foreach ($where as $facetWhere)
			{
				if ($i == 0)
					$subJoin .= "FROM ".$this->storage->getTableName()." FC$in";
				else
					$subJoin .= "INNER JOIN ".$this->storage->getTableName()." FC$i ON FC$i.ELEMENT_ID = FC0.ELEMENT_IDn";

				$sqlWhere = $this->whereToSql($facetWhere, "FC$i");
				if ($sqlWhere)
				{
					if ($subWhere)
						$subWhere .= "nAND ".$sqlWhere;
					else
						$subWhere .= $sqlWhere;
				}

				$i++;
			}
			$fcJoin = "
				INNER JOIN (
					SELECT FC0.ELEMENT_ID
					$subJoin
					WHERE
					$subWhere
				) FC on FC.ELEMENT_ID = BE.ID
			";
		}
		else
		{
			$condition = array();
			foreach ($where as $facetWhere)
			{
				$sqlWhere = $this->whereToSql($facetWhere, "FC0");
				if ($sqlWhere)
					$condition[] = $sqlWhere;
			}
			$fcJoin = "
					INNER JOIN (
						SELECT FC0.ELEMENT_ID
						FROM ".$this->storage->getTableName()." FC0
						WHERE FC0.SECTION_ID = ".$this->sectionId."
						AND (
						(".implode(")OR(", $condition).")
						)
					GROUP BY FC0.ELEMENT_ID
					HAVING count(DISTINCT FC0.FACET_ID) = ".count($condition)."
					) FC on FC.ELEMENT_ID = BE.ID
				";
		}

		$sqlUnion[] = "
			SELECT
				F.FACET_ID
				,F.VALUE
				,MIN(F.VALUE_NUM) MIN_VALUE_NUM
				,MAX(F.VALUE_NUM) MAX_VALUE_NUM
				".($connection instanceof BitrixMainDBMysqlCommonConnection
					?",MAX(case when LOCATE('.', F.VALUE_NUM) > 0 then LENGTH(SUBSTRING_INDEX(F.VALUE_NUM, '.', -1)) else 0 end)"
					:",MAX(".$sqlHelper->getLengthFunction("ABS(F.VALUE_NUM) - FLOOR(ABS(F.VALUE_NUM))")."+1-".$sqlHelper->getLengthFunction("0.1").")"
				)." VALUE_FRAC_LEN
				,COUNT(DISTINCT F.ELEMENT_ID) ELEMENT_COUNT
			FROM
				".$this->storage->getTableName()." F
				INNER JOIN (
					SELECT BE.ID
					FROM
						".($elementFrom
							?$elementFrom
							:"b_iblock_element BE"
						)."
						".$fcJoin."
					WHERE ".implode(" AND ", $sqlSearch)."
					".$elementWhere."
				) E ON E.ID = F.ELEMENT_ID
			WHERE
				F.SECTION_ID = ".$this->sectionId."
				and F.FACET_ID in (".implode(",", $facetFilter).")
			GROUP BY
				F.FACET_ID, F.VALUE
		";
	}

	$result = $connection->query(implode("nUNION ALLn", $sqlUnion));

	return $result;
}