Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig;
use Xentral\Core\DependencyInjection\ContainerInterface;
use Xentral\Modules\SystemConfig\Gateway\SystemConfigGateway;
use Xentral\Modules\SystemConfig\Helper\SystemConfigHelper;
use Xentral\Modules\SystemConfig\Service\SystemConfigService;
final class Bootstrap
{
/**
* @return array
*/
public static function registerServices(): array
{
return [
'SystemConfigModule' => 'onInitSystemConfigModule',
];
}
/**
* @param ContainerInterface $container
*
* @return SystemConfigService
*/
public static function onInitSystemConfigModule(ContainerInterface $container): SystemConfigModule
{
return new SystemConfigModule(
self::onInitSystemConfigService($container),
self::onInitSystemConfigGateway($container)
);
}
/**
* @param ContainerInterface $container
*
* @return SystemConfigService
*/
private static function onInitSystemConfigService(ContainerInterface $container): SystemConfigService
{
return new SystemConfigService(
self::onInitSystemConfigGateway($container),
$container->get('Database'),
self::onInitSystemConfigHelper()
);
}
/**
* @param ContainerInterface $container
*
* @return SystemConfigGateway
*/
private static function onInitSystemConfigGateway(ContainerInterface $container): SystemConfigGateway
{
return new SystemConfigGateway(
$container->get('Database'),
self::onInitSystemConfigHelper()
);
}
/**
* @return SystemConfigHelper
*/
private static function onInitSystemConfigHelper(): SystemConfigHelper
{
return new SystemConfigHelper();
}
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use RuntimeException as SplRuntimeException;
class ConfigurationKeyNotFoundException extends SplRuntimeException implements SystemConfigExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use InvalidArgumentException as SplInvalidArgumentException;
class InvalidArgumentException extends SplInvalidArgumentException implements SystemConfigExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use RuntimeException as SplRuntimeException;
class SystemConfigClassCreationFailed extends SplRuntimeException implements SystemConfigExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use TypeError;
class SystemConfigClassTypeError extends TypeError implements SystemConfigExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use Xentral\Core\Exception\ModuleExceptionInterface;
interface SystemConfigExceptionInterface extends ModuleExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Modules\SystemConfig\Exception;
use InvalidArgumentException as SplInvalidArgumentException;
class ValueTooLargeException extends SplInvalidArgumentException implements SystemConfigExceptionInterface
{
}
@@ -0,0 +1,176 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig\Gateway;
use Exception;
use TypeError;
use Xentral\Components\Database\Database;
use Xentral\Modules\SystemConfig\Exception\ConfigurationKeyNotFoundException;
use Xentral\Modules\SystemConfig\Exception\InvalidArgumentException;
use Xentral\Modules\SystemConfig\Exception\SystemConfigClassCreationFailed;
use Xentral\Modules\SystemConfig\Exception\SystemConfigClassTypeError;
use Xentral\Modules\SystemConfig\Helper\SystemConfigHelper;
use Xentral\Modules\SystemConfig\Interfaces\SystemConfigSerializableInterface;
final class SystemConfigGateway
{
/** @var Database $db */
private $db;
/** @var SystemConfigHelper $helper */
private $helper;
/**
* @param Database $database
* @param SystemConfigHelper $helper
*/
public function __construct(
Database $database,
SystemConfigHelper $helper
) {
$this->db = $database;
$this->helper = $helper;
}
/**
* @param string $namespace
* @param string $key
* @param mixed $default
*
* @throws InvalidArgumentException
*
* @return string
*/
public function tryGetValue(string $namespace, string $key, string $default = null): ?string
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$result = $this->fetchValueFromDatabase($configurationKey);
if ($result === false) {
if(is_null($default)){
return null;
}
return (string)$default;
}
return (string)$result;
}
/**
* @param string $configurationKey
*
* @return false|string
*/
protected function fetchValueFromDatabase($configurationKey)
{
$sql = 'SELECT `wert`
FROM `konfiguration`
WHERE `name` = :name LIMIT 1';
$values = [
'name' => $configurationKey,
];
return $this->db->fetchValue($sql, $values);
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
*
* @return bool
*/
public function isKeyExisting(string $namespace, string $key): bool
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$sql = 'SELECT `name`
FROM `konfiguration`
WHERE `name` = :name';
$values = [
'name' => $configurationKey,
];
return !empty($this->db->fetchValue($sql, $values));
}
/**
* @param string $class
*
* @throws InvalidArgumentException
* @throws ConfigurationKeyNotFoundException
*
* @return object|SystemConfigSerializableInterface
*/
public function getObject(string $class)
{
if (!in_array(SystemConfigSerializableInterface::class, class_implements($class), true)) {
$message = sprintf('Class %s does not implement %s', $class, SystemConfigSerializableInterface::class);
throw new InvalidArgumentException($message);
}
/** @var SystemConfigSerializableInterface $class */
$namespace = $class::getSystemConfigNamespace();
$key = $class::getSystemConfigKey();
$result = $this->getValue($namespace, $key);
try {
return $class::fromArray(unserialize($result, ['allowed_classes' => false]));
} catch (Exception $exception) {
$message = 'Was not able to create object for class ' . $class;
throw new SystemConfigClassCreationFailed($message, $exception->getCode(), $exception);
} catch (TypeError $error) {
throw new SystemConfigClassTypeError($error->getMessage(), $error->getCode(), $error);
}
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
* @throws ConfigurationKeyNotFoundException
*
* @return string
*/
public function getValue(string $namespace, string $key): string
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$result = $this->fetchValueFromDatabase($configurationKey);
if ($result === false) {
$message = sprintf(
'Key "%s" was not found in namespace "%s".',
$key,
$namespace
);
throw new ConfigurationKeyNotFoundException($message);
}
return (string)$result;
}
/**
* @deprecated Used to get legacy configuration data from the database <br>
* Ideally this function should only be used to migrate data in combination with the deleteLegacyKey() function
*
* @param string $key
*
* @return string|null
*/
public function tryGetLegacyValue(string $key): ?string
{
$result = $this->fetchValueFromDatabase($key);
if($result === false){
return null;
}
return (string)$this->fetchValueFromDatabase($key);
}
}
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig\Helper;
use Xentral\Modules\SystemConfig\Exception\InvalidArgumentException;
final class SystemConfigHelper
{
/** @var string $delimiter */
private $delimiter = '__';
/** @var int $allowedTotalLength */
private $allowedTotalLength;
public function __construct()
{
$this->setAllowedTotalLength(255 - strlen($this->getDelimiter()));
}
/**
* @param int $allowedLength
*/
private function setAllowedTotalLength(int $allowedLength): void
{
$this->allowedTotalLength = $allowedLength;
}
/**
* @return string
*/
private function getDelimiter(): string
{
return $this->delimiter;
}
/**
* @param string $namespace
* @param string $key
*
* @return string
*/
public function getValidatedConfigurationKey($namespace, $key): string
{
$this->validateNamespaceAndKey($namespace, $key);
return $this->getConfigurationKey($namespace, $key);
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
*
* @return void
*/
private function validateNamespaceAndKey(string $namespace, string $key): void
{
if (empty($namespace)) {
throw new InvalidArgumentException('Required value "namespace" is empty.');
}
if (empty($key)) {
throw new InvalidArgumentException('Required value "key" is empty.');
}
$pattern = '/^_|[^a-z0-9_]|_$/';
if (preg_match($pattern, $namespace)) {
$message = 'Value "namespace" contains illegal characters. Valid Pattern: ' . $pattern;
throw new InvalidArgumentException($message);
}
if (preg_match($pattern, $key)) {
$message = 'Value "key" contains illegal characters. Valid Pattern: ' . $pattern;
throw new InvalidArgumentException($message);
}
if (strlen(strtolower($namespace . $this->getDelimiter() . $key)) > $this->allowedTotalLength) {
$message = sprintf(
'Combined length of "namespace" and "key" exceeds the allowed length of %d characters.',
$this->allowedTotalLength
);
throw new InvalidArgumentException($message);
}
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
*
* @return string
*/
private function getConfigurationKey($namespace, $key): string
{
return strtolower($namespace . $this->getDelimiter() . $key);
}
/**
* @return int
*/
public function getAllowedTotalLength(): int
{
return $this->allowedTotalLength;
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig\Interfaces;
interface SystemConfigSerializableInterface
{
/**
* @param array $array
*
* @return self
*/
public static function fromArray(array $array): self;
/**
* @return string
*/
public static function getSystemConfigNamespace(): string;
/**
* @return string
*/
public static function getSystemConfigKey(): string;
/**
* @return array
*/
public function toArray(): array;
}
@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig\Service;
use Xentral\Components\Database\Database;
use Xentral\Modules\SystemConfig\Exception\InvalidArgumentException;
use Xentral\Modules\SystemConfig\Exception\ValueTooLargeException;
use Xentral\Modules\SystemConfig\Gateway\SystemConfigGateway;
use Xentral\Modules\SystemConfig\Helper\SystemConfigHelper;
use Xentral\Modules\SystemConfig\Interfaces\SystemConfigSerializableInterface;
final class SystemConfigService
{
/** @var Database $db */
private $db;
/** @var SystemConfigGateway $gateway */
private $gateway;
/** @var SystemConfigHelper $helper */
private $helper;
/**
* @param SystemConfigGateway $gateway
* @param Database $database
* @param SystemConfigHelper $helper
*/
public function __construct(
SystemConfigGateway $gateway,
Database $database,
SystemConfigHelper $helper
) {
$this->gateway = $gateway;
$this->db = $database;
$this->helper = $helper;
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
*
* @return void
*/
public function deleteKey(string $namespace, string $key): void
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$sql = 'DELETE FROM `konfiguration`
WHERE `name` = :name';
$values = [
'name' => $configurationKey,
];
$this->db->perform($sql, $values);
}
/**
* @deprecated Used to delete legacy configuration data from the database <br>
* Ideally this function should only be used to migrate data in combination with the getLegacyValue() function
*
* @param string $key
*
* @return void
*/
public function deleteLegacyKey(string $key): void
{
$sql = 'DELETE FROM `konfiguration`
WHERE `name` = :name';
$values = [
'name' => $key,
];
$this->db->perform($sql, $values);
}
/**
* @param SystemConfigSerializableInterface $object
*
* @throws InvalidArgumentException
*
* @return void
*/
public function setObject(SystemConfigSerializableInterface $object): void
{
$namespace = $object->getSystemConfigNamespace();
$key = $object->getSystemConfigKey();
$this->setValue($namespace, $key, serialize($object->toArray()));
}
/**
* @param string $namespace
* @param string $key
* @param mixed $value
*
* @throws InvalidArgumentException
* @throws ValueTooLargeException
*
* @return void
*/
public function setValue(string $namespace, string $key, $value): void
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$allowedSize = 65536;
if (strlen($value) > $allowedSize) {
throw new ValueTooLargeException('Value to be saved is too large. Maximum allowed Size: ' . $allowedSize);
}
if (!$this->gateway->isKeyExisting($namespace, $key)) {
$this->createConfigEntry($namespace, $key);
}
$sql = 'UPDATE `konfiguration`
SET `wert` = :value
WHERE `name` = :name';
$values = [
'name' => $configurationKey,
'value' => (string)$value,
];
$this->db->perform($sql, $values);
}
/**
* @param string $namespace
* @param string $key
*
* @return void
*/
private function createConfigEntry(string $namespace, string $key): void
{
$configurationKey = $this->helper->getValidatedConfigurationKey($namespace, $key);
$sql = 'INSERT INTO `konfiguration` (`name`, `wert`, `firma`, `adresse`)
VALUES (:name, :value, 0, 0)';
$values = [
'name' => $configurationKey,
'value' => '',
];
$this->db->perform($sql, $values);
}
}
@@ -0,0 +1,152 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\SystemConfig;
use Xentral\Modules\SystemConfig\Exception\ConfigurationKeyNotFoundException;
use Xentral\Modules\SystemConfig\Exception\InvalidArgumentException;
use Xentral\Modules\SystemConfig\Exception\ValueTooLargeException;
use Xentral\Modules\SystemConfig\Gateway\SystemConfigGateway;
use Xentral\Modules\SystemConfig\Interfaces\SystemConfigSerializableInterface;
use Xentral\Modules\SystemConfig\Service\SystemConfigService;
final class SystemConfigModule
{
/** @var SystemConfigGateway $gateway */
private $gateway;
/** @var SystemConfigService $service */
private $service;
/**
* @param SystemConfigService $service
* @param SystemConfigGateway $gateway
*/
public function __construct(SystemConfigService $service, SystemConfigGateway $gateway)
{
$this->service = $service;
$this->gateway = $gateway;
}
/**
* @param string $namespace
* @param string $key
* @param string $value
*
* @throws InvalidArgumentException
* @throws ValueTooLargeException
*
* @return void
*/
public function setValue(string $namespace, string $key, string $value): void
{
$this->service->setValue($namespace, $key, $value);
}
/**
* @param SystemConfigSerializableInterface $object
*
* @throws InvalidArgumentException
* @throws ValueTooLargeException
*
* @return void
*/
public function setObject(SystemConfigSerializableInterface $object): void
{
$this->service->setObject($object);
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
*
* @return void
*/
public function deleteKey(string $namespace, string $key): void
{
$this->service->deleteKey($namespace, $key);
}
/**
* @deprecated Used to delete legacy configuration data from the database <br>
* Ideally this function should only be used to migrate data in combination with the getLegacyValue() function
*
* @param string $key
*
* @return void
*/
public function deleteLegacyKey(string $key): void
{
$this->service->deleteLegacyKey($key);
}
/**
* @param string $class
*
* @throws InvalidArgumentException
* @throws ConfigurationKeyNotFoundException
*
* @return object|SystemConfigSerializableInterface
*/
public function getObject(string $class)
{
return $this->gateway->getObject($class);
}
/**
* @param string $namespace
* @param string $key
*
*
* @throws InvalidArgumentException
* @throws ConfigurationKeyNotFoundException
* @return string
*/
public function getValue(string $namespace, string $key): string
{
return $this->gateway->getValue($namespace, $key);
}
/**
* @param string $namespace
* @param string $key
* @param mixed $default
*
* @throws InvalidArgumentException
*
* @return string|null
*/
public function tryGetValue(string $namespace, string $key, string $default = null): ?string
{
return $this->gateway->tryGetValue($namespace, $key, $default);
}
/**
* @deprecated Used to get legacy configuration data from the database <br>
* Ideally this function should only be used to migrate data in combination with the deleteLegacyKey() function
*
* @param string $key
*
* @return string|null
*/
public function tryGetLegacyValue(string $key): ?string
{
return $this->gateway->tryGetLegacyValue($key);
}
/**
* @param string $namespace
* @param string $key
*
* @throws InvalidArgumentException
* @return bool
*/
public function isKeyExisting(string $namespace, string $key): bool
{
return $this->gateway->isKeyExisting($namespace, $key);
}
}
+238
View File
@@ -0,0 +1,238 @@
# SystemConfig
## Neue SystemConfig-Instanz erzeugen
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
```
## Validierung von Namespace und Key
Namespace und Key dürfen nur folgende Zeichen enthalten:
* Buchstaben im lowercase
* Zahlen
* Unterstriche
Alle anderen Zeichen sind nicht erlaubt und führen zu einer `InvalidArgumentException`.
Zusätzlich darf die Anzahl der Zeichen von Namespace + Key nicht größer als 244 sein,
da sonst ebenso eine `InvalidArgumentException` geworfen wird.
## Maximale Wertgröße
Die maximale Größe eines zu speichernden Wertes ist 64kB.
## Wert speichern
Für die Speicherung eines Wertes werden ein Namespace und Key benötigt.
Der Namespace ist der Modulname, für den die Konfiguration gespeichert werden soll.
Der Key kann frei gewählt werden.
Wenn ein Namespace-Key Paar beim Speichern noch nicht in der Datenbank existiert,
wird es neu erstellt.
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$namespace = 'report';
$key = 'last_value_of_element_1';
$value = 'checked';
$systemConfig->setValue($namespace, $key, $value);
```
## Wert auslesen
Für das Auslesen eines Wertes werden wieder der Namespace und Key benötigt.
Es stehen zwei Funktionen zur Auswahl: `getValue()` sowie `tryGetValue()`.
Falls kein Wert zu einem gegeben Namespace-Key Paar gefunden werden konnte, wirft die getValue()
`ConfigurationKeyNotFoundException`. Die Funktion `tryGetValue()` gibt in so einem Fall den optionalen
default Parameter zurück.
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$namespace = 'report';
$key = 'last_value_of_element_1';
$value = $systemConfig->tryGetValue($namespace, $key, 'fallback');
try {
/** @var string $response */
$value = $systemConfig->getValue($namespace, $key);
} catch (\Xentral\Modules\SystemConfig\Exception\InvalidArgumentException $exception) {
// Für das Namespace-Key Paar existiert noch kein Eintrag in der Datbenank
}
```
## Schlüssel auf Existenz prüfen
Es ist möglich Schlüssel auf Existenz zu prüfen.
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$namespace = 'report';
$key = 'last_value_of_element_1';
$keyExists = $systemConfig->isKeyExisting($namespace, $key);
```
## Datenbankeintrag löschen
Bei Bedarf können Schlüssel samt Wert aus der Datenbank entfernt werden.
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$namespace = 'report';
$key = 'last_value_of_element_1';
$systemConfig->deleteKey($namespace, $key);
```
## Serialisierung von Objekten
Es ist möglich für ein Modul je ein Konfigurationsobjekt zu speichern. Dazu muss das
SystemConfigSerializableInterface implementiert werden.
```php
<?php
declare(strict_types=1);
use Xentral\Modules\SystemConfig\Interfaces\SystemConfigSerializableInterface;
final class ExampleSystemConfig implements SystemConfigSerializableInterface
{
/** @var string|null $voucherArticle */
private $voucherArticle = null;
/** @var int $codeLength */
private $codeLength = 8;
/**
* @return string
*/
public static function getSystemConfigNamespace(): string
{
return 'example';
}
/**
* @return string
*/
public static function getSystemConfigKey(): string
{
return 'voucher_settings';
}
/**
* @return bool
*/
public function hasVoucherArticle(): bool
{
return !is_null($this->voucherArticle);
}
/**
* @return string|null
*/
public function getVoucherArticle(): ?string
{
return $this->voucherArticle;
}
/**
* @return int
*/
public function getCodeLength(): int
{
return $this->codeLength;
}
/**
* @param string|null $voucherArticle
*
* @throws InvalidArgumentException
*/
public function setVoucherArticle(?string $voucherArticle): void
{
if (is_string($voucherArticle) && empty(trim($voucherArticle))) {
throw new InvalidArgumentException('Gutschein-Artikelnummer darf kein Leer-String sein.');
}
$this->voucherArticle = $voucherArticle;
}
/**
* @param int $codeLength
*
* @throws InvalidArgumentException
*/
public function setCodeLength(int $codeLength): void
{
if ($codeLength < 6) {
throw new InvalidArgumentException('Mindestlänge für Gutschein-Codes sind sechs Zeichen.');
}
$this->codeLength = $codeLength;
}
/**
* @return array
*/
public function toArray(): array
{
return [
'voucher_article' => $this->voucherArticle,
'code_length' => $this->codeLength,
];
}
/**
* @param array $data
*
* @throws InvalidArgumentException
*
* @return self
*/
public static function fromArray(array $data): SystemConfigSerializableInterface
{
$instance = new self();
if (isset($data['voucher_article'])) {
$instance->setVoucherArticle($data['voucher_article']);
}
if (isset($data['code_length'])) {
$instance->setCodeLength($data['code_length']);
}
return $instance;
}
}
```
### Objekte speichern
Das Objekt kann anschließend über die `setObject()` Funktion gespeichert werden.
```php
$object = new ClassThatUtilizesSystemConfig([1,'a', 'b' => 'c']);
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$systemConfig->setObject($object);
```
### Objekte laden
Die `getObject()` Funktion liefert ein Object der übergebenen Klasse. Sollte für die Klasse noch keine
Konfiguration gespeichert worden sein, sprich der Schlüssel noch nicht in der Datenbank existieren, wird
eine `ConfigurationKeyNotFoundException` geworfen.
```php
/** @var \Xentral\Modules\SystemConfig\SystemConfigModule $config */
$systemConfig = $container->get('SystemConfigModule');
$object = $systemConfig->getObject(ClassThatUtilizesSystemConfig::class);
```