• Модуль: tasks
  • Путь к файлу: ~/bitrix/modules/tasks/lib/provider/taskfilterbuilder.php
  • Класс: BitrixTasksProviderTaskFilterBuilder
  • Вызов: TaskFilterBuilder::createSubfilter
private function createSubfilter($field, $values, string $operation, string $cast): ?ConditionTree
{
	if (!is_array($values))
	{
		$values = [$values];
	}
	$values = array_unique(array_values($values));

	if (count($values) === 0)
	{
		return null;
	}

	$filter = Query::filter();
	if ($operation !== self::OPERATION_NOT)
	{
		$filter->logic('or');
	}

	$condition = self::OPERATION_EQUAL;
	if (
		in_array(
			$operation,
			[
				self::OPERATION_GREAT,
				self::OPERATION_GREAT_EQ,
				self::OPERATION_LESS_EQ,
				self::OPERATION_LESS,
				self::OPERATION_NOT_EQUAL
			]
		)
	)
	{
		$condition = $operation;
	}

	if (
		$cast === self::CAST_NUMBER
		&& count($values) > 1
	)
	{
		$values = array_unique(array_map('intval', $values));
		if ($operation === self::OPERATION_NOT)
		{
			$filter->whereNotIn($field, $values);
		}
		else
		{
			$filter->whereIn($field, $values);
		}
		return $filter;
	}

	foreach ($values as $key => $value)
	{
		if (
			$cast === self::CAST_NUMBER
			&& !$value
		)
		{
			$value = 0;
		}

		if (
			!(
				$value === 0
				|| $value <> ''
				|| $value === false
			)
		)
		{
			$allowEmptyCastTypes = [
				self::CAST_NULL_OR_ZERO,
				self::CAST_DATE,
				self::CAST_LEFT_EXIST,
			];

			if (!in_array($cast, $allowEmptyCastTypes, true))
			{
				continue;
			}
		}

		switch ($cast)
		{
			case self::CAST_NUMBER:
				if ($values[$key] === false || !strlen($value))
				{
					($operation === self::OPERATION_NOT)
						? $filter->whereNotNull($field)
						: $filter->whereNull($field);
					break;
				}

				if ($operation === self::OPERATION_NOT)
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNot(
								Query::filter()
									->where($field, $condition, floatval($value))
							)
					);
				}
				else
				{
					$filter->where($field, $condition, floatval($value));
				}
				break;

			case self::CAST_NUMBER_WO_NULLS:
				if (!is_integer($value))
				{
					$value = floatval($value);
				}

				if ($operation === self::OPERATION_NOT)
				{
					$filter->whereNot(
						Query::filter()
							->where($field, $condition, $value)
					);
				}
				else
				{
					$filter->where($field, $condition, $value);
				}
				break;

			case self::CAST_REFERENCE:
				$value = trim($value);
				if (!preg_match('#^[a-z0-9_]+(.{1}[a-z0-9_]+)*$#i', $value))
				{
					throw new InvalidFilterException();
				}
				if ($operation === self::OPERATION_DEFAULT)
				{
					$filter->whereColumn($field, '=', $value);
				}
				elseif ($operation === self::OPERATION_NOT)
				{
					$filter->whereColumn($field, '!=', $value);
				}
				elseif ($operation === self::OPERATION_LESS)
				{
					$filter->whereColumn($field, '<', $value);
				}
				elseif ($operation === self::OPERATION_GREAT)
				{
					$filter->whereColumn($field, '>', $value);
				}
				else
				{
					throw new InvalidFilterException();
				}
				break;

			case self::CAST_NULL_OR_ZERO:
				if ($operation === self::OPERATION_NOT)
				{
					$filter->where(
						Query::filter()
							->logic('and')
							->whereNotNull($field)
							->where($field, '!=', 0)
					);
				}
				else
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->where($field, 0)
					);
				}
				break;

			case self::CAST_STRING:
				if (
					$operation === self::OPERATION_ASK
					|| $operation === self::OPERATION_LIKE
				)
				{
					$filter->whereLike($field, '%'.$value.'%');
				}
				elseif ($operation === self::OPERATION_NOT_LIKE)
				{
					$filter->whereNotLike($field, '%'.$value.'%');
				}
				elseif ($operation === self::OPERATION_MATCH_LIKE)
				{
					$filter->where([
						[self::OPERATION_MATCH_LIKE.$field, $value]
					]);
				}
				elseif (empty($value))
				{
					$subFilter = Query::filter()
						->logic('or')
						->whereNull($field)
						->where(Query::expr()->length($field), '<=', 0);

					($operation === self::OPERATION_NOT)
						? $filter->whereNot($subFilter)
						: $filter->where($subFilter);
				}
				elseif (
					$condition === self::OPERATION_EQUAL
					&& $operation === self::OPERATION_NOT
				)
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNotLike($field, '%'. $value .'%')
					);
				}
				elseif ($condition === self::OPERATION_EQUAL)
				{
					$filter->whereLike($field, '%'. $value .'%');
				}
				elseif ($operation === self::OPERATION_NOT)
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNot($field, $condition, $value)
					);
				}
				else
				{
					$filter->where($field, $condition, $value);
				}
				break;

			case self::CAST_FULLTEXT:
				if (
					$operation === self::OPERATION_MATCH_EQ
					|| $operation === self::OPERATION_MATCH
				)
				{
					$filter->whereMatch($field, $value);
				}
				elseif ($operation === self::OPERATION_MATCH_LIKE)
				{
					$filter->where([
						[self::OPERATION_MATCH_LIKE.$field, $value]
					]);
				}
				elseif (
					$operation === self::OPERATION_ASK
					|| $operation === self::OPERATION_LIKE
				)
				{
					if (
						$value === 0
						|| $value <> ''
					)
					{
						$filter->whereLike($field, '%'.$value.'%');
					}
				}
				elseif ($operation === self::OPERATION_NOT_LIKE)
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNotLike($field, '%'. $value .'%')
					);
				}
				elseif (empty($value))
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->where(Query::expr()->length($field), '=', 0)
					);
				}
				elseif (
					$condition === '='
					&& $operation === self::OPERATION_NOT
				)
				{
					$filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNotLike($field, '%'. $value .'%')
					);
				}
				elseif (
					$condition === '='
					&& $operation !== self::OPERATION_EQUAL
					&& $operation !== self::OPERATION_NOT_EQUAL
				)
				{
					$filter->whereLike($field, '%'. $value .'%');
				}
				else
				{
					$filter->where($field, $condition, $value);
				}
				break;

			case self::CAST_STRING_EQ:
				if (empty($value))
				{
					$subFilter = Query::filter()
						->logic('or')
						->whereNull($field)
						->where(Query::expr()->length($field), '<=', 0);
					($operation === self::OPERATION_NOT)
						? $filter->whereNot($subFilter)
						: $filter->where($subFilter);
				}
				else
				{
					$subFilter = Query::filter()
						->where($field, $condition, $value);
					($operation === self::OPERATION_NOT)
						? $filter->where(
							Query::filter()
								->logic('or')
								->whereNull($field)
								->whereNot($subFilter)
						)
						: $filter->where($subFilter);
				}
				break;

			case self::CAST_DATE:
			case self::CAST_DATE_STRING:
				if (empty($value))
				{
					($operation === self::OPERATION_NOT)
						? $filter->whereNotNull($field)
						: $filter->whereNull($field);
					break;
				}

				$entityFields = (TaskTable::getEntity())->getFields();
				if (
					is_string($field)
					&& array_key_exists($field, $entityFields)
					&&
					(
						is_a($entityFields[$field], DateTimeField::class)
						|| is_a($entityFields[$field], BitrixMainORMFieldsDatetimeField::class)
					)
					&& is_string($value)
				)
				{
					$value = DateTime::createFromUserTime($value);
				}
				elseif (
					is_string($field)
					&& array_key_exists($field, $entityFields)
					&& is_a($entityFields[$field], DateField::class)
					&& is_string($value)
				)
				{
					$value = new Date($value);
				}
				elseif (is_string($value))
				{
					$value = DateTime::createFromUserTime($value)->format('Y-m-d H:i:s');
				}

				if (
					$cast === self::CAST_DATE_STRING
					&& $value instanceof BitrixTasksUtilTypeDateTime
				)
				{
					$value = $value->format('Y-m-d H:i:s');
				}

				$subFilter = Query::filter()
					->where($field, $condition, $value);
				($operation === self::OPERATION_NOT)
					? $filter->where(
						Query::filter()
							->logic('or')
							->whereNull($field)
							->whereNot($subFilter)
					)
					: $filter->where($subFilter);

				break;

			case self::CAST_LEFT_EXIST:
				if ($condition !== '=')
				{
					throw new InvalidFilterException();
				}

				if (
					(
						$value === 'Y'
						&& $operation !== self::OPERATION_NOT
					)
					||
					(
						$value === 'N'
						&& $operation === self::OPERATION_NOT
					)
				)
				{
					$filter->whereNotNull($field);
				}
				else
				{
					$filter->whereNull($field);
				}
				break;
		}
	}

	return $filter;
}