misuzu/src/Emoticons/Emotes.php

217 lines
7.5 KiB
PHP

<?php
namespace Misuzu\Emoticons;
use InvalidArgumentException;
use RuntimeException;
use Index\Data\DbStatementCache;
use Index\Data\IDbConnection;
class Emotes {
private const EMOTE_ORDER = [
'order' => 'emote_order',
'id' => 'emote_id',
'rank' => 'emote_hierarchy',
];
private IDbConnection $dbConn;
private DbStatementCache $cache;
public function __construct(IDbConnection $dbConn) {
$this->dbConn = $dbConn;
$this->cache = new DbStatementCache($dbConn);
}
public function getEmote(string $emoteId): EmoteInfo {
$stmt = $this->cache->get('SELECT emote_id, emote_order, emote_hierarchy, emote_url FROM msz_emoticons WHERE emote_id = ?');
$stmt->addParameter(1, $emoteId);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('No emoticon with that ID exists.');
return EmoteInfo::fromResult($result);
}
public static function emoteOrderOptions(): array {
return array_keys(self::EMOTE_ORDER);
}
// TODO: pagination
public function getEmotes(
?int $minRank = null,
?string $orderBy = null,
?bool $reverse = null
): iterable {
$hasMinRank = $minRank !== null;
$hasOrderBy = $orderBy !== null;
$hasReverse = $reverse !== null;
$query = 'SELECT emote_id, emote_order, emote_hierarchy, emote_url FROM msz_emoticons';
if($hasMinRank)
$query .= ' WHERE emote_hierarchy <= ?';
if($hasOrderBy) {
if(!array_key_exists($orderBy, self::EMOTE_ORDER))
throw new InvalidArgumentException('Invalid $orderBy specified.');
$query .= sprintf(' ORDER BY %s', self::EMOTE_ORDER[$orderBy]);
if($hasReverse)
$query .= $reverse ? ' DESC' : ' ASC';
}
$stmt = $this->cache->get($query);
if($hasMinRank)
$stmt->addParameter(1, $minRank);
$stmt->execute();
return $stmt->getResult()->getIterator(EmoteInfo::fromResult(...));
}
private static function checkEmoteUrlInternal(string $url): string {
// more checks?
if(empty($url))
return 'empty';
if(trim($url) !== $url)
return 'spaces';
return '';
}
public function checkEmoteUrl(string $url): string {
$check = self::checkEmoteUrlInternal($url);
if($check !== '')
return $check;
$stmt = $this->cache->get('SELECT COUNT(*) FROM msz_emoticons WHERE emote_url = ?');
$stmt->addParameter(1, $url);
$stmt->execute();
$result = $stmt->getResult();
if($result->next() && $result->getInteger(0) > 0)
return 'used';
return '';
}
public function createEmote(string $url, int $minRank = 0, ?int $order = null): EmoteInfo {
$check = self::checkEmoteUrlInternal($url);
if($check !== '')
throw new InvalidArgumentException('$url is not correctly formatted: ' . $check);
$stmt = $this->cache->get('INSERT INTO msz_emoticons (emote_url, emote_hierarchy, emote_order) SELECT ?, ?, COALESCE(?, (SELECT FLOOR(MAX(emote_order) / 10) * 10 + 10 FROM msz_emoticons), 10)');
$stmt->addParameter(1, $url);
$stmt->addParameter(2, $minRank);
$stmt->addParameter(3, $order);
$stmt->execute();
return $this->getEmote((string)$this->dbConn->getLastInsertId());
}
public function deleteEmote(EmoteInfo|string $infoOrId): void {
if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId();
$stmt = $this->cache->get('DELETE FROM msz_emoticons WHERE emote_id = ?');
$stmt->addParameter(1, $infoOrId);
$stmt->execute();
}
public function updateEmote(
EmoteInfo|string $infoOrId,
?int $order = null,
?int $minRank = null,
?string $url = null
): void {
if($url !== null) {
$check = self::checkEmoteUrlInternal($url);
if($check !== '')
throw new InvalidArgumentException('$url is not correctly formatted: ' . $check);
}
if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId();
$stmt = $this->cache->get('UPDATE msz_emoticons SET emote_order = COALESCE(?, emote_order), emote_hierarchy = COALESCE(?, emote_hierarchy), emote_url = COALESCE(?, emote_url) WHERE emote_id = ?');
$stmt->addParameter(1, $order);
$stmt->addParameter(2, $minRank);
$stmt->addParameter(3, $url);
$stmt->addParameter(4, $infoOrId);
$stmt->execute();
}
public function updateEmoteOrderOffset(EmoteInfo|string $infoOrId, int $offset): void {
if($offset === 0) return;
if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId();
$stmt = $this->cache->get('UPDATE msz_emoticons SET emote_order = emote_order + ? WHERE emote_id = ?');
$stmt->addParameter(1, $offset);
$stmt->addParameter(2, $infoOrId);
$stmt->execute();
}
public function getEmoteStrings(EmoteInfo|string $infoOrId): iterable {
if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId();
$stmt = $this->cache->get('SELECT emote_id, emote_string_order, emote_string FROM msz_emoticons_strings WHERE emote_id = ? ORDER BY emote_string_order');
$stmt->addParameter(1, $infoOrId);
$stmt->execute();
return $stmt->getResult()->getIterator(EmoteStringInfo::fromResult(...));
}
private static function checkEmoteStringInternal(string $string): string {
if(empty($string))
return 'empty';
if(trim($string) !== $string)
return 'spaces';
if(strtolower($string) !== $string)
return 'case';
if(!preg_match('#^[a-z][a-z0-9_-]*[a-z0-9]$#', $string))
return 'format';
return '';
}
public function checkEmoteString(string $string): string {
$check = self::checkEmoteStringInternal($string);
if($check !== '')
return $check;
$stmt = $this->cache->get('SELECT COUNT(*) FROM msz_emoticons_strings WHERE emote_string = ?');
$stmt->addParameter(1, $string);
$stmt->execute();
$result = $stmt->getResult();
if($result->next() && $result->getInteger(0) > 0)
return 'used';
return '';
}
public function addEmoteString(EmoteInfo|string $infoOrId, string $string, ?int $order = null): void {
$check = self::checkEmoteStringInternal($string);
if($check !== '')
throw new InvalidArgumentException('$string is not correctly formatted: ' . $check);
if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId();
$stmt = $this->cache->get('INSERT INTO msz_emoticons_strings (emote_id, emote_string, emote_string_order) SELECT ? AS target_emote_id, ?, COALESCE(?, (SELECT MAX(emote_string_order) + 1 FROM msz_emoticons_strings WHERE emote_id = target_emote_id), 1)');
$stmt->addParameter(1, $infoOrId);
$stmt->addParameter(2, $string);
$stmt->addParameter(3, $order);
$stmt->execute();
}
public function removeEmoteString(EmoteStringInfo|string $infoOrString): void {
if($infoOrString instanceof EmoteStringInfo)
$infoOrString = $infoOrString->getString();
$stmt = $this->cache->get('DELETE FROM msz_emoticons_strings WHERE emote_string = ?');
$stmt->addParameter(1, $infoOrString);
$stmt->execute();
}
}