static function processParams(array $params): array
{
$select = [];
$runtime = [];
$filterIn = [];
$filterOut = [];
if (isset($params['filter']))
{
if (is_object($params['filter']))
{
$filterIn = clone $params['filter'];
}
else
{
$filterIn = $params['filter'];
}
}
$enabledLanguages = TranslateConfig::getEnabledLanguages();
$languageUpperKeys = array_combine($enabledLanguages, array_map('mb_strtoupper', $enabledLanguages));
/*
foreach ($languageUpperKeys as $langId => $langUpper)
{
$alias = "{$langUpper}_LANG";
if (
!empty($params['select']) && in_array($alias, $params['select'])
|| isset($params['order'], $params['order'][$alias])
)
{
$tblAlias = "Phrase{$alias}";
$runtime[] = new MainORMFieldsRelationsReference(
$tblAlias,
IndexInternalsPhraseFts::getFtsEntityClass($langId),
MainORMQueryJoin::on('ref.PATH_ID', '=', 'this.PATH_ID')
->whereColumn('ref.CODE', '=', 'this.CODE')
->where('ref.LANG_ID', '=', $langId),
['join_type' => 'LEFT']
);
}
}
*/
if (!isset($filterIn['PHRASE_ENTRY']))
{
$filterIn['PHRASE_ENTRY'] = [];
}
if (!isset($filterIn['CODE_ENTRY']))
{
$filterIn['CODE_ENTRY'] = [];
}
// top folder
if (!empty($filterIn['PATH']))
{
$topIndexPath = IndexPathIndex::loadByPath($filterIn['PATH']);
if ($topIndexPath instanceof IndexPathIndex)
{
$filterOut['=PATH.DESCENDANTS.PARENT_ID'] = $topIndexPath->getId();//ancestor
}
unset($filterIn['PATH']);
}
// search by code
if (!empty($filterIn['INCLUDE_PHRASE_CODES']))
{
$codes = preg_split("/[rnt,; ]+/".BX_UTF_PCRE_MODIFIER, $filterIn['INCLUDE_PHRASE_CODES']);
$codes = array_filter($codes);
if (count($codes) > 0)
{
$useLike = false;
foreach ($codes as $code)
{
if (mb_strpos($code, '%') !== false)
{
$useLike = true;
break;
}
}
if ($useLike)
{
$filterOut['=%CODE'] = $codes;
}
else
{
$filterOut['=CODE'] = $codes;
}
}
unset($filterIn['INCLUDE_PHRASE_CODES']);
}
if (!empty($filterIn['EXCLUDE_PHRASE_CODES']))
{
$codes = preg_split("/[rnt,; ]+/".BX_UTF_PCRE_MODIFIER, $filterIn['EXCLUDE_PHRASE_CODES']);
$codes = array_filter($codes);
if (count($codes) > 0)
{
$useLike = false;
foreach ($codes as $code)
{
if (mb_strpos($code, '%') !== false)
{
$useLike = true;
break;
}
}
if ($useLike)
{
$filterOut["!=%CODE"] = $codes;
}
else
{
$filterOut["!=CODE"] = $codes;
}
}
unset($filterIn['EXCLUDE_PHRASE_CODES']);
}
if (!empty($filterIn['PHRASE_CODE']))
{
if (in_array(self::SEARCH_METHOD_CASE_SENSITIVE, $filterIn['CODE_ENTRY']))
{
if (in_array(self::SEARCH_METHOD_EQUAL, $filterIn['CODE_ENTRY']))
{
$filterOut["=CODE"] = $filterIn['PHRASE_CODE'];
}
elseif (in_array(self::SEARCH_METHOD_START_WITH, $filterIn['CODE_ENTRY']))
{
$filterOut["=%CODE"] = $filterIn['PHRASE_CODE'].'%';
}
elseif (in_array(self::SEARCH_METHOD_END_WITH, $filterIn['CODE_ENTRY']))
{
$filterOut["=%CODE"] = '%'.$filterIn['PHRASE_CODE'];
}
else
{
$filterOut["=%CODE"] = '%'.$filterIn['PHRASE_CODE'].'%';
}
}
else
{
$runtime[] = new MainORMFieldsExpressionField('CODE_UPPER', 'UPPER(%s)', 'CODE');
if (in_array(self::SEARCH_METHOD_EQUAL, $filterIn['CODE_ENTRY']))
{
$filterOut['=CODE_UPPER'] = mb_strtoupper($filterIn['PHRASE_CODE']);
}
elseif (in_array(self::SEARCH_METHOD_START_WITH, $filterIn['CODE_ENTRY']))
{
$filterOut['=%CODE_UPPER'] = mb_strtoupper($filterIn['PHRASE_CODE']).'%';
}
elseif (in_array(self::SEARCH_METHOD_END_WITH, $filterIn['CODE_ENTRY']))
{
$filterOut['=%CODE_UPPER'] = '%'.mb_strtoupper($filterIn['PHRASE_CODE']);
}
else
{
$filterOut['=%CODE_UPPER'] = '%'.mb_strtoupper($filterIn['PHRASE_CODE']).'%';
}
}
}
unset($filterIn['PHRASE_CODE'], $filterIn['CODE_ENTRY']);
$runtime[] = new MainORMFieldsRelationsReference(
'PATH',
IndexInternalsPathIndexTable::class,
MainORMQueryJoin::on('ref.ID', '=', 'this.PATH_ID'),
['join_type' => 'INNER']
);
$filterOut['=PATH.IS_DIR'] = 'N';
$replaceLangId = function(&$val)
{
$val = TranslateIOPath::replaceLangId($val, '#LANG_ID#');
};
$trimSlash = function(&$val)
{
if (mb_strpos($val, '%') === false)
{
if (TranslateIOPath::isPhpFile($val))
{
$val = '/'. trim($val, '/');
}
else
{
$val = '/'. trim($val, '/'). '/%';
}
}
};
if (!empty($filterIn['INCLUDE_PATHS']))
{
$pathIncludes = preg_split("/[rnt,; ]+/".BX_UTF_PCRE_MODIFIER, $filterIn['INCLUDE_PATHS']);
$pathIncludes = array_filter($pathIncludes);
if (count($pathIncludes) > 0)
{
$pathPathIncludes = [];
$pathNameIncludes = [];
foreach ($pathIncludes as $testPath)
{
if (!empty($testPath) && trim($testPath) !== '')
{
if (mb_strpos($testPath, '/') === false)
{
$pathNameIncludes[] = $testPath;
}
else
{
$pathPathIncludes[] = $testPath;
}
}
}
if (count($pathNameIncludes) > 0 && count($pathPathIncludes) > 0)
{
array_walk($pathNameIncludes, $replaceLangId);
array_walk($pathPathIncludes, $replaceLangId);
array_walk($pathPathIncludes, $trimSlash);
$filterOut[] = [
'LOGIC' => 'OR',
'%=PATH.NAME' => $pathNameIncludes,
'%=PATH.PATH' => $pathPathIncludes,
];
}
elseif (count($pathNameIncludes) > 0)
{
array_walk($pathNameIncludes, $replaceLangId);
$filterOut[] = [
'LOGIC' => 'OR',
'%=PATH.NAME' => $pathNameIncludes,
'%=PATH.PATH' => $pathNameIncludes,
];
}
elseif (count($pathPathIncludes) > 0)
{
array_walk($pathPathIncludes, $replaceLangId);
array_walk($pathPathIncludes, $trimSlash);
$filterOut['%=PATH.PATH'] = $pathPathIncludes;
}
}
unset($testPath, $pathIncludes, $pathNameIncludes, $pathPathIncludes);
}
if (!empty($filterIn['EXCLUDE_PATHS']))
{
$pathExcludes = preg_split("/[rnt,; ]+/".BX_UTF_PCRE_MODIFIER, $filterIn['EXCLUDE_PATHS']);
$pathExcludes = array_filter($pathExcludes);
if (count($pathExcludes) > 0)
{
$pathPathExcludes = [];
$pathNameExcludes = [];
foreach ($pathExcludes as $testPath)
{
if (!empty($testPath) && trim($testPath) !== '')
{
if (mb_strpos($testPath, '/') === false)
{
$pathNameExcludes[] = $testPath;
}
else
{
$pathPathExcludes[] = $testPath;
}
}
}
if (count($pathNameExcludes) > 0 && count($pathPathExcludes) > 0)
{
array_walk($pathNameExcludes, $replaceLangId);
array_walk($pathPathExcludes, $replaceLangId);
array_walk($pathPathExcludes, $trimSlash);
$filterOut[] = [
'LOGIC' => 'AND',
'!=%PATH.NAME' => $pathNameExcludes,
'!=%PATH.PATH' => $pathPathExcludes,
];
}
elseif (count($pathNameExcludes) > 0)
{
array_walk($pathNameExcludes, $replaceLangId);
$filterOut[] = [
'LOGIC' => 'AND',
'!=%PATH.NAME' => $pathNameExcludes,
'!=%PATH.PATH' => $pathNameExcludes,
];
}
elseif (count($pathPathExcludes) > 0)
{
array_walk($pathPathExcludes, $replaceLangId);
array_walk($pathPathExcludes, $trimSlash);
$filterOut["!=%PATH.PATH"] = $pathPathExcludes;
}
}
unset($testPath, $pathExcludes, $pathPathExcludes, $pathNameExcludes);
}
unset($filterIn['INCLUDE_PATHS'], $filterIn['EXCLUDE_PATHS']);
// search by phrase
if (!empty($filterIn['PHRASE_TEXT']))
{
$langId = !empty($filterIn['LANGUAGE_ID']) ? $filterIn['LANGUAGE_ID'] : Loc::getCurrentLang();
$langUpper = $languageUpperKeys[$langId];
$tbl = "{$langUpper}_LNG";
$alias = "{$langUpper}_LANG";
$tblAlias = "{$tbl}.PHRASE_{$langUpper}";
$fieldAlias = "{$tblAlias}.PHRASE";
$runtime[] = new MainORMFieldsRelationsReference(
$tbl,
IndexInternalsPhraseIndexTable::class,
MainORMQueryJoin::on('ref.PATH_ID', '=', 'this.PATH_ID')
->whereColumn('ref.CODE', '=', 'this.CODE')
->where('ref.LANG_ID', '=', $langId),
['join_type' => 'INNER']
);
$select[$alias] = "{$tblAlias}.PHRASE";
$select["{$langUpper}_FILE_ID"] = "{$tblAlias}.FILE_ID";
$exact = in_array(self::SEARCH_METHOD_EXACT, $filterIn['PHRASE_ENTRY']);
$entry = in_array(self::SEARCH_METHOD_ENTRY_WORD, $filterIn['PHRASE_ENTRY']);
$case = in_array(self::SEARCH_METHOD_CASE_SENSITIVE, $filterIn['PHRASE_ENTRY']);
$start = in_array(self::SEARCH_METHOD_START_WITH, $filterIn['PHRASE_ENTRY']);
$end = in_array(self::SEARCH_METHOD_END_WITH, $filterIn['PHRASE_ENTRY']);
$equal = in_array(self::SEARCH_METHOD_EQUAL, $filterIn['PHRASE_ENTRY']);
if ($exact)
{
$phraseSearch = ["={$fieldAlias}" => $filterIn['PHRASE_TEXT']];
}
else
{
$sqlHelper = MainApplication::getConnection()->getSqlHelper();
$str = $sqlHelper->forSql($filterIn['PHRASE_TEXT']);
$phraseSearch = [
'LOGIC' => 'AND'
];
// use fulltext index to help like operator
$minLengthFulltextWorld = self::getFullTextMinLength();
$fulltextIndexSearchStr = self::prepareTextForFulltextSearch($filterIn['PHRASE_TEXT']);
if (mb_strlen($fulltextIndexSearchStr) > $minLengthFulltextWorld)
{
if ($entry)
{
// identical full text match
// MATCH(PHRASE) AGAINST ('+smth' IN BOOLEAN MODE)
$phraseSearch["*={$fieldAlias}"] = $fulltextIndexSearchStr;
}
else
{
// use fulltext index to help like operator
// partial full text match
// MATCH(PHRASE) AGAINST ('+smth*' IN BOOLEAN MODE)
$phraseSearch["*{$fieldAlias}"] = $fulltextIndexSearchStr;
}
}
if ($equal)
{
$likeStr = "{$str}";
}
elseif ($start)
{
$likeStr = "{$str}%%";
}
elseif ($end)
{
$likeStr = "%%{$str}";
}
elseif ($entry)
{
$likeStr = "%%{$str}%%";
}
else
{
$likeStr = "%%" . preg_replace("/W+/i" . BX_UTF_PCRE_MODIFIER, "%%", $str) . "%%";
}
if (self::allowICURegularExpression())
{
$regStr = preg_replace("/s+/i" . BX_UTF_PCRE_MODIFIER, '[[:blank:]]+', $str);
}
else
{
if ($case)
{
$regStr = preg_replace("/s+/i" . BX_UTF_PCRE_MODIFIER, '[[:blank:]]+', $str);
}
else
{
$regStr = '';
$regChars = ['?', '*', '|', '[', ']', '(', ')', '-', '+', '.'];
for ($p = 0, $len = TranslateTextStringHelper::getLength($str); $p < $len; $p++)
{
$c0 = TranslateTextStringHelper::getSubstring($str, $p, 1);
if (in_array($c0, $regChars))
{
$regStr .= "\\" . $c0;
continue;
}
$c1 = TranslateTextStringHelper::changeCaseToLower($c0);
$c2 = TranslateTextStringHelper::changeCaseToUpper($c0);
if ($c0 != $c1)
{
$regStr .= '(' . $c0 . '|' . $c1 . '){1}';
}
elseif ($c0 != $c2)
{
$regStr .= '(' . $c0 . '|' . $c2 . '){1}';
}
else
{
$regStr .= $c0;
}
}
$regStr = preg_replace("/s+/i" . BX_UTF_PCRE_MODIFIER, '[[:blank:]]+', $regStr);
}
}
$regExpStart = '';
$regExpEnd = '';
if (preg_match("/^[[:alnum:]]+/i" . BX_UTF_PCRE_MODIFIER, $str))
{
if (self::allowICURegularExpression())
{
$regExpStart = '\\b';
}
else
{
$regExpStart = '[[:<:]]';
}
}
if (preg_match("/[[:alnum:]]+$/i" . BX_UTF_PCRE_MODIFIER, $str))
{
if (self::allowICURegularExpression())
{
$regExpEnd = '\\b';
}
else
{
$regExpEnd = '[[:>:]]';
}
}
// Exact word match
if ($equal)
{
$regStr = "[[:blank:]]*{$regExpStart}({$regStr}){$regExpEnd}[[:blank:]]*";
}
elseif ($start)
{
$regStr = "[[:blank:]]*{$regExpStart}({$regStr}){$regExpEnd}";
}
elseif ($end)
{
$regStr = "{$regExpStart}({$regStr}){$regExpEnd}[[:blank:]]*";
}
elseif ($entry)
{
$regStr = "[[:blank:]]*{$regExpStart}({$regStr}){$regExpEnd}[[:blank:]]*";
}
// regexp binary mode works not exactly we want using like binary to fix it
$binarySensitive = $case ? 'BINARY' : '';
$runtime[] =
new MainORMFieldsExpressionField(
'PHRASE_LIKE',
"CASE WHEN %s LIKE {$binarySensitive} '{$likeStr}' THEN 1 ELSE 0 END",
"{$fieldAlias}"
);
$phraseSearch["=PHRASE_LIKE"] = 1;
if (self::allowICURegularExpression())
{
// c meaning case-sensitive matching
// i meaning case-insensitive matching
$regCaseSensitive = $case ? 'c' : 'i';
$runtime[] =
new MainORMFieldsExpressionField(
'PHRASE_REGEXP',
"REGEXP_LIKE(%s, '{$regStr}', '{$regCaseSensitive}')",
"{$fieldAlias}"
);
}
else
{
$runtime[] =
new MainORMFieldsExpressionField(
'PHRASE_REGEXP',
"CASE WHEN %s REGEXP '{$regStr}' THEN 1 ELSE 0 END",
"{$fieldAlias}"
);
}
$phraseSearch["=PHRASE_REGEXP"] = 1;
}
$filterOut[] = $phraseSearch;
}
unset($filterIn['PHRASE_ENTRY'], $filterIn['PHRASE_TEXT'], $filterIn['LANGUAGE_ID']);
if (!empty($filterIn['FILE_NAME']))
{
$filterOut["=%PATH.NAME"] = '%'. $filterIn['FILE_NAME']. '%';
unset($filterIn['FILE_NAME']);
}
if (!empty($filterIn['FOLDER_NAME']))
{
$filterOut['=%PATH.PATH'] = '%/'. $filterIn['FOLDER_NAME']. '/%';
unset($filterIn['FOLDER_NAME']);
}
foreach ($filterIn as $key => $value)
{
if (in_array($key, ['tabId', 'FILTER_ID', 'PRESET_ID', 'FILTER_APPLIED', 'FIND']))
{
continue;
}
$filterOut[$key] = $value;
}
return [$select, $runtime, $filterOut];
}