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;
}