Updated to use Syokuhou config library.

This commit is contained in:
flash 2023-10-20 22:29:28 +00:00
parent 14c9a1d9f6
commit c2836719c7
18 changed files with 52 additions and 685 deletions

View File

@ -8,7 +8,8 @@
"chillerlan/php-qrcode": "^4.3",
"symfony/mailer": "^6.0",
"matomo/device-detector": "^6.1",
"sentry/sdk": "^3.5"
"sentry/sdk": "^3.5",
"flashwave/syokuhou": "dev-master"
},
"autoload": {
"classmap": [

41
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d2644d39e84bfb4bac716f3ce1821f07",
"content-hash": "25bf91ebdb63cd82de113ae91e944fc0",
"packages": [
{
"name": "chillerlan/php-qrcode",
@ -495,6 +495,45 @@
"homepage": "https://railgun.sh/sasae",
"time": "2023-08-24T23:24:45+00:00"
},
{
"name": "flashwave/syokuhou",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://git.flash.moe/flash/syokuhou.git",
"reference": "b3470ad8605b0484294c73cd95be6e7ba4551e5a"
},
"require": {
"flashwave/index": "dev-master",
"php": ">=8.2"
},
"require-dev": {
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.4"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"Syokuhou\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"bsd-3-clause-clear"
],
"authors": [
{
"name": "flashwave",
"email": "packagist@flash.moe",
"homepage": "https://flash.moe",
"role": "mom"
}
],
"description": "Configuration library for PHP.",
"homepage": "https://railgun.sh/syokuhou",
"time": "2023-10-20T21:26:38+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.0.1",

View File

@ -3,7 +3,7 @@ namespace Misuzu;
use Index\Environment;
use Index\Data\DbTools;
use Misuzu\Config\DbConfig;
use Syokuhou\DbConfig;
define('MSZ_STARTUP', microtime(true));
define('MSZ_ROOT', __DIR__);
@ -39,7 +39,7 @@ if(!empty($cfg['sentry-dsn'])) {
$db = DbTools::create($cfg['dsn'] ?? 'null:');
$db->execute('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';');
$cfg = new DbConfig($db);
$cfg = new DbConfig($db, 'msz_config');
Mailer::init($cfg->scopeTo('mail'));

View File

@ -1,8 +1,6 @@
<?php
namespace Misuzu;
use Misuzu\Config\CfgTools;
if(!$msz->getAuthInfo()->getPerms('global')->check(Perm::G_CONFIG_MANAGE))
Template::throwError(403);

View File

@ -1,7 +1,7 @@
<?php
namespace Misuzu;
use Misuzu\Config\DbConfig;
use Syokuhou\DbConfig;
if(!$msz->getAuthInfo()->getPerms('global')->check(Perm::G_CONFIG_MANAGE))
Template::throwError(403);

View File

@ -2,7 +2,7 @@
namespace Misuzu\Auth;
use Index\Data\IDbConnection;
use Misuzu\Config\IConfig;
use Syokuhou\IConfig;
class AuthContext {
private Sessions $sessions;

View File

@ -1,317 +0,0 @@
<?php
namespace Misuzu\Config;
use RuntimeException;
use InvalidArgumentException;
use Index\Data\DataException;
use Index\Data\DbStatementCache;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Data\IDbStatement;
use Index\Data\IDbResult;
use Misuzu\Pagination;
class DbConfig implements IConfig {
private DbStatementCache $cache;
private array $values = [];
public function __construct(IDbConnection $dbConn) {
$this->cache = new DbStatementCache($dbConn);
}
public static function validateName(string $name): bool {
// this should better validate the format, this allows for a lot of shittery
return preg_match('#^([a-z][a-zA-Z0-9._]+)$#', $name) === 1;
}
public function reset(): void {
$this->values = [];
}
public function unload(string|array $names): void {
if(empty($names))
return;
if(is_string($names))
$names = [$names];
foreach($names as $name)
unset($this->values[$name]);
}
public function scopeTo(string $prefix): IConfig {
return new ScopedConfig($this, $prefix);
}
public function hasValues(string|array $names): bool {
if(empty($names))
return true;
if(is_string($names))
$names = [$names];
$cachedNames = array_keys($this->values);
$names = array_diff($names, $cachedNames);
if(!empty($names)) {
// array_diff preserves keys, the for() later would fuck up without it
$names = array_values($names);
$nameCount = count($names);
$stmt = $this->cache->get(sprintf(
'SELECT COUNT(*) FROM msz_config WHERE config_name IN (%s)',
DbTools::prepareListString($nameCount)
));
for($i = 0; $i < $nameCount; ++$i)
$stmt->addParameter($i + 1, $names[$i]);
$stmt->execute();
$result = $stmt->getResult();
if($result->next())
return $result->getInteger(0) >= $nameCount;
}
return true;
}
public function removeValues(string|array $names): void {
if(empty($names))
return;
if(is_string($names))
$names = [$names];
foreach($names as $name)
unset($this->values[$name]);
$nameCount = count($names);
$stmt = $this->cache->get(sprintf(
'DELETE FROM msz_config WHERE config_name IN (%s)',
DbTools::prepareListString($nameCount)
));
for($i = 0; $i < $nameCount; ++$i)
$stmt->addParameter($i + 1, $names[$i]);
$stmt->execute();
}
public function getAllValueInfos(?Pagination $pagination = null): array {
$this->reset();
$infos = [];
$hasPagination = $pagination !== null;
$query = 'SELECT config_name, config_value FROM msz_config';
if($hasPagination)
$query .= ' LIMIT ? RANGE ?';
$stmt = $this->cache->get($query);
if($hasPagination) {
$stmt->addParameter(1, $pagination->getRange());
$stmt->addParameter(2, $pagination->getOffset());
}
$stmt->execute();
$result = $stmt->getResult();
while($result->next()) {
$name = $result->getString(0);
$infos[] = $this->values[$name] = new DbConfigValueInfo($result);
}
return $infos;
}
public function getValueInfos(string|array $names): array {
if(empty($names))
return [];
if(is_string($names))
$names = [$names];
$infos = [];
$skip = [];
foreach($names as $name)
if(array_key_exists($name, $this->values)) {
$infos[] = $this->values[$name];
$skip[] = $name;
}
$names = array_diff($names, $skip);
if(!empty($names)) {
// array_diff preserves keys, the for() later would fuck up without it
$names = array_values($names);
$nameCount = count($names);
$stmt = $this->cache->get(sprintf(
'SELECT config_name, config_value FROM msz_config WHERE config_name IN (%s)',
DbTools::prepareListString($nameCount)
));
for($i = 0; $i < $nameCount; ++$i)
$stmt->addParameter($i + 1, $names[$i]);
$stmt->execute();
$result = $stmt->getResult();
while($result->next()) {
$name = $result->getString(0);
$infos[] = $this->values[$name] = new DbConfigValueInfo($result);
}
}
return $infos;
}
public function getValueInfo(string $name): ?IConfigValueInfo {
$infos = $this->getValueInfos($name);
return empty($infos) ? null : $infos[0];
}
public function getValues(array $specs): array {
$names = [];
foreach($specs as $key => $spec) {
if(is_string($spec)) {
$name = $spec;
$default = null;
$alias = null;
} elseif(is_array($spec) && !empty($spec)) {
$name = $spec[0];
$default = $spec[1] ?? null;
$alias = $spec[2] ?? null;
} else
throw new InvalidArgumentException('$specs array contains an invalid entry.');
if(($colon = strpos($name, ':')) !== false) {
$type = substr($name, $colon + 1, 1);
$name = substr($name, 0, $colon);
} else $type = '';
$names[] = $name;
$specs[$key] = [
'name' => $name,
'type' => $type,
'default' => $default,
'alias' => $alias,
];
}
$infos = $this->getValueInfos($names);
$results = [];
foreach($specs as $spec) {
foreach($infos as $infoTest)
if($infoTest->getName() === $spec['name']) {
$info = $infoTest;
break;
}
$resultName = $spec['alias'] ?? $spec['name'];
if(!isset($info)) {
$defaultValue = $spec['default'] ?? null;
if($spec['type'] !== '')
settype($defaultValue, match($spec['type']) {
's' => 'string',
'a' => 'array',
'i' => 'int',
'b' => 'bool',
'f' => 'float',
'd' => 'double',
default => throw new RuntimeException('Invalid type letter encountered.'),
});
$results[$resultName] = $defaultValue;
continue;
}
$results[$resultName] = match($spec['type']) {
's' => $info->getString(),
'a' => $info->getArray(),
'i' => $info->getInteger(),
'b' => $info->getBoolean(),
'f' => $info->getFloat(),
'd' => $info->getFloat(),
'' => $info->getValue(),
default => throw new RuntimeException('Unknown type encountered in $specs.'),
};
unset($info);
}
return $results;
}
public function getString(string $name, string $default = ''): string {
$valueInfo = $this->getValueInfo($name);
return $valueInfo?->isString() ? $valueInfo->getString() : $default;
}
public function getInteger(string $name, int $default = 0): int {
$valueInfo = $this->getValueInfo($name);
return $valueInfo?->isInteger() ? $valueInfo->getInteger() : $default;
}
public function getFloat(string $name, float $default = 0): float {
$valueInfo = $this->getValueInfo($name);
return $valueInfo?->isFloat() ? $valueInfo->getFloat() : $default;
}
public function getBoolean(string $name, bool $default = false): bool {
$valueInfo = $this->getValueInfo($name);
return $valueInfo?->isBoolean() ? $valueInfo->getBoolean() : $default;
}
public function getArray(string $name, array $default = []): array {
$valueInfo = $this->getValueInfo($name);
return $valueInfo?->isArray() ? $valueInfo->getArray() : $default;
}
public function setValues(array $values): void {
if(empty($values))
return;
$valueCount = count($values);
$stmt = $this->cache->get(sprintf(
'REPLACE INTO msz_config (config_name, config_value) VALUES %s',
DbTools::prepareListString($valueCount, '(?, ?)')
));
$args = 0;
foreach($values as $name => $value) {
if(!self::validateName($name))
throw new InvalidArgumentException('Invalid name encountered in $values.');
if(is_array($value)) {
foreach($value as $entry)
if(!is_scalar($entry))
throw new InvalidArgumentException('An array value in $values contains a non-scalar type.');
} elseif(!is_scalar($value))
throw new InvalidArgumentException('Invalid value type encountered in $values.');
$stmt->addParameter(++$args, $name);
$stmt->addParameter(++$args, serialize($value));
}
$stmt->execute();
}
public function setString(string $name, string $value): void {
$this->setValues([$name => $value]);
}
public function setInteger(string $name, int $value): void {
$this->setValues([$name => $value]);
}
public function setFloat(string $name, float $value): void {
$this->setValues([$name => $value]);
}
public function setBoolean(string $name, bool $value): void {
$this->setValues([$name => $value]);
}
public function setArray(string $name, array $value): void {
$this->setValues([$name => $value]);
}
}

View File

@ -1,93 +0,0 @@
<?php
namespace Misuzu\Config;
use RuntimeException;
use Index\Data\IDbResult;
class DbConfigValueInfo implements IConfigValueInfo {
private string $name;
private string $value;
public function __construct(IDbResult $result) {
$this->name = $result->getString(0);
$this->value = $result->getString(1);
}
public function getName(): string {
return $this->name;
}
public function getType(): string {
return match($this->value[0]) {
's' => 'string',
'a' => 'array',
'i' => 'int',
'b' => 'bool',
'd' => 'float',
default => 'unknown',
};
}
public function isString(): bool {
return $this->value[0] === 's';
}
public function isInteger(): bool {
return $this->value[0] === 'i';
}
public function isFloat(): bool {
return $this->value[0] === 'd';
}
public function isBoolean(): bool {
return $this->value[0] === 'b';
}
public function isArray(): bool {
return $this->value[0] === 'a';
}
public function getValue(): mixed {
return unserialize($this->value);
}
public function getString(): string {
$value = $this->getValue();
if(!is_string($value))
throw new RuntimeException('Value is not a string.');
return $value;
}
public function getInteger(): int {
$value = $this->getValue();
if(!is_int($value))
throw new RuntimeException('Value is not an integer.');
return $value;
}
public function getFloat(): float {
$value = $this->getValue();
if(!is_float($value))
throw new RuntimeException('Value is not a floating point number.');
return $value;
}
public function getBoolean(): bool {
$value = $this->getValue();
if(!is_bool($value))
throw new RuntimeException('Value is not a boolean.');
return $value;
}
public function getArray(): array {
$value = $this->getValue();
if(!is_array($value))
throw new RuntimeException('Value is not an array.');
return $value;
}
public function __toString(): string {
return $this->isArray() ? implode(', ', $this->getArray()) : (string)$this->getValue();
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace Misuzu\Config;
use Misuzu\Pagination;
interface IConfig {
public function scopeTo(string $prefix): IConfig;
public function hasValues(string|array $names): bool;
public function removeValues(string|array $names): void;
public function getAllValueInfos(?Pagination $pagination = null): array;
public function getValueInfos(string|array $names): array;
public function getValueInfo(string $name): ?IConfigValueInfo;
public function getValues(array $specs): array;
public function getString(string $name, string $default = ''): string;
public function getInteger(string $name, int $default = 0): int;
public function getFloat(string $name, float $default = 0): float;
public function getBoolean(string $name, bool $default = false): bool;
public function getArray(string $name, array $default = []): array;
public function setValues(array $values): void;
public function setString(string $name, string $value): void;
public function setInteger(string $name, int $value): void;
public function setFloat(string $name, float $value): void;
public function setBoolean(string $name, bool $value): void;
public function setArray(string $name, array $value): void;
}

View File

@ -1,22 +0,0 @@
<?php
namespace Misuzu\Config;
use Stringable;
interface IConfigValueInfo extends Stringable {
public function getName(): string;
public function getType(): string;
public function isString(): bool;
public function isInteger(): bool;
public function isFloat(): bool;
public function isBoolean(): bool;
public function isArray(): bool;
public function getValue(): mixed;
public function getString(): string;
public function getInteger(): int;
public function getFloat(): float;
public function getBoolean(): bool;
public function getArray(): array;
}

View File

@ -1,138 +0,0 @@
<?php
namespace Misuzu\Config;
use InvalidArgumentException;
use Misuzu\Pagination;
class ScopedConfig implements IConfig {
private IConfig $config;
private string $prefix;
private int $prefixLength;
private const SCOPE_CHAR = '.';
public function __construct(IConfig $config, string $prefix) {
if($prefix === '')
throw new InvalidArgumentException('$prefix may not be empty.');
if(!str_ends_with($prefix, self::SCOPE_CHAR))
$prefix .= self::SCOPE_CHAR;
$this->config = $config;
$this->prefix = $prefix;
$this->prefixLength = strlen($prefix);
}
private function prefixNames(string|array $names): array {
if(is_string($names))
return [$this->prefix . $names];
foreach($names as $key => $name)
$names[$key] = $this->prefix . $name;
return $names;
}
private function prefixName(string $name): string {
return $this->prefix . $name;
}
public function scopeTo(string $prefix): IConfig {
return $this->config->scopeTo($this->prefixName($prefix));
}
public function hasValues(string|array $names): bool {
return $this->config->hasValues($this->prefixNames($names));
}
public function removeValues(string|array $names): void {
$this->config->removeValues($this->prefixNames($names));
}
public function getAllValueInfos(?Pagination $pagination = null): array {
$infos = $this->config->getAllValueInfos($pagination);
foreach($infos as $key => $info)
$infos[$key] = new ScopedConfigValueInfo($info, $this->prefixLength);
return $infos;
}
public function getValueInfos(string|array $names): array {
$infos = $this->config->getValueInfos($this->prefixNames($names));
foreach($infos as $key => $info)
$infos[$key] = new ScopedConfigValueInfo($info, $this->prefixLength);
return $infos;
}
public function getValueInfo(string $name): ?IConfigValueInfo {
$info = $this->config->getValueInfo($this->prefixName($name));
if($info !== null)
$info = new ScopedConfigValueInfo($info, $this->prefixLength);
return $info;
}
public function getValues(array $specs): array {
foreach($specs as $key => $spec) {
if(is_string($spec))
$specs[$key] = $this->prefixName($spec);
elseif(is_array($spec) && !empty($spec))
$specs[$key][0] = $this->prefixName($spec[0]);
else
throw new InvalidArgumentException('$specs array contains an invalid entry.');
}
$results = [];
foreach($this->config->getValues($specs) as $name => $result)
$results[substr($name, $this->prefixLength)] = $result;
return $results;
}
public function getString(string $name, string $default = ''): string {
return $this->config->getString($this->prefixName($name), $default);
}
public function getInteger(string $name, int $default = 0): int {
return $this->config->getInteger($this->prefixName($name), $default);
}
public function getFloat(string $name, float $default = 0): float {
return $this->config->getFloat($this->prefixName($name), $default);
}
public function getBoolean(string $name, bool $default = false): bool {
return $this->config->getBoolean($this->prefixName($name), $default);
}
public function getArray(string $name, array $default = []): array {
return $this->config->getArray($this->prefixName($name), $default);
}
public function setValues(array $values): void {
if(empty($values))
return;
$prefixed = [];
foreach($values as $name => $value)
$prefixed[$this->prefixName($name)] = $value;
$this->config->setValues($values);
}
public function setString(string $name, string $value): void {
$this->config->setString($this->prefixName($name), $value);
}
public function setInteger(string $name, int $value): void {
$this->config->setInteger($this->prefixName($name), $value);
}
public function setFloat(string $name, float $value): void {
$this->config->setFloat($this->prefixName($name), $value);
}
public function setBoolean(string $name, bool $value): void {
$this->config->setBoolean($this->prefixName($name), $value);
}
public function setArray(string $name, array $value): void {
$this->config->setArray($this->prefixName($name), $value);
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace Misuzu\Config;
class ScopedConfigValueInfo implements IConfigValueInfo {
private IConfigValueInfo $info;
private int $prefixLength;
public function __construct(IConfigValueInfo $info, int $prefixLength) {
$this->info = $info;
$this->prefixLength = $prefixLength;
}
public function getName(): string {
return substr($this->info->getName(), $this->prefixLength);
}
public function getRealName(): string {
return $this->info->getName();
}
public function getType(): string {
return $this->info->getType();
}
public function isString(): bool {
return $this->info->isString();
}
public function isInteger(): bool {
return $this->info->isInteger();
}
public function isFloat(): bool {
return $this->info->isFloat();
}
public function isBoolean(): bool {
return $this->info->isBoolean();
}
public function isArray(): bool {
return $this->info->isArray();
}
public function getValue(): mixed {
return $this->info->getValue();
}
public function getString(): string {
return $this->info->getString();
}
public function getInteger(): int {
return $this->info->getInteger();
}
public function getFloat(): float {
return $this->info->getFloat();
}
public function getBoolean(): bool {
return $this->info->getBoolean();
}
public function getArray(): array {
return $this->info->getArray();
}
public function __toString(): string {
return (string)$this->info;
}
}

View File

@ -7,13 +7,13 @@ use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Syokuhou\IConfig;
use Misuzu\Pagination;
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo;
use Misuzu\Changelog\Changelog;
use Misuzu\Comments\Comments;
use Misuzu\Config\IConfig;
use Misuzu\Counters\Counters;
use Misuzu\News\News;
use Misuzu\URLs\URLInfo;

View File

@ -2,7 +2,7 @@
namespace Misuzu;
use InvalidArgumentException;
use Misuzu\Config\IConfig;
use Syokuhou\IConfig;
use Symfony\Component\Mime\Email as SymfonyMessage;
use Symfony\Component\Mime\Address as SymfonyAddress;
use Symfony\Component\Mailer\Transport as SymfonyTransport;

View File

@ -7,6 +7,7 @@ use Index\Data\Migration\IDbMigrationRepo;
use Index\Data\Migration\DbMigrationManager;
use Index\Data\Migration\FsDbMigrationRepo;
use Sasae\SasaeEnvironment;
use Syokuhou\IConfig;
use Misuzu\Template;
use Misuzu\Auth\AuthContext;
use Misuzu\Auth\AuthInfo;
@ -14,7 +15,6 @@ use Misuzu\AuditLog\AuditLog;
use Misuzu\Changelog\Changelog;
use Misuzu\Changelog\ChangelogRoutes;
use Misuzu\Comments\Comments;
use Misuzu\Config\IConfig;
use Misuzu\Counters\Counters;
use Misuzu\Emoticons\Emotes;
use Misuzu\Forum\ForumContext;

View File

@ -6,9 +6,9 @@ use Index\Colour\Colour;
use Index\Routing\IRouter;
use Index\Routing\IRouteHandler;
use Index\Routing\Route;
use Syokuhou\IConfig;
use Misuzu\Pagination;
use Misuzu\RoutingContext;
use Misuzu\Config\IConfig;
use Misuzu\Forum\ForumContext;
use Misuzu\Profile\ProfileFields;
use Misuzu\Users\UsersContext;

View File

@ -6,11 +6,11 @@ use Index\Colour\Colour;
use Index\Routing\IRouter;
use Index\Routing\IRouteHandler;
use Index\Routing\Route;
use Syokuhou\IConfig;
use Misuzu\RoutingContext;
use Misuzu\Auth\AuthContext;
use Misuzu\Auth\AuthInfo;
use Misuzu\Auth\Sessions;
use Misuzu\Config\IConfig;
use Misuzu\Emoticons\Emotes;
use Misuzu\Perms\Permissions;
use Misuzu\URLs\URLRegistry;

View File

@ -1,7 +1,7 @@
<?php
namespace Misuzu;
use Misuzu\Config\IConfig;
use Syokuhou\IConfig;
class SiteInfo {
private bool $loaded = false;