227 lines
6.7 KiB
PHP
227 lines
6.7 KiB
PHP
<?php
|
|
// DbConfig.php
|
|
// Created: 2023-10-20
|
|
// Updated: 2023-10-20
|
|
|
|
namespace Syokuhou;
|
|
|
|
use InvalidArgumentException;
|
|
use Index\Data\DbStatementCache;
|
|
use Index\Data\DbTools;
|
|
use Index\Data\IDbConnection;
|
|
|
|
/**
|
|
* Provides a configuration based on a {@see IDbConnection} instance.
|
|
*
|
|
* @todo provide table name in constructor
|
|
* @todo scan for vendor specific queries and generalise them
|
|
* @todo getValues() parsing should probably be done external so it can be reused
|
|
*/
|
|
class DbConfig implements IConfig {
|
|
use MutableConfigTrait, GetValueInfoTrait, GetValuesTrait;
|
|
|
|
private DbStatementCache $cache;
|
|
/** @var array<string, DbConfigValueInfo> */
|
|
private array $values = [];
|
|
|
|
public function __construct(
|
|
IDbConnection $dbConn,
|
|
private string $tableName,
|
|
private string $nameField = 'config_name',
|
|
private string $valueField = 'config_value'
|
|
) {
|
|
$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;
|
|
}
|
|
|
|
/**
|
|
* Resets value cache.
|
|
*/
|
|
public function reset(): void {
|
|
$this->values = [];
|
|
}
|
|
|
|
/**
|
|
* Unloads specifics items from the local cache.
|
|
*
|
|
* @param string|string[] $names Names of values to unload.
|
|
*/
|
|
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 getSeparator(): string {
|
|
return '.';
|
|
}
|
|
|
|
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 %s WHERE %s IN (%s)',
|
|
$this->tableName, $this->nameField,
|
|
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 %s WHERE %s IN (%s)',
|
|
$this->tableName, $this->nameField,
|
|
DbTools::prepareListString($nameCount)
|
|
));
|
|
|
|
for($i = 0; $i < $nameCount; ++$i)
|
|
$stmt->addParameter($i + 1, $names[$i]);
|
|
|
|
$stmt->execute();
|
|
}
|
|
|
|
public function getAllValueInfos(int $range = 0, int $offset = 0): array {
|
|
$this->reset();
|
|
$infos = [];
|
|
|
|
$hasRange = $range !== 0;
|
|
|
|
$query = sprintf('SELECT %s, %s FROM %s', $this->nameField, $this->valueField, $this->tableName);
|
|
if($hasRange) {
|
|
if($range < 0)
|
|
throw new InvalidArgumentException('$range must be a positive integer.');
|
|
if($offset < 0)
|
|
throw new InvalidArgumentException('$offset must be greater than zero if a range is specified.');
|
|
|
|
$query .= ' LIMIT ? OFFSET ?';
|
|
}
|
|
|
|
$stmt = $this->cache->get($query);
|
|
if($hasRange) {
|
|
$stmt->addParameter(1, $range);
|
|
$stmt->addParameter(2, $offset);
|
|
}
|
|
$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 %s, %s FROM %s WHERE config_name IN (%s)',
|
|
$this->nameField, $this->valueField, $this->tableName,
|
|
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 setValues(array $values): void {
|
|
if(empty($values))
|
|
return;
|
|
|
|
$stmt = $this->cache->get(sprintf(
|
|
'INSERT INTO %s (%s, %s) VALUES (?, ?)',
|
|
$this->tableName, $this->nameField, $this->valueField
|
|
));
|
|
|
|
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.');
|
|
|
|
$this->removeValues($name);
|
|
|
|
$stmt->addParameter(1, $name);
|
|
$stmt->addParameter(2, serialize($value));
|
|
$stmt->execute();
|
|
}
|
|
|
|
}
|
|
}
|