DBTypes/Filters
* filters should test string input during initialization, so errors can be passed on to the PageTemplate. * have strings be compared for identity by default and (NOT) LIKE as optional operator * note: if a string criterium gets processed via callback function it will not get prechecked
This commit is contained in:
parent
9d187e8d4c
commit
2216b664fa
18 changed files with 226 additions and 199 deletions
|
|
@ -938,7 +938,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
|||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: see also
|
||||
$seeAlso = new QuestList(array(['name_loc'.Lang::getLocale()->value, '%'.Util::htmlEscape($this->subject->getField('name', true)).'%'], ['id', $this->typeId, '!']));
|
||||
$seeAlso = new QuestList(array(['name_loc'.Lang::getLocale()->value, Util::htmlEscape($this->subject->getField('name', true))], ['id', $this->typeId, '!']));
|
||||
if (!$seeAlso->error)
|
||||
{
|
||||
$this->extendGlobalData($seeAlso->getJSGlobals());
|
||||
|
|
|
|||
|
|
@ -29,13 +29,14 @@ abstract class DBTypeList
|
|||
* expression: str - must match fieldname;
|
||||
* int - 1: select everything; 0: select nothing
|
||||
* array - another condition array
|
||||
* value: str - operator defaults to: LIKE <val>
|
||||
* int - operator defaults to: = <val>
|
||||
* value: str - operator defaults to: = <val>
|
||||
* num - operator defaults to: = <val>
|
||||
* array - operator defaults to: IN (<val>)
|
||||
* null - operator defaults to: IS [NULL]
|
||||
* operator: modifies/overrides default
|
||||
* ! - negated default value (NOT LIKE; <>; NOT IN)
|
||||
* MATCH - creates fulltext search ('value' must be array; column must have fulltext index)
|
||||
* LIKE / NOT LIKE - partial string matching ('value' must be string (*d'uh*))
|
||||
* condition as str
|
||||
* defines linking (AND || OR)
|
||||
* condition as int
|
||||
|
|
@ -167,37 +168,50 @@ abstract class DBTypeList
|
|||
else
|
||||
return null;
|
||||
|
||||
$c[2] ??= '';
|
||||
|
||||
if (is_array($c[1]) && !empty($c[1]))
|
||||
{
|
||||
if (($c[2] ?? '') === 'MATCH')
|
||||
if ($c[2] === 'MATCH')
|
||||
return 'MATCH('.$field.') AGAINST(\''.implode(' ', $c[1]).'\' IN BOOLEAN MODE)';
|
||||
|
||||
array_walk($c[1], fn(&$x) => $x = Util::checkNumeric($x) ? $x : DB::Aowow()->escape($x));
|
||||
|
||||
$op = (isset($c[2]) && $c[2] == '!') ? 'NOT IN' : 'IN';
|
||||
$op = $c[2] == '!' ? 'NOT IN' : 'IN';
|
||||
$val = '('.implode(', ', $c[1]).')';
|
||||
}
|
||||
else if (Util::checkNumeric($c[1])) // Note: should this be a NUM_REQ_* check?
|
||||
{
|
||||
$op = (isset($c[2]) && $c[2] == '!') ? '<>' : '=';
|
||||
$val = $c[1];
|
||||
$op = $c[2] == '!' ? '<>' : ($c[2] ?: '=');
|
||||
}
|
||||
else if (is_string($c[1]))
|
||||
{
|
||||
$op = (isset($c[2]) && $c[2] == '!') ? 'NOT LIKE' : 'LIKE';
|
||||
$val = DB::Aowow()->escape($c[1]);
|
||||
$val = mysqli_real_escape_string(DB::Aowow()->link, $c[1]);
|
||||
if ($c[2] == 'LIKE')
|
||||
{
|
||||
$op = 'LIKE';
|
||||
$val = '"%'.$val.'%"';
|
||||
}
|
||||
else if ($c[2] == 'NOT LIKE')
|
||||
{
|
||||
$op = 'NOT LIKE';
|
||||
$val = '"%'.$val.'%"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$op = $c[2] == '!' ? '<>' : '=';
|
||||
$val = '"'.$val.'"';
|
||||
}
|
||||
}
|
||||
else if (count($c) > 1 && $c[1] === null) // specifficly check for NULL
|
||||
{
|
||||
$op = (isset($c[2]) && $c[2] == '!') ? 'IS NOT' : 'IS';
|
||||
$op = $c[2] == '!' ? 'IS NOT' : 'IS';
|
||||
$val = 'NULL';
|
||||
}
|
||||
else // null for example
|
||||
return null;
|
||||
|
||||
if (isset($c[2]) && $c[2] != '!')
|
||||
$op = $c[2];
|
||||
|
||||
return '('.$field.' '.$op.' '.$val.')';
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ abstract class Filter
|
|||
public const V_LIST = 10;
|
||||
public const V_CALLBACK = 11;
|
||||
public const V_REGEX = 12;
|
||||
public const V_NAME = 13;
|
||||
|
||||
protected const ENUM_ANY = -2323;
|
||||
protected const ENUM_NONE = -2324;
|
||||
|
|
@ -102,7 +103,13 @@ abstract class Filter
|
|||
private array $cndSet = []; // db type query storage
|
||||
private array $rawData = [];
|
||||
|
||||
/* genericFilter: [FILTER_TYPE, colOrFnName, param1, param2]
|
||||
protected string $type = ''; // set by child
|
||||
protected array $parentCats = []; // used to validate ty-filter
|
||||
protected array $inTokens = []; // text search includes
|
||||
protected array $exTokens = []; // text search excludes
|
||||
protected array $ftTokens = []; // fulltext search
|
||||
|
||||
/* $genericFilter: [FILTER_TYPE, colOrFnName, param1, param2]
|
||||
[self::CR_BOOLEAN, <string:colName>, <bool:isString>, null]
|
||||
[self::CR_FLAG, <string:colName>, <int:testBit>, <bool:matchAny>] # default param2: matchExact
|
||||
[self::CR_NUMERIC, <string:colName>, <int:NUM_FLAGS>, <bool:addExtraCol>]
|
||||
|
|
@ -111,12 +118,17 @@ abstract class Filter
|
|||
[self::CR_STAFFFLAG, <string:colName>, null, null]
|
||||
[self::CR_CALLBACK, <string:fnName>, <mixed:param1>, <mixed:param2>]
|
||||
[self::CR_NYI_PH, null, <int:returnVal>, param2] # mostly 1: to ignore this criterium; 0: to fail the whole query
|
||||
*/
|
||||
protected string $type = ''; // set by child
|
||||
protected array $parentCats = []; // used to validate ty-filter
|
||||
|
||||
$inputFields: fieldName => [VALUE_TYPE, checkInfo, fieldIsArray]
|
||||
[self::V_EQUAL, <mixed:exactValue>, <bool:isArray>]
|
||||
[self::V_RANGE, <array:minMaxInt>, <bool:isArray>]
|
||||
[self::V_LIST, <array:validInts>, <bool:isArray>]
|
||||
[self::V_CALLBACK, <string:fnName>, <bool:isArray>]
|
||||
[self::V_REGEX, <string:regexp>, <bool:isArray>]
|
||||
[self::V_NAME, <bool:matchExact>, <bool:isArray>]
|
||||
*/
|
||||
protected static array $genericFilter = [];
|
||||
protected static array $inputFields = []; // list of input fields defined per page - fieldName => [checkType, checkValue[, fieldIsArray]]
|
||||
protected static array $inputFields = []; // list of input fields defined per page
|
||||
protected static array $enums = []; // validation for opt lists per page - criteriumID => [validOptionList]
|
||||
|
||||
// express Filters in template
|
||||
|
|
@ -441,6 +453,12 @@ abstract class Filter
|
|||
continue 2;
|
||||
break;
|
||||
case self::CR_STRING:
|
||||
if ($param1 & STR_LOCALIZED)
|
||||
$colOrFn .= '_loc'.Lang::getLocale()->value;
|
||||
|
||||
if ($this->tokenizeString($colOrFn, $_crv[$i], $param1 & STR_MATCH_EXACT, $param1 & STR_ALLOW_SHORT))
|
||||
continue 2;
|
||||
break;
|
||||
case self::CR_CALLBACK:
|
||||
case self::CR_NYI_PH:
|
||||
continue 2;
|
||||
|
|
@ -497,19 +515,19 @@ abstract class Filter
|
|||
$this->fiSetWeights = [$_wt, $_wtv];
|
||||
}
|
||||
|
||||
protected function checkInput(int $type, mixed $valid, mixed &$val, bool $recursive = false) : bool
|
||||
protected function checkInput(int $type, mixed $checkInfo, mixed &$val, bool $recursive = false) : bool
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case self::V_EQUAL:
|
||||
if (gettype($valid) == 'integer')
|
||||
if (gettype($checkInfo) == 'integer')
|
||||
$val = intval($val);
|
||||
else if (gettype($valid) == 'double')
|
||||
else if (gettype($checkInfo) == 'double')
|
||||
$val = floatval($val);
|
||||
else /* if (gettype($valid) == 'string') */
|
||||
else /* if (gettype($checkInfo) == 'string') */
|
||||
$val = strval($val);
|
||||
|
||||
if ($valid == $val)
|
||||
if ($checkInfo == $val)
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
|
@ -517,10 +535,10 @@ abstract class Filter
|
|||
if (!Util::checkNumeric($val, NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
if (in_array($val, $valid))
|
||||
if (in_array($val, $checkInfo))
|
||||
return true;
|
||||
|
||||
foreach ($valid as $v)
|
||||
foreach ($checkInfo as $v)
|
||||
{
|
||||
if (gettype($v) != 'array')
|
||||
continue;
|
||||
|
|
@ -531,142 +549,144 @@ abstract class Filter
|
|||
|
||||
break;
|
||||
case self::V_RANGE:
|
||||
if (Util::checkNumeric($val, NUM_CAST_INT) && $val >= $valid[0] && $val <= $valid[1])
|
||||
if (Util::checkNumeric($val, NUM_CAST_INT) && $val >= $checkInfo[0] && $val <= $checkInfo[1])
|
||||
return true;
|
||||
|
||||
break;
|
||||
case self::V_CALLBACK:
|
||||
if ($this->$valid($val))
|
||||
if ($this->$checkInfo($val))
|
||||
return true;
|
||||
|
||||
break;
|
||||
case self::V_REGEX:
|
||||
if (!preg_match($valid, $val))
|
||||
if (!preg_match($checkInfo, $val))
|
||||
return true;
|
||||
|
||||
break;
|
||||
case self::V_NAME:
|
||||
if (preg_match(self::PATTERN_NAME, $val))
|
||||
break;
|
||||
|
||||
if (!$this->tokenizeString('na', $val, $checkInfo && $this->values['ex']))
|
||||
return false; // quit without logging more errors
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$recursive)
|
||||
{
|
||||
trigger_error('Filter::checkInput - check failed [type: '.$type.' valid: '.Util::toString($valid).' val: '.((string)$val).']', E_USER_NOTICE);
|
||||
trigger_error('Filter::checkInput - check failed [type: '.$type.' valid: '.Util::toString($checkInfo).' val: '.((string)$val).']', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function transformToken(string $string, bool $exact) : string
|
||||
public static function transformToken(string &$string, bool $allowShort = false) : ?array
|
||||
{
|
||||
$lenTest = fn($x) => $x !== '' && (mb_strlen($x) > 2 || $allowShort || Lang::getLocale()->isLogographic());
|
||||
$string = trim($string);
|
||||
|
||||
if ($string === '')
|
||||
return null;
|
||||
|
||||
// invalid chars for both LIKE and MATCH
|
||||
$str = str_replace(['\\', '%'], '', $string);
|
||||
|
||||
if ($neg = ($str[0] === '-'))
|
||||
$str = mb_substr($str, 1);
|
||||
|
||||
if (!$lenTest($str))
|
||||
return null;
|
||||
|
||||
// if the fulltext token contains invalid chars, should it be sub-tokenized (current behavior) or should the chars just be stripped
|
||||
$ft = array_filter(explode(' ', preg_replace(self::PATTERN_FT, ' ', $str)), $lenTest);
|
||||
|
||||
// escape manually entered _; entering % should be prohibited
|
||||
$string = str_replace('_', '\\_', $string);
|
||||
// then replace search wildcards with sql wildcards
|
||||
$lk = strtr(str_replace('_', '\\_', $str), self::$wCards);
|
||||
|
||||
// now replace search wildcards with sql wildcards
|
||||
$string = strtr($string, self::$wCards);
|
||||
|
||||
return sprintf($exact ? '%s' : '%%%s%%', $string);
|
||||
return [$lk, $ft, $neg];
|
||||
}
|
||||
|
||||
protected function tokenizeString(array $fields, string $string = '', bool $exact = false, bool $allowShort = false) : array
|
||||
protected function tokenizeString(string $field, string $string, bool $exact = false, bool $allowShort = false) : bool
|
||||
{
|
||||
if (!$string && $this->values['na'])
|
||||
$string = $this->values['na'];
|
||||
|
||||
// always allow sub 3 chars for logographic locales
|
||||
if (Lang::getLocale()->isLogographic())
|
||||
$allowShort = true;
|
||||
|
||||
$qry = [];
|
||||
foreach ($fields as $f)
|
||||
{
|
||||
$sub = [];
|
||||
$tokens = $exact ? [$string] : array_filter(explode(' ', $string));
|
||||
foreach ($tokens as $t)
|
||||
{
|
||||
if ($t[0] == '-' && (mb_strlen($t) > 3 || $allowShort))
|
||||
$sub[] = [$f, $this->transformToken(mb_substr($t, 1), $exact), '!'];
|
||||
else if ($t[0] != '-' && (mb_strlen($t) > 2 || $allowShort))
|
||||
$sub[] = [$f, $this->transformToken($t, $exact)];
|
||||
}
|
||||
|
||||
// single cnd?
|
||||
if (!$sub)
|
||||
continue;
|
||||
else if (count($sub) > 1)
|
||||
array_unshift($sub, 'AND');
|
||||
else
|
||||
$sub = $sub[0];
|
||||
|
||||
$qry[] = $sub;
|
||||
}
|
||||
|
||||
// single cnd?
|
||||
if (!$qry)
|
||||
{
|
||||
trigger_error('Filter::tokenizeString - could not tokenize string: '.$string, E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
}
|
||||
else if (count($qry) > 1)
|
||||
array_unshift($qry, 'OR');
|
||||
else
|
||||
$qry = $qry[0];
|
||||
|
||||
return $qry;
|
||||
}
|
||||
|
||||
protected function buildMatchLookup(array $fields, string $string = '', bool $exact = false, bool $allowShort = false) : array
|
||||
{
|
||||
if (!$string && $this->values['na'])
|
||||
$string = $this->values['na'];
|
||||
|
||||
if (Lang::getLocale()->isLogographic() && !Cfg::get('LOGOGRAPHIC_FT_SEARCH'))
|
||||
return $this->tokenizeString($fields, $string, $exact, $allowShort);
|
||||
|
||||
$ftString = trim(preg_replace(self::PATTERN_FT, ' ', $string));
|
||||
if (!$ftString)
|
||||
return [];
|
||||
|
||||
// always allow sub 3 chars for logographic locales
|
||||
if (Lang::getLocale()->isLogographic())
|
||||
$allowShort = true;
|
||||
|
||||
$sub = [];
|
||||
$tokens = $exact ? [$ftString] : array_filter(explode(' ', $ftString));
|
||||
$tokens = $exact ? [$string] : explode(' ', $string);
|
||||
foreach ($tokens as $t)
|
||||
{
|
||||
$ex = $t[0] === '-';
|
||||
if ($ex)
|
||||
$t = mb_substr($t, 1);
|
||||
if ([$like, $fulltext, $ex] = self::transformToken($t, $allowShort))
|
||||
{
|
||||
if ($like)
|
||||
$this->{$ex ? 'exTokens' : 'inTokens'}[$field][] = $like;
|
||||
|
||||
// cant have trailing/leading dashes. FT confuses them for additional modifiers and dies with a syntax error
|
||||
// would be an issue for all modifiers, but Filter::PATTERN_FT only allows for - at this point
|
||||
$t = preg_replace('/^-+|-+$/', '', $t);
|
||||
// don't bother with fulltext search if exact is specified
|
||||
if ($exact)
|
||||
continue;
|
||||
|
||||
if ($allowShort || mb_strlen($t) > 2)
|
||||
$sub[] = ($ex ? '-' : '+') . $t . '*';
|
||||
// note: a fulltext search purely from exclude tokens will return no result
|
||||
foreach ($fulltext as $ft)
|
||||
{
|
||||
// cant have trailing/leading dashes. FT confuses them for additional modifiers and dies with a syntax error
|
||||
// would be an issue for all modifiers, but Filter::PATTERN_FT only allows for - at this point
|
||||
$this->ftTokens[$field][] = ($ex ? '-' : '+') . preg_replace('/^-+|-+$/', '', $ft) . '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$sub)
|
||||
if (empty($this->inTokens[$field]))
|
||||
{
|
||||
trigger_error('Filter::buildMatchLookup - could not build MATCH AGAINST from: "'.$ftString.'"', E_USER_NOTICE);
|
||||
trigger_error('Filter::tokenizeString - could not tokenize string: "'.$string.'" for input: '.$field, E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function buildLikeLookup(array $fields, bool $exact = false) : array
|
||||
{
|
||||
$qry = [];
|
||||
foreach ($fields as $field => $col)
|
||||
{
|
||||
$sub = [];
|
||||
if (!empty($this->inTokens[$field]))
|
||||
$sub = array_merge($sub, array_map(fn($x) => [$col, $x, $exact ? null : 'LIKE'], $this->inTokens[$field]));
|
||||
if (!empty($this->exTokens[$field]))
|
||||
$sub = array_merge($sub, array_map(fn($x) => [$col, $x, $exact ? null : 'NOT LIKE'], $this->exTokens[$field]));
|
||||
|
||||
if (count($sub) > 1)
|
||||
array_unshift($sub, 'AND');
|
||||
else if ($sub)
|
||||
$sub = $sub[0];
|
||||
|
||||
if ($sub)
|
||||
$qry[] = $sub;
|
||||
}
|
||||
|
||||
return $qry ? ['OR', ...$qry] : [];
|
||||
}
|
||||
|
||||
protected function buildMatchLookup(array $fields, bool $exact = false) : array
|
||||
{
|
||||
if (Lang::getLocale()->isLogographic() && !Cfg::get('LOGOGRAPHIC_FT_SEARCH'))
|
||||
return $this->buildLikeLookup($fields, $exact);
|
||||
|
||||
$qry = [];
|
||||
foreach ($fields as $f)
|
||||
foreach ($fields as $field => $col)
|
||||
{
|
||||
$qry[] = [$f, trim($string)];
|
||||
if ($sub)
|
||||
$qry[] = [$f, $sub, 'MATCH'];
|
||||
if (!empty($this->ftTokens[$field]))
|
||||
$qry[] = [$col, $this->ftTokens[$field], 'MATCH'];
|
||||
|
||||
$tok = $this->values[$field];
|
||||
if (self::transformToken($tok))
|
||||
$qry[] = [$col, $tok];
|
||||
}
|
||||
|
||||
// single cnd?
|
||||
if (count($qry) > 1)
|
||||
array_unshift($qry, 'OR');
|
||||
else
|
||||
$qry = $qry[0];
|
||||
|
||||
return $qry;
|
||||
return $qry ? ['OR', ...$qry] : [];
|
||||
}
|
||||
|
||||
protected function int2Op(mixed &$op) : bool
|
||||
|
|
@ -738,14 +758,14 @@ abstract class Filter
|
|||
return [[$field, $value, '&'], $value];
|
||||
}
|
||||
|
||||
private function genericString(string $field, string $value, ?int $strFlags) : ?array
|
||||
private function genericString(string $field, ?int $strFlags) : ?array
|
||||
{
|
||||
$strFlags ??= 0x0;
|
||||
|
||||
if ($strFlags & STR_LOCALIZED)
|
||||
$field .= '_loc'.Lang::getLocale()->value;
|
||||
|
||||
return $this->tokenizeString([$field], $value, $strFlags & STR_MATCH_EXACT, $strFlags & STR_ALLOW_SHORT);
|
||||
return $this->buildLikeLookup([$field => $field]);
|
||||
}
|
||||
|
||||
private function genericNumeric(string $field, int|float $value, int $op, int $typeCast) : ?array
|
||||
|
|
@ -821,7 +841,7 @@ abstract class Filter
|
|||
self::CR_FLAG => $this->genericBooleanFlags($colOrFn, $param1, $crs, $param2),
|
||||
self::CR_STAFFFLAG => $this->genericBooleanFlags($colOrFn, (1 << ($crs - 1)), true),
|
||||
self::CR_BOOLEAN => $this->genericBoolean($colOrFn, $crs, !empty($param1)),
|
||||
self::CR_STRING => $this->genericString($colOrFn, $crv, $param1),
|
||||
self::CR_STRING => $this->genericString($colOrFn, $param1),
|
||||
self::CR_CALLBACK => $this->{$colOrFn}($cr, $crs, $crv, $param1, $param2),
|
||||
self::CR_ENUM => $handleEnum($cr, $crs, $colOrFn, $param1, $param2),
|
||||
self::CR_NYI_PH => $handleNYIPH($crs, $crv, $param1),
|
||||
|
|
|
|||
|
|
@ -112,40 +112,20 @@ class Search
|
|||
|
||||
foreach (explode(' ', $this->query) as $raw)
|
||||
{
|
||||
// invalid chars for both LIKE and MATCH
|
||||
$clean = str_replace(['\\', '%'], '', $raw);
|
||||
|
||||
if ($clean === '')
|
||||
continue;
|
||||
|
||||
$ex = ($clean[0] == '-');
|
||||
if ($ex)
|
||||
if ([$like, $fulltext, $ex] = Filter::transformToken($raw, $allowShort))
|
||||
{
|
||||
$clean = mb_substr($clean, 1);
|
||||
$raw = mb_substr($raw, 1);
|
||||
}
|
||||
$this->{$ex ? 'excluded' : 'included'}[] = $like;
|
||||
|
||||
if (mb_strlen($clean) < 3 && !$allowShort)
|
||||
{
|
||||
$this->invalid[] = $raw;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->{$ex ? 'excluded' : 'included'}[] = str_replace('_', '\\_', $clean);
|
||||
|
||||
// note: a fulltext search purely with exclude tokens will return no result
|
||||
if (($tokens = trim(preg_replace(Filter::PATTERN_FT, ' ', $clean))) !== '')
|
||||
{
|
||||
foreach (array_filter(explode(' ', $tokens)) as $t)
|
||||
// note: a fulltext search purely from exclude tokens will return no result
|
||||
foreach ($fulltext as $ft)
|
||||
{
|
||||
// cant have trailing/leading dashes. FT confuses them for additional modifiers and dies with a syntax error
|
||||
// would be an issue for all modifiers, but Filter::PATTERN_FT only allows for - at this point
|
||||
$t = preg_replace('/^-+|-+$/', '', $t);
|
||||
|
||||
if ($allowShort || mb_strlen($t) > 2)
|
||||
$this->fulltext[] = ($ex ? '-' : '+') . $t . '*';
|
||||
$this->fulltext[] = ($ex ? '-' : '+') . preg_replace('/^-+|-+$/', '', $ft) . '*';
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->invalid[] = $raw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -165,11 +145,8 @@ class Search
|
|||
foreach ($fields as $f)
|
||||
{
|
||||
$sub = [];
|
||||
foreach ($this->included as $i)
|
||||
$sub[] = [$f, '%'.$i.'%'];
|
||||
|
||||
foreach ($this->excluded as $x)
|
||||
$sub[] = [$f, '%'.$x.'%', '!'];
|
||||
$sub = array_merge($sub, array_map(fn($x) => [$f, $x, 'LIKE'], $this->included));
|
||||
$sub = array_merge($sub, array_map(fn($x) => [$f, $x, 'NOT LIKE'], $this->excluded));
|
||||
|
||||
// single cnd?
|
||||
if (count($sub) > 1)
|
||||
|
|
@ -202,17 +179,17 @@ class Search
|
|||
$fields[] = 'name_loc'.Lang::getLocale()->value;
|
||||
|
||||
$qry = [];
|
||||
foreach ($fields as $f)
|
||||
{
|
||||
$qry[] = [$f, $this->query];
|
||||
if ($this->fulltext)
|
||||
$qry[] = [$f, $this->fulltext, 'MATCH'];
|
||||
}
|
||||
if ($this->fulltext)
|
||||
$qry = array_map(fn($x) => [$x, $this->fulltext, 'MATCH'], $fields);
|
||||
|
||||
$strBak = trim($this->query);
|
||||
if (mb_strlen($strBak) > 2 || Lang::getLocale()->isLogographic())
|
||||
$qry = array_merge($qry, array_map(fn($x) => [$x, $strBak], $fields));
|
||||
|
||||
// single cnd?
|
||||
if (count($qry) > 1)
|
||||
array_unshift($qry, 'OR');
|
||||
else
|
||||
else if (count($qry) == 1)
|
||||
$qry = $qry[0];
|
||||
|
||||
return $qry;
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ class AchievementListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [2, 18], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 99999]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values - only printable chars, no delimiters
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / description - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name / description - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // extended name search
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'si' => [parent::V_LIST, [SIDE_ALLIANCE, SIDE_HORDE, SIDE_BOTH, -SIDE_ALLIANCE, -SIDE_HORDE], false], // side
|
||||
|
|
@ -328,9 +328,9 @@ class AchievementListFilter extends Filter
|
|||
{
|
||||
$_ = [];
|
||||
if ($_v['ex'] == 'on')
|
||||
$_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value, 'reward_loc'.Lang::getLocale()->value, 'description_loc'.Lang::getLocale()->value]);
|
||||
$_ = $this->buildLikeLookup(['na' => 'name_loc'.Lang::getLocale()->value, 'na' => 'reward_loc'.Lang::getLocale()->value, 'na' => 'description_loc'.Lang::getLocale()->value]);
|
||||
else
|
||||
$_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]);
|
||||
$_ = $this->buildLikeLookup(['na' => 'name_loc'.Lang::getLocale()->value]);
|
||||
|
||||
if ($_)
|
||||
$parts[] = $_;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class AreaTriggerListFilter extends Filter
|
|||
'cr' => [parent::V_LIST, [2], true ], // criteria ids
|
||||
'crs' => [parent::V_RANGE, [1, 6], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_INT, true ], // criteria values - all criteria are numeric here
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ty' => [parent::V_RANGE, [0, 5], true ] // types
|
||||
);
|
||||
|
|
@ -85,7 +85,7 @@ class AreaTriggerListFilter extends Filter
|
|||
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['name']))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'name']))
|
||||
$parts[] = $_;
|
||||
|
||||
// type [list]
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ class ArenaTeamListFilter extends Filter
|
|||
protected string $type = 'arenateams';
|
||||
protected static array $genericFilter = [];
|
||||
protected static array $inputFields = array(
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact - must be defined before 'na' as it's test relies on 'ex's value
|
||||
'na' => [parent::V_NAME, true, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [parent::V_LIST, [1, 2], false], // side
|
||||
'sz' => [parent::V_LIST, [2, 3, 5], false], // tema size
|
||||
'rg' => [parent::V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
|
|
@ -73,7 +73,7 @@ class ArenaTeamListFilter extends Filter
|
|||
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['at.name'], $_v['na'], $_v['ex'] == 'on'))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'at.name'], $_v['ex'] == 'on'))
|
||||
$parts[] = $_;
|
||||
|
||||
// side [list]
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ class CreatureListFilter extends Filter
|
|||
'cr' => [parent::V_LIST, [[1, 3],[5, 12], 15, 16, [18, 25], [27, 29], [31, 35], 37, 38, [40, 44]], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 9999]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values - only printable chars, no delimiter
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / subname - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name / subname - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'fa' => [parent::V_CALLBACK, 'cbPetFamily', true ], // pet family [list] - cat[0] == 1
|
||||
|
|
@ -365,10 +365,10 @@ class CreatureListFilter extends Filter
|
|||
if ($_v['na'])
|
||||
{
|
||||
if ($_v['ex'] == 'on')
|
||||
if ($_ = $this->tokenizeString(['subname_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'subname_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildMatchLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
{
|
||||
if ($parts)
|
||||
$parts = ['OR', $_, ...$parts];
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ class EnchantmentListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [2, 123], true ], // criteria ids
|
||||
'crs' => [parent::V_RANGE, [1, 15], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_INT, true ], // criteria values - only numerals
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ty' => [parent::V_RANGE, [1, 8], true ] // types
|
||||
);
|
||||
|
|
@ -249,7 +249,7 @@ class EnchantmentListFilter extends Filter
|
|||
|
||||
//string
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
// type
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ class GameObjectListFilter extends Filter
|
|||
'cr' => [parent::V_LIST, [[1, 5], 7, 11, 13, 15, 16, 18, 50], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 5000]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_INT, true ], // criteria values - only numeric input values expected
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false] // match any / all filter
|
||||
);
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ class GameObjectListFilter extends Filter
|
|||
|
||||
// name
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildMatchLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ class GuildListFilter extends Filter
|
|||
protected string $type = 'guilds';
|
||||
protected static array $genericFilter = [];
|
||||
protected static array $inputFields = array(
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact - must be defined before 'na' as it's test relies on 'ex's value
|
||||
'na' => [parent::V_NAME, true, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [parent::V_LIST, [SIDE_ALLIANCE, SIDE_HORDE], false], // side
|
||||
'rg' => [parent::V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'bg' => [parent::V_EQUAL, null, false], // battlegroup - unsued here, but var expected by template
|
||||
|
|
@ -114,7 +114,7 @@ class GuildListFilter extends Filter
|
|||
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['g.name'], $_v['na'], $_v['ex'] == 'on'))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'g.name'], $_v['ex'] == 'on'))
|
||||
$parts[] = $_;
|
||||
|
||||
// side [list]
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class IconListFilter extends Filter
|
|||
'cr' => [parent::V_LIST, [1, 2, 3, 6, 9, 11, 13], true ], // criteria ids
|
||||
'crs' => [parent::V_RANGE, [1, 6], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_INT, true ], // criteria values - all criteria are numeric here
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false] // match any / all filter
|
||||
);
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ class IconListFilter extends Filter
|
|||
|
||||
//string
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['name']))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'name']))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
|
|
|
|||
|
|
@ -1991,7 +1991,7 @@ class ItemListFilter extends Filter
|
|||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values - only printable chars, no delimiters
|
||||
'upg' => [parent::V_REGEX, '/[^\d:]/ui', true ], // upgrade item ids
|
||||
'gb' => [parent::V_LIST, [0, 1, 2, 3], false], // search result grouping
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ub' => [parent::V_LIST, [[1, 9], 11], false], // usable by classId
|
||||
'qu' => [parent::V_RANGE, [0, 7], true ], // quality ids
|
||||
|
|
@ -2097,7 +2097,7 @@ class ItemListFilter extends Filter
|
|||
|
||||
// name
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildMatchLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
// usable-by (not excluded by requiredClass && armor or weapons match mask from ?_classes)
|
||||
|
|
@ -2218,9 +2218,16 @@ class ItemListFilter extends Filter
|
|||
protected function cbHasRandEnchant(int $cr, int $crs, string $crv) : ?array
|
||||
{
|
||||
$n = preg_replace(parent::PATTERN_NAME, '', $crv);
|
||||
$n = $this->transformToken($n, false);
|
||||
if (!$this->tokenizeString($cr, $n))
|
||||
return null;
|
||||
|
||||
$randIds = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, ABS(`id`) AS `id`, name_loc?d, `name_loc0` FROM ?_itemrandomenchant WHERE name_loc?d LIKE ?', Lang::getLocale()->value, Lang::getLocale()->value, $n);
|
||||
$parts = [];
|
||||
foreach ($this->inTokens[$cr] ?? [] as $tok)
|
||||
$parts[] = sprintf('name_loc%d LIKE "%%%s%%"', Lang::getLocale()->value, mysqli_real_escape_string(DB::Aowow()->link, $tok));
|
||||
foreach ($this->exTokens[$cr] ?? [] as $tok)
|
||||
$parts[] = sprintf('name_loc%d NOT LIKE "%%%s%%"', Lang::getLocale()->value, mysqli_real_escape_string(DB::Aowow()->link, $tok));
|
||||
|
||||
$randIds = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, ABS(`id`) AS `id`, name_loc?d, `name_loc0` FROM ?_itemrandomenchant WHERE '.implode(' AND ', $parts), Lang::getLocale()->value);
|
||||
$tplIds = $randIds ? DB::World()->select('SELECT `entry`, `ench` FROM item_enchantment_template WHERE `ench` IN (?a)', array_column($randIds, 'id')) : [];
|
||||
foreach ($tplIds as &$set)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ class ItemsetListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [2, 12], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 424]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values - only printable chars, no delimiters
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / description - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name / description - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'qu' => [parent::V_RANGE, [0, 7], true ], // quality
|
||||
'ty' => [parent::V_RANGE, [1, 12], true ], // set type
|
||||
|
|
@ -199,7 +199,7 @@ class ItemsetListFilter extends Filter
|
|||
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
// quality [enum]
|
||||
|
|
|
|||
|
|
@ -244,9 +244,9 @@ class ProfileListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [1, 36], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 5000]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact - must be defined before 'na' as it's test relies on 'ex's value
|
||||
'na' => [parent::V_NAME, true, false], // name - only printable chars, no delimiter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [parent::V_LIST, [SIDE_ALLIANCE, SIDE_HORDE], false], // side
|
||||
'ra' => [parent::V_LIST, [[1, 8], 10, 11], true ], // race
|
||||
'cl' => [parent::V_LIST, [[1, 9], 11], true ], // class
|
||||
|
|
@ -284,13 +284,20 @@ class ProfileListFilter extends Filter
|
|||
// table key differs between remote and local :<
|
||||
$k = $this->useLocalList ? 'p' : 'c';
|
||||
|
||||
// name [str] - the table is case sensitive. Since i don't want to destroy indizes, lets alter the search terms
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
{
|
||||
$lower = $this->tokenizeString([$k.'.name'], Util::lower($_v['na']), $_v['ex'] == 'on', true);
|
||||
$proper = $this->tokenizeString([$k.'.name'], Util::ucWords($_v['na']), $_v['ex'] == 'on', true);
|
||||
// issue: the table is case sensitive. so we need to alter the tokens for multiple cases
|
||||
foreach (['inTokens', 'exTokens'] as $prop)
|
||||
{
|
||||
if (empty($this->{$prop}['na']))
|
||||
continue;
|
||||
|
||||
$parts[] = ['OR', $lower, $proper];
|
||||
$this->{$prop}['na'] = array_map(Util::lower(...), $this->{$prop}['na']);
|
||||
$this->{$prop}['_na'] = array_map(Util::ucWords(...), $this->{$prop}['na']);
|
||||
};
|
||||
|
||||
$parts[] = $this->buildLikeLookup(['na' => $k.'.name', '_na' => $k.'.name'], $_v['ex'] == 'on');
|
||||
}
|
||||
|
||||
// side [list]
|
||||
|
|
@ -406,8 +413,10 @@ class ProfileListFilter extends Filter
|
|||
|
||||
protected function cbTeamName(int $cr, int $crs, string $crv, $size) : ?array
|
||||
{
|
||||
if ($_ = $this->tokenizeString(['at.name'], $crv))
|
||||
return ['AND', ['at.type', $size], $_];
|
||||
$n = preg_replace(parent::PATTERN_NAME, '', $crv);
|
||||
if ($this->tokenizeString($cr, $n))
|
||||
if ($_ = $this->buildLikeLookup([$cr => 'at.name']))
|
||||
return ['AND', ['at.type', $size], $_];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ class QuestListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [1, 45], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 99999]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_INT, true ], // criteria values - only numerals
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / text - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name / text - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'minle' => [parent::V_RANGE, [0, 99], false], // min quest level
|
||||
|
|
@ -507,10 +507,10 @@ class QuestListFilter extends Filter
|
|||
if ($_v['na'])
|
||||
{
|
||||
if ($_v['ex'] == 'on')
|
||||
if ($_ = $this->tokenizeString(['objectives_loc'.Lang::getLocale()->value, 'details_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'objectives_loc'.Lang::getLocale()->value, 'na' => 'details_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildMatchLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
{
|
||||
if ($parts)
|
||||
$parts[0][] = $_;
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class SoundListFilter extends Filter
|
|||
{
|
||||
protected string $type = 'sounds';
|
||||
protected static array $inputFields = array(
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name - only printable chars, no delimiter
|
||||
'ty' => [parent::V_LIST, [[1, 4], 6, 9, 10, 12, 13, 14, 16, 17, [19, 31], 50, 52, 53], true ] // type
|
||||
);
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ class SoundListFilter extends Filter
|
|||
|
||||
// name [str]
|
||||
if ($_v['na'])
|
||||
if ($_ = $this->tokenizeString(['name']))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'name']))
|
||||
$parts[] = $_;
|
||||
|
||||
// type [list]
|
||||
|
|
|
|||
|
|
@ -2575,7 +2575,7 @@ class SpellListFilter extends Filter
|
|||
'cr' => [parent::V_RANGE, [1, 116], true ], // criteria ids
|
||||
'crs' => [parent::V_LIST, [parent::ENUM_NONE, parent::ENUM_ANY, [0, 99999]], true ], // criteria operators
|
||||
'crv' => [parent::V_REGEX, parent::PATTERN_CRV, true ], // criteria values - only printable chars, no delimiters
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / text - only printable chars, no delimiter
|
||||
'na' => [parent::V_NAME, false, false], // name / text - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // extended name search
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'minle' => [parent::V_RANGE, [0, 99], false], // spell level min
|
||||
|
|
@ -2599,10 +2599,10 @@ class SpellListFilter extends Filter
|
|||
if ($_v['na'])
|
||||
{
|
||||
if ($_v['ex'] == 'on')
|
||||
if ($_ = $this->tokenizeString(['buff_loc'.Lang::getLocale()->value, 'description_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildLikeLookup(['na' => 'buff_loc'.Lang::getLocale()->value, 'na' => 'description_loc'.Lang::getLocale()->value]))
|
||||
$parts[] = $_;
|
||||
|
||||
if ($_ = $this->buildMatchLookup(['name_loc'.Lang::getLocale()->value]))
|
||||
if ($_ = $this->buildMatchLookup(['na' => 'name_loc'.Lang::getLocale()->value]))
|
||||
{
|
||||
if ($parts)
|
||||
$parts[0][] = $_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue