• Модуль: report
  • Путь к файлу: ~/bitrix/modules/report/classes/general/report.php
  • Класс: CReport
  • Вызов: CReport::prepareSelectViewElement
static function prepareSelectViewElement($elem, $select, $isInitEntityAggregated, $fList, $fChainList,
	$helperClassName, EntityBase $entity)
{
	$selectElem = null;
	$totalInfo = null;
	$alias = null;

	if (empty($elem['aggr']) && !mb_strlen($elem['prcnt']))
	{
		$selectElem = $elem['name'];
	}
	else
	{
		$expression = '';

		/** @var EntityField $field */
		$field = $fList[$elem['name']];
		$chain = $fChainList[$elem['name']];
		$sourceAlias = $alias = $chain->getAlias();

		$dataType = call_user_func(array($helperClassName, 'getFieldDataType'), $field);

		// Need pack 1:N aggregations into subquery?
		$needPack1NAggr = false;
		if ($chain->hasBackReference() && $elem['aggr'] != 'GROUP_CONCAT')
		{
			$confirm = call_user_func_array(
				array($helperClassName, 'confirmSelectBackReferenceRewrite'),
				array(&$elem, $chain)
			);

			if ($confirm)
			{
				$needPack1NAggr = true;
			}
		}

		if (!empty($elem['aggr']))
		{
			$alias = $elem['aggr'] . '_' . $alias;

			if ($dataType == 'boolean')
			{
				// sum int for boolean
				global $DB;

				/** @var EntityBooleanField $field */
				$trueValue = $field->normalizeValue(true);
				$localDef = 'CASE WHEN %s = ''.$DB->ForSql($trueValue).'' THEN 1 ELSE 0 END';
			}
			else
			{
				$localDef = '%s';
			}

			if ($elem['aggr'] == 'COUNT_DISTINCT')
			{
				$dataType = 'integer';
				$expression = array(
					'COUNT(DISTINCT '.$localDef.')', $elem['name']
				);
			}
			else
			{
				if ($dataType == 'boolean')
				{
					$dataType = 'integer';
				}

				if ($elem['aggr'] == 'GROUP_CONCAT')
				{
					$expression = array(
						$localDef, $elem['name']
					);
				}
				else
				{
					if ($elem['aggr'] === 'AVG')
					{
						if (!is_array($totalInfo))
						{
							$totalInfo = [];
						}
						$totalInfo['average'] = [
							'type' => 'average',
							'cnt' => [
								'alias' => $sourceAlias.'_AVGCNT',
								'def' => [
									'data_type' => 'integer',
									'expression' => ['COUNT(1)']
								]
							],
							'sum' => [
								'alias' => $sourceAlias.'_AVGSUM',
								'def' => [
									'data_type' => $dataType,
									'expression' => ['SUM('.$localDef.')', $elem['name']]
								]
							]
						];
					}
					else
					{
						if ($elem['aggr'] === 'MIN' || $elem['aggr'] === 'MAX')
						{
							$typeMap = ['MIN' => 'minimum', 'MAX' => 'maximum'];
							$type = $typeMap[$elem['aggr']];
							if (!is_array($totalInfo))
							{
								$totalInfo = [];
							}
							$totalInfo[$type] = ['type' => $type];
							unset($typeMap, $type);
						}
					}

					$expression = [$elem['aggr'].'('.$localDef.')', $elem['name']];
				}
			}

			// pack 1:N aggregations into subquery
			if ($needPack1NAggr)
			{
				$filter = array();
				foreach ($entity->GetPrimaryArray() as $primary)
				{
					$filter['='.$primary] = new CSQLWhereExpression(
						'?#', ToLower($entity->getCode()).'.'.$primary
					);
				}

				$query = new EntityQuery($entity);
				$query->addSelect(new EntityExpressionField('X', $expression[0], $elem['name']));
				$query->setFilter($filter);
				$query->setTableAliasPostfix('_sub');

				$expression = array('('.$query->getQuery().')');

				// double aggregation if init entity aggregated
				if ($isInitEntityAggregated)
				{
					if ($elem['aggr'] == 'COUNT_DISTINCT')
					{
						$expression[0] = 'SUM('.$expression[0].')';
					}
					else
					{
						if ($elem['aggr'] === 'AVG')
						{
							$cntQuery = new EntityQuery($entity);
							$cntQuery->addSelect(new EntityExpressionField('CNT', 'COUNT(1)', $elem['name']));
							$cntQuery->setFilter($filter);
							$cntQuery->setTableAliasPostfix('_cnt');

							$sumQuery = new EntityQuery($entity);
							$sumQuery->addSelect(new EntityExpressionField(
								'SUM', 'SUM('.$localDef.')', $elem['name'])
							);
							$sumQuery->setFilter($filter);
							$sumQuery->setTableAliasPostfix('_sum');

							if (!is_array($totalInfo))
							{
								$totalInfo = [];
							}
							$totalInfo['average'] = [
								'type' => 'average',
								'cnt' => [
									'alias' => $sourceAlias.'_AVGCNT',
									'def' => [
										'data_type' => 'integer',
										'expression' => ['SUM(('.$cntQuery->getQuery().'))']
									]
								],
								'sum' => [
									'alias' => $sourceAlias.'_AVGSUM',
									'def' => [
										'data_type' => $dataType,
										'expression' => ['SUM(('.$sumQuery->getQuery().'))']
									]
								]
							];

							unset($cntQuery, $sumQuery);
						}
						$expression[0] = $elem['aggr'].'('.$expression[0].')';
					}
				}
			}
		}

		if($elem['prcnt'] <> '')
		{
			$alias = $alias.'_PRCNT';
			$dataType = 'integer';

			if($elem['prcnt'] == 'self_column')
			{
				if(empty($expression))
				{
					$expression = array('%s', $elem['name']);
				}
			}
			else
			{
				if(empty($expression))
				{
					$localDef = '%s';
					$localMembers = array($elem['name']);
				}
				else
				{
					$localDef = $expression[0];
					$localMembers = array_slice($expression, 1);
				}

				list($remoteAlias, $remoteSelect) = self::prepareSelectViewElement(
					$select[$elem['prcnt']],
					$select,
					$isInitEntityAggregated,
					$fList,
					$fChainList,
					$helperClassName,
					$entity
				);

				if(is_array($remoteSelect) && !empty($remoteSelect['expression']))
				{
					// remote field is expression
					$remoteDef = $remoteSelect['expression'][0];
					$remoteMembers = array_slice($remoteSelect['expression'], 1);

					$alias = $alias.'_FROM_'.$remoteAlias;
				}
				else
				{
					// remote field is usual field
					$remoteDef = '%s';
					$remoteMembers = array($remoteSelect);

					$remoteAlias = EntityQueryChain::getAliasByDefinition($entity, $remoteSelect);
					$alias = $alias.'_FROM_'.$remoteAlias;
				}

				// Expression
				// 'ROUND(STATUS / ID * 100)'
				// 'ROUND( (EX1(F1, F2)) / (EX2(F3, F1)) * 100)',
				// F1, F2, F3, F1
				$exprDef = '('.$localDef.') / ('.$remoteDef.') * 100';
				$expression = array_merge(array($exprDef), $localMembers, $remoteMembers);

				// Total expression
				if(!is_array($totalInfo))
				{
					$totalInfo = [];
				}
				$totalInfo['prcntFromCol'] = [
					'type' => 'prcntFromCol',
					'local' => [
						'alias' => $sourceAlias.'_PRCNTFC',
						'def' => [
							'data_type' => $dataType,
							'expression' => array_merge(array($localDef), $localMembers)
						]
					],
					'remote' => [
						'alias' => $remoteAlias
					]
				];
			}
		}

		$selectElem = array(
			'data_type' => $dataType,
			'expression' => $expression
		);
	}

	return array($alias, $selectElem, $totalInfo);
}