'?_items', 'nSpells' => '?_spell', 'nAchievements' => '?_achievement', 'nCurrencies' => '?_currencies', 'nPets' => '?_pet' ); protected string $queryBase = 'SELECT ic.*, ic.`id` AS ARRAY_KEY FROM ?_icons ic'; /* this works, but takes ~100x more time than i'm comfortable with .. kept as reference protected array $queryOpts = array( // 29 => Type::ICON 'ic' => [['s', 'i', 'a', 'c', 'p'], 'g' => 'ic.id'], 'i' => ['j' => ['?_items `i` ON `i`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `i`.`id`) AS "nItems"'], 's' => ['j' => ['?_spell `s` ON `s`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `s`.`id`) AS "nSpells"'], 'a' => ['j' => ['?_achievement `a` ON `a`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `a`.`id`) AS "nAchievements"'], 'c' => ['j' => ['?_currencies `c` ON `c`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `c`.`id`) AS "nCurrencies"'], 'p' => ['j' => ['?_pet `p` ON `p`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `p`.`id`) AS "nPets"'] ); */ public function __construct(array $conditions = [], array $miscData = []) { parent::__construct($conditions, $miscData); if (!$this->getFoundIDs()) return; foreach ($this->pseudoJoin as $var => $tbl) { $res = DB::Aowow()->selectCol($this->pseudoQry, $tbl, $this->getFoundIDs()); foreach ($res as $icon => $qty) $this->templates[$icon][$var] = $qty; } } public static function getName(int $id) : ?LocString { if ($n = DB::Aowow()->selectRow('SELECT `name` AS "name_loc0" FROM ?# WHERE `id` = ?d', self::$dataTable, $id)) return new LocString($n); return null; } public function getListviewData(int $addInfoMask = 0x0) : array { $data = []; foreach ($this->iterate() as $__) { $data[$this->id] = array( 'id' => $this->id, 'name' => $this->getField('name', true, true), 'icon' => $this->getField('name', true, true), 'itemcount' => (int)$this->getField('nItems'), 'spellcount' => (int)$this->getField('nSpells'), 'achievementcount' => (int)$this->getField('nAchievements'), 'npccount' => 0, // UNUSED 'petabilitycount' => 0, // UNUSED 'currencycount' => (int)$this->getField('nCurrencies'), 'missionabilitycount' => 0, // UNUSED 'buildingcount' => 0, // UNUSED 'petcount' => (int)$this->getField('nPets'), 'threatcount' => 0, // UNUSED 'classcount' => 0 // class icons are hardcoded and not referenced in dbc ); } return $data; } public function getJSGlobals(int $addMask = GLOBALINFO_ANY) : array { $data = []; foreach ($this->iterate() as $__) $data[Type::ICON][$this->id] = ['name' => $this->getField('name', true, true), 'icon' => $this->getField('name', true, true)]; return $data; } public function renderTooltip() : ?string { return null; } } class IconListFilter extends Filter { private array $iconTotals = []; private array $criterion2field = array( 1 => '?_items', // items [num] 2 => '?_spell', // spells [num] 3 => '?_achievement', // achievements [num] // 4 => '', // battlepets [num] // 5 => '', // battlepetabilities [num] 6 => '?_currencies', // currencies [num] // 7 => '', // garrisonabilities [num] // 8 => '', // garrisonbuildings [num] 9 => '?_pet', // hunterpets [num] // 10 => '', // garrisonmissionthreats [num] 11 => '', // classes [num] 13 => '' // used [num] ); protected string $type = 'icons'; protected static array $genericFilter = array( 1 => [parent::CR_CALLBACK, 'cbUsedBy' ], // items [num] 2 => [parent::CR_CALLBACK, 'cbUsedBy' ], // spells [num] 3 => [parent::CR_CALLBACK, 'cbUsedBy' ], // achievements [num] 6 => [parent::CR_CALLBACK, 'cbUsedBy' ], // currencies [num] 9 => [parent::CR_CALLBACK, 'cbUsedBy' ], // hunterpets [num] 11 => [parent::CR_NYI_PH, null, 0 ], // classes [num] 13 => [parent::CR_CALLBACK, 'cbUsedBy', true] // used [num] ); protected static array $inputFields = array( '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 'ma' => [parent::V_EQUAL, 1, false] // match any / all filter ); public array $extraOpts = []; protected function createSQLForValues() : array { $parts = []; $_v = &$this->values; //string if ($_v['na']) if ($_ = $this->tokenizeString(['name'])) $parts[] = $_; return $parts; } protected function cbUsedBy(int $cr, int $crs, string $crv, ?bool $all = false) : ?array { if (!Util::checkNumeric($crv, NUM_CAST_INT) || ![$filter, $negate] = $this->int2Filter($crs, $crv)) return null; $total = $this->prepareIconTotals($all ? 0 : $cr); $ids = array_filter($total, $filter); if ($negate) return $ids ? ['id', array_keys($ids), '!'] : [1]; else return $ids ? ['id', array_keys($ids)] : ['id', array_keys($total), '!']; } private function int2Filter(mixed $op, int $y) : ?array { return match ($op) { 1 => [fn($x) => $x > $y, false], 2 => [fn($x) => $x >= $y, false], 3 => [fn($x) => $x == $y, false], 4 => [fn($x) => $x > $y, true], 5 => [fn($x) => $x >= $y, true], 6 => [fn($x) => $x == $y, true], default => null }; } private function prepareIconTotals(int $forCr = 0) : array { foreach ($this->criterion2field as $cr => $tbl) { if (!$tbl || isset($this->iconTotals[$cr]) || ($forCr && $forCr != $cr)) continue; $this->iconTotals[$cr] = DB::Aowow()->selectCol('SELECT `iconId` AS ARRAY_KEY, COUNT(*) AS "n" FROM ?# GROUP BY `iconId`', $tbl); } if ($forCr) return $this->iconTotals[$forCr]; if (!isset($this->iconTotals['all'])) { $this->iconTotals['all'] = []; Util::arraySumByKey($this->iconTotals['all'], ...$this->iconTotals); } return $this->iconTotals['all']; } } ?>