cache = new DbStatementCache($dbConn); } private const GET_COUNTERS_SORT = [ 'name' => 'counter_name', 'value' => 'counter_value', 'updated' => 'counter_updated', ]; public function getCounters( ?string $orderBy = null, ?Pagination $pagination = null ): iterable { $hasOrderBy = $orderBy !== null; $hasPagination = $pagination !== null; $query = 'SELECT counter_name, counter_value, UNIX_TIMESTAMP(counter_updated) FROM msz_counters'; if($hasOrderBy) { if(!array_key_exists($orderBy, self::GET_COUNTERS_SORT)) throw new InvalidArgumentException('Invalid sort specified.'); $query .= ' ORDER BY ' . self::GET_COUNTERS_SORT[$orderBy]; } if($hasPagination) $query .= ' LIMIT ? OFFSET ?'; $args = 0; $stmt = $this->cache->get($query); if($hasPagination) { $stmt->addParameter(++$args, $pagination->getRange()); $stmt->addParameter(++$args, $pagination->getOffset()); } $stmt->execute(); return $stmt->getResult()->getIterator(CounterInfo::fromResult(...)); } public function get(array|string $names): array|int { if(is_string($names)) { $returnFirst = true; $names = [$names]; } else $returnFirst = false; $args = 0; $stmt = $this->cache->get(sprintf( 'SELECT counter_name, counter_value FROM msz_counters WHERE counter_name IN (%s)', DbTools::prepareListString($names) )); foreach($names as $name) $stmt->addParameter(++$args, (string)$name); $stmt->execute(); $values = []; $result = $stmt->getResult(); while($result->next()) $values[$result->getString(0)] = $result->getInteger(1); return $returnFirst ? $values[array_key_first($values)] : $values; } public function set(string|array $nameOrValues, ?int $value = null): void { if(empty($nameOrValues)) throw new InvalidArgumentException('$nameOrValues may not be empty.'); if(is_string($nameOrValues)) { if($value === null) throw new InvalidArgumentException('$value may not be null.'); $values = [$nameOrValues => $value]; } else $values = $nameOrValues; $args = 0; $stmt = $this->cache->get(sprintf( 'REPLACE INTO msz_counters (counter_name, counter_value) VALUES %s', DbTools::prepareListString($values, '(?, ?)') )); foreach($values as $name => $value) { $stmt->addParameter(++$args, (string)$name); $stmt->addParameter(++$args, (int)$value); } $stmt->execute(); } public function reset(string|array $names): void { if(empty($names)) throw new InvalidArgumentException('$names may not be empty.'); if(is_string($names)) $names = [$names]; $args = 0; $stmt = $this->cache->get(sprintf( 'DELETE FROM msz_counters WHERE counter_name IN (%s)', DbTools::prepareListString($names) )); foreach($names as $name) $stmt->addParameter(++$args, (string)$name); $stmt->execute(); } public function increment(string $name, int $step = 1): void { $stmt = $this->cache->get('INSERT INTO msz_counters (counter_name, counter_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE counter_value = counter_value + ?'); $stmt->addParameter(1, $name); $stmt->addParameter(2, $step); $stmt->addParameter(3, $step); $stmt->execute(); } public function decrement(string $name, int $step = 1): void { $stmt = $this->cache->get('INSERT INTO msz_counters (counter_name, counter_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE counter_value = counter_value - ?'); $stmt->addParameter(1, $name); $stmt->addParameter(2, -$step); $stmt->addParameter(3, $step); $stmt->execute(); } }