151 lines
3.4 KiB
PHP
151 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App;
|
|
|
|
final class RegistrationStore
|
|
{
|
|
public function __construct(
|
|
private readonly string $storagePath,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public function all(): array
|
|
{
|
|
$items = $this->read();
|
|
usort(
|
|
$items,
|
|
static fn (array $left, array $right): int => strcmp(
|
|
(string) ($right['created_at'] ?? ''),
|
|
(string) ($left['created_at'] ?? '')
|
|
)
|
|
);
|
|
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function find(string $id): ?array
|
|
{
|
|
foreach ($this->read() as $item) {
|
|
if ((string) ($item['id'] ?? '') === $id) {
|
|
return $item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function findConflict(string $username, string $email): ?array
|
|
{
|
|
$username = strtolower(trim($username));
|
|
$email = strtolower(trim($email));
|
|
|
|
foreach ($this->read() as $item) {
|
|
$status = (string) ($item['status'] ?? 'pending');
|
|
|
|
if ($status === 'rejected') {
|
|
continue;
|
|
}
|
|
|
|
if (strtolower((string) ($item['username'] ?? '')) === $username) {
|
|
return $item;
|
|
}
|
|
|
|
if (strtolower((string) ($item['email'] ?? '')) === $email) {
|
|
return $item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $payload
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function create(array $payload): array
|
|
{
|
|
$items = $this->read();
|
|
$items[] = $payload;
|
|
$this->write($items);
|
|
|
|
return $payload;
|
|
}
|
|
|
|
/**
|
|
* @param callable(array<string, mixed>): array<string, mixed> $mutator
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function update(string $id, callable $mutator): ?array
|
|
{
|
|
$items = $this->read();
|
|
$updated = null;
|
|
|
|
foreach ($items as $index => $item) {
|
|
if ((string) ($item['id'] ?? '') !== $id) {
|
|
continue;
|
|
}
|
|
|
|
$items[$index] = $mutator($item);
|
|
$updated = $items[$index];
|
|
break;
|
|
}
|
|
|
|
if ($updated === null) {
|
|
return null;
|
|
}
|
|
|
|
$this->write($items);
|
|
|
|
return $updated;
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
private function read(): array
|
|
{
|
|
if (!is_file($this->storagePath)) {
|
|
return [];
|
|
}
|
|
|
|
$raw = file_get_contents($this->storagePath);
|
|
|
|
if ($raw === false || trim($raw) === '') {
|
|
return [];
|
|
}
|
|
|
|
$decoded = json_decode($raw, true);
|
|
|
|
return is_array($decoded) ? array_values(array_filter($decoded, 'is_array')) : [];
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $items
|
|
*/
|
|
private function write(array $items): void
|
|
{
|
|
$directory = dirname($this->storagePath);
|
|
|
|
if (!is_dir($directory)) {
|
|
mkdir($directory, 0775, true);
|
|
}
|
|
|
|
file_put_contents(
|
|
$this->storagePath,
|
|
json_encode($items, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL,
|
|
LOCK_EX
|
|
);
|
|
}
|
|
}
|