Initial Version
This commit is contained in:
136
shared/lib/Utile/Collection/CollectionAbstract.php
Normal file
136
shared/lib/Utile/Collection/CollectionAbstract.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXF\Utile\Collection;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @extends \ArrayObject<int, T>
|
||||
*/
|
||||
class CollectionAbstract extends \ArrayObject {
|
||||
|
||||
protected const TYPE_STRING = 'string';
|
||||
protected const TYPE_INT = 'int';
|
||||
protected const TYPE_FLOAT = 'float';
|
||||
protected const TYPE_BOOL = 'bool';
|
||||
protected const TYPE_ARRAY = 'array';
|
||||
protected const TYPE_DATE = 'date';
|
||||
|
||||
protected bool $associative = false;
|
||||
protected string $typeKey = 'int';
|
||||
protected string $typeValue = 'string';
|
||||
|
||||
/**
|
||||
* @param array<T> $data
|
||||
* @param class-string<T>|string|null $typeValue
|
||||
* @param class-string<TKey>|string|null $typeKey
|
||||
*/
|
||||
public function __construct(array $data = [], string $typeValue, string|null $typeKey = null) {
|
||||
// Ensure that all data entries are of the specified type
|
||||
$this->typeValue = $typeValue;
|
||||
if ($typeKey !== null) {
|
||||
$this->typeKey = $typeKey;
|
||||
$this->associative = true;
|
||||
}
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if ($this->associative && !$this->validateKey($key)) {
|
||||
throw new \InvalidArgumentException('Type error: element key ' . $key . ' is not of type ' . $this->typeKey);
|
||||
}
|
||||
if (!$this->validateValue($value)) {
|
||||
throw new \InvalidArgumentException('Type error: element value at index ' . $key . ' is not of type ' . $this->typeValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->associative) {
|
||||
parent::__construct(array_values($data));
|
||||
} else {
|
||||
parent::__construct($data);
|
||||
}
|
||||
}
|
||||
|
||||
private function validateValue($value): bool {
|
||||
// Check if the value is of the specified type
|
||||
return match ($this->typeValue) {
|
||||
self::TYPE_STRING => is_string($value),
|
||||
self::TYPE_INT, 'integer' => is_int($value),
|
||||
self::TYPE_FLOAT => is_float($value),
|
||||
self::TYPE_BOOL, 'boolean' => is_bool($value),
|
||||
self::TYPE_ARRAY => is_array($value),
|
||||
self::TYPE_DATE => $value instanceof \DateTimeInterface,
|
||||
default => $value instanceof $this->typeValue
|
||||
};
|
||||
}
|
||||
|
||||
protected function validateKey($key): bool {
|
||||
// Check if the key is of the specified type
|
||||
return match ($this->typeKey) {
|
||||
self::TYPE_STRING => is_string($key),
|
||||
default => is_int($key),
|
||||
};
|
||||
}
|
||||
|
||||
public function add($value, string|int|null $key = null): void {
|
||||
$this->offsetSet($key, $value);
|
||||
}
|
||||
|
||||
public function remove(string|int $key): void {
|
||||
$this->offsetUnset($key);
|
||||
}
|
||||
|
||||
public function extant(string|int $key): bool {
|
||||
return $this->offsetExists($key);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function append(mixed $value): void {
|
||||
if ($this->associative) {
|
||||
throw new \LogicException('Cannot append to an associative collection. Use add() or offsetSet() instead.');
|
||||
}
|
||||
// ensure that the value is of the specified type before appending
|
||||
if (!$this->validateValue($value)) {
|
||||
throw new \InvalidArgumentException('Type error: value is not of type ' . $this->typeValue);
|
||||
}
|
||||
parent::append($value);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function offsetSet(mixed $key, mixed $value): void {
|
||||
if ($this->associative) {
|
||||
if ($key === null) {
|
||||
throw new \LogicException('Logic error: Key cannot be null for associative collections');
|
||||
}
|
||||
if (!$this->validateKey($key)) {
|
||||
throw new \InvalidArgumentException('Type error: key is not of type ' . $this->typeKey);
|
||||
}
|
||||
} else {
|
||||
if ($key !== null) {
|
||||
throw new \LogicException('Logic error: Key must be null for non-associative collections');
|
||||
}
|
||||
}
|
||||
if (!$this->validateValue($value)) {
|
||||
throw new \InvalidArgumentException('Type error: value is not of type ' . $this->typeValue);
|
||||
}
|
||||
parent::offsetSet($key, $value);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function offsetUnset(mixed $key): void
|
||||
{
|
||||
if (!$this->validateKey($key)) {
|
||||
throw new \InvalidArgumentException('Type error: key is not of type ' . $this->typeKey);
|
||||
}
|
||||
parent::offsetUnset($key);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function offsetExists(mixed $key): bool
|
||||
{
|
||||
if (!$this->validateKey($key)) {
|
||||
throw new \InvalidArgumentException('Type error: key is not of type ' . $this->typeKey);
|
||||
}
|
||||
return parent::offsetExists($key);
|
||||
}
|
||||
|
||||
}
|
||||
54
shared/lib/Utile/UUID.php
Normal file
54
shared/lib/Utile/UUID.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace KTXF\Utile;
|
||||
|
||||
/**
|
||||
* UUID Generator Utility Class
|
||||
*
|
||||
* Generates RFC 4122 compliant UUIDs (version 4 - random)
|
||||
*/
|
||||
class UUID {
|
||||
|
||||
/**
|
||||
* Generate a random UUID v4
|
||||
*
|
||||
* @return string UUID in format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
||||
*/
|
||||
public static function v4(): string {
|
||||
// Generate 16 random bytes
|
||||
$bytes = random_bytes(16);
|
||||
|
||||
// Set version to 4 (random)
|
||||
$bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40);
|
||||
|
||||
// Set variant to RFC 4122
|
||||
$bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80);
|
||||
|
||||
// Format as UUID string
|
||||
return vsprintf(
|
||||
'%s%s-%s-%s-%s-%s%s%s',
|
||||
str_split(bin2hex($bytes), 4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a UUID string
|
||||
*
|
||||
* @param string $uuid UUID to validate
|
||||
* @return bool True if valid UUID format
|
||||
*/
|
||||
public static function isValid(string $uuid): bool {
|
||||
return (bool)preg_match(
|
||||
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i',
|
||||
$uuid
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user