This repository has been archived on 2024-09-05. You can view files and clone it, but cannot push or open issues or pull requests.
shimmie2/core/config.php

379 lines
12 KiB
PHP
Raw Normal View History

2021-12-14 18:32:47 +00:00
<?php
declare(strict_types=1);
namespace Shimmie2;
2009-07-19 07:38:13 +00:00
/**
* Interface Config
*
* An abstract interface for altering a name:value pair list.
2009-01-04 14:38:48 +00:00
*/
interface Config
{
/**
* Save the list of name:value pairs to wherever they came from,
* so that the next time a page is loaded it will use the new
* configuration.
*/
2023-11-11 21:49:12 +00:00
public function save(string $name = null): void;
//@{ /*--------------------------------- SET ------------------------------------------------------*/
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*/
2020-01-26 13:19:35 +00:00
public function set_int(string $name, ?int $value): void;
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*/
2020-01-26 13:19:35 +00:00
public function set_float(string $name, ?float $value): void;
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*/
public function set_string(string $name, ?string $value): void;
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*/
2020-01-26 13:19:35 +00:00
public function set_bool(string $name, ?bool $value): void;
/**
* Set a configuration option to a new value, regardless of what the value is at the moment.
*
* @param mixed[] $value
*/
public function set_array(string $name, array $value): void;
//@} /*--------------------------------------------------------------------------------------------*/
//@{ /*-------------------------------- SET DEFAULT -----------------------------------------------*/
/**
* Set a configuration option to a new value, if there is no value currently.
*
* Extensions should generally call these from their InitExtEvent handlers.
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*/
public function set_default_int(string $name, int $value): void;
/**
* Set a configuration option to a new value, if there is no value currently.
*
* Extensions should generally call these from their InitExtEvent handlers.
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*/
public function set_default_float(string $name, float $value): void;
/**
* Set a configuration option to a new value, if there is no value currently.
*
* Extensions should generally call these from their InitExtEvent handlers.
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*/
public function set_default_string(string $name, string $value): void;
/**
* Set a configuration option to a new value, if there is no value currently.
*
* Extensions should generally call these from their InitExtEvent handlers.
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*/
public function set_default_bool(string $name, bool $value): void;
/**
* Set a configuration option to a new value, if there is no value currently.
*
* Extensions should generally call these from their InitExtEvent handlers.
* This has the advantage that the values will show up in the "advanced" setup
* page where they can be modified, while calling get_* with a "default"
* parameter won't show up.
*
* @param mixed[] $value
*/
public function set_default_array(string $name, array $value): void;
//@} /*--------------------------------------------------------------------------------------------*/
//@{ /*--------------------------------- GET ------------------------------------------------------*/
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*/
2023-11-11 21:49:12 +00:00
public function get_int(string $name, ?int $default = null): ?int;
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*/
2023-11-11 21:49:12 +00:00
public function get_float(string $name, ?float $default = null): ?float;
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*/
2023-11-11 21:49:12 +00:00
public function get_string(string $name, ?string $default = null): ?string;
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*/
2023-11-11 21:49:12 +00:00
public function get_bool(string $name, ?bool $default = null): ?bool;
/**
* Pick a value out of the table by name, cast to the appropriate data type.
*
* @param mixed[] $default
* @return mixed[]
*/
2023-11-11 21:49:12 +00:00
public function get_array(string $name, ?array $default = []): ?array;
//@} /*--------------------------------------------------------------------------------------------*/
2009-01-04 14:38:48 +00:00
}
2009-07-19 07:38:13 +00:00
/**
* Class BaseConfig
*
2009-01-04 14:38:48 +00:00
* Common methods for manipulating the list, loading and saving is
* left to the concrete implementation
*/
abstract class BaseConfig implements Config
{
/** @var array<string, mixed> */
public array $values = [];
2020-01-26 13:19:35 +00:00
public function set_int(string $name, ?int $value): void
{
2020-01-26 13:19:35 +00:00
$this->values[$name] = is_null($value) ? null : $value;
$this->save($name);
}
2020-01-26 13:19:35 +00:00
public function set_float(string $name, ?float $value): void
{
$this->values[$name] = $value;
$this->save($name);
}
2019-05-28 18:00:23 +00:00
public function set_string(string $name, ?string $value): void
{
$this->values[$name] = $value;
$this->save($name);
}
2020-01-26 13:19:35 +00:00
public function set_bool(string $name, ?bool $value): void
{
2020-01-26 13:19:35 +00:00
$this->values[$name] = $value ? 'Y' : 'N';
$this->save($name);
}
public function set_array(string $name, ?array $value): void
{
2023-11-11 21:49:12 +00:00
if ($value != null) {
$this->values[$name] = implode(",", $value);
} else {
$this->values[$name] = null;
}
$this->save($name);
}
2019-05-28 18:00:23 +00:00
public function set_default_int(string $name, int $value): void
{
if (is_null($this->get($name))) {
$this->values[$name] = $value;
}
}
2019-06-15 16:03:09 +00:00
public function set_default_float(string $name, float $value): void
{
if (is_null($this->get($name))) {
$this->values[$name] = $value;
}
}
2019-05-28 18:00:23 +00:00
public function set_default_string(string $name, string $value): void
{
if (is_null($this->get($name))) {
$this->values[$name] = $value;
}
}
2019-05-28 18:00:23 +00:00
public function set_default_bool(string $name, bool $value): void
{
if (is_null($this->get($name))) {
$this->values[$name] = $value ? 'Y' : 'N';
}
}
2019-05-28 18:00:23 +00:00
public function set_default_array(string $name, array $value): void
{
if (is_null($this->get($name))) {
$this->values[$name] = implode(",", $value);
}
}
/**
* @template T of int|null
* @param T $default
* @return T|int
*/
2023-11-11 21:49:12 +00:00
public function get_int(string $name, ?int $default = null): ?int
{
return (int)($this->get($name, $default));
}
/**
* @template T of float|null
* @param T $default
* @return T|float
*/
2023-11-11 21:49:12 +00:00
public function get_float(string $name, ?float $default = null): ?float
2019-06-15 16:03:09 +00:00
{
return (float)($this->get($name, $default));
}
/**
* @template T of string|null
* @param T $default
* @return T|string
*/
2023-11-11 21:49:12 +00:00
public function get_string(string $name, ?string $default = null): ?string
{
2020-01-26 17:43:39 +00:00
$val = $this->get($name, $default);
2020-01-26 23:23:01 +00:00
if (!is_string($val) && !is_null($val)) {
2024-02-11 15:47:40 +00:00
throw new ServerError("$name is not a string: $val");
2020-01-26 23:23:01 +00:00
}
2020-01-26 17:43:39 +00:00
return $val;
}
/**
* @template T of bool|null
* @param T $default
* @return T|bool
*/
2023-11-11 21:49:12 +00:00
public function get_bool(string $name, ?bool $default = null): ?bool
{
return bool_escape($this->get($name, $default));
}
/**
* @template T of array<string>|null
* @param T $default
* @return T|array<string>
*/
public function get_array(string $name, ?array $default = null): ?array
{
$val = $this->get($name);
if(is_null($val)) {
return $default;
}
if(empty($val)) {
return [];
}
return explode(",", $val);
}
private function get(string $name, mixed $default = null): mixed
{
if (isset($this->values[$name])) {
return $this->values[$name];
} else {
return $default;
}
}
2009-01-04 14:38:48 +00:00
}
2009-07-19 07:38:13 +00:00
/**
* Class DatabaseConfig
*
2009-01-04 15:57:54 +00:00
* Loads the config list from a table in a given database, the table should
* be called config and have the schema:
*
* \code
2009-01-04 15:57:54 +00:00
* CREATE TABLE config(
* name VARCHAR(255) NOT NULL,
* value TEXT
* );
* \endcode
*/
class DatabaseConfig extends BaseConfig
{
private Database $database;
private string $table_name;
private ?string $sub_column;
private ?string $sub_value;
2023-02-03 16:44:16 +00:00
private string $cache_name;
2019-09-29 13:30:55 +00:00
public function __construct(
Database $database,
string $table_name = "config",
string $sub_column = null,
string $sub_value = null
) {
global $cache;
$this->database = $database;
$this->table_name = $table_name;
$this->sub_value = $sub_value;
$this->sub_column = $sub_column;
$this->cache_name = empty($sub_value) ? "config" : "config_{$sub_column}_{$sub_value}";
2023-12-14 17:06:54 +00:00
$this->values = cache_get_or_set($this->cache_name, fn () => $this->get_values());
}
2023-12-14 17:06:54 +00:00
private function get_values(): mixed
{
$values = [];
2023-12-14 17:06:54 +00:00
$query = "SELECT name, value FROM {$this->table_name}";
$args = [];
2023-12-14 17:06:54 +00:00
if (!empty($this->sub_column) && !empty($this->sub_value)) {
$query .= " WHERE {$this->sub_column} = :sub_value";
$args["sub_value"] = $this->sub_value;
}
2023-12-14 17:06:54 +00:00
foreach ($this->database->get_all($query, $args) as $row) {
$values[$row["name"]] = $row["value"];
}
2023-12-14 17:06:54 +00:00
return $values;
}
2023-11-11 21:49:12 +00:00
public function save(string $name = null): void
{
global $cache;
if (is_null($name)) {
reset($this->values); // rewind the array to the first element
foreach ($this->values as $name => $value) {
$this->save($name);
}
} else {
$query = "DELETE FROM {$this->table_name} WHERE name = :name";
2023-11-11 21:49:12 +00:00
$args = ["name" => $name];
$cols = ["name","value"];
$params = [":name",":value"];
2023-11-11 21:49:12 +00:00
if (!empty($this->sub_column) && !empty($this->sub_value)) {
$query .= " AND $this->sub_column = :sub_value";
$args["sub_value"] = $this->sub_value;
$cols[] = $this->sub_column;
$params[] = ":sub_value";
}
2020-10-25 21:34:52 +00:00
$this->database->execute($query, $args);
2023-11-11 21:49:12 +00:00
$args["value"] = $this->values[$name];
2020-10-25 21:34:52 +00:00
$this->database->execute(
2019-09-29 13:30:55 +00:00
"INSERT INTO {$this->table_name} (".join(",", $cols).") VALUES (".join(",", $params).")",
$args
);
}
// rather than deleting and having some other request(s) do a thundering
// herd of race-conditioned updates, just save the updated version once here
2023-02-02 16:39:36 +00:00
$cache->set($this->cache_name, $this->values);
$this->database->notify($this->cache_name);
}
}