feat(cloud): P1-B scaffold — composer autoload + Config
This commit is contained in:
parent
65344f6ea6
commit
50cb2cfe82
6 changed files with 70 additions and 0 deletions
4
cloud/.gitignore
vendored
Normal file
4
cloud/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/vendor/
|
||||
/config.php
|
||||
/storage/snapshots/*
|
||||
!/storage/snapshots/.gitkeep
|
||||
8
cloud/composer.json
Normal file
8
cloud/composer.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "move-detect/cloud",
|
||||
"type": "project",
|
||||
"require": { "php": ">=8.2" },
|
||||
"require-dev": { "phpunit/phpunit": "^11" },
|
||||
"autoload": { "psr-4": { "App\\": "src/" } },
|
||||
"autoload-dev": { "psr-4": { "App\\Tests\\": "tests/" } }
|
||||
}
|
||||
9
cloud/config.example.php
Normal file
9
cloud/config.example.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
return [
|
||||
'db_dsn' => 'mysql:host=localhost;dbname=move_detect;charset=utf8mb4',
|
||||
'db_user' => 'CHANGEME',
|
||||
'db_pass' => 'CHANGEME',
|
||||
'snapshot_dir' => __DIR__ . '/storage/snapshots',
|
||||
'timestamp_window' => 300,
|
||||
'rate_limit_per_min' => 60,
|
||||
];
|
||||
7
cloud/phpunit.xml
Normal file
7
cloud/phpunit.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
bootstrap="vendor/autoload.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="unit"><directory>tests</directory></testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
18
cloud/src/Config.php
Normal file
18
cloud/src/Config.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace App;
|
||||
|
||||
final class Config
|
||||
{
|
||||
private function __construct(private array $a) {}
|
||||
|
||||
public static function fromArray(array $a): self { return new self($a); }
|
||||
|
||||
public function dbDsn(): string { return (string)($this->a['db_dsn'] ?? ''); }
|
||||
public function dbUser(): string { return (string)($this->a['db_user'] ?? ''); }
|
||||
public function dbPass(): string { return (string)($this->a['db_pass'] ?? ''); }
|
||||
public function snapshotDir(): string { return (string)($this->a['snapshot_dir'] ?? __DIR__ . '/../storage/snapshots'); }
|
||||
public function nonceTtl(): int { return (int)($this->a['nonce_ttl'] ?? 86400); }
|
||||
public function timestampWindow(): int { return (int)($this->a['timestamp_window'] ?? 300); }
|
||||
public function rateLimitPerMin(): int { return (int)($this->a['rate_limit_per_min'] ?? 60); }
|
||||
}
|
||||
24
cloud/tests/ConfigTest.php
Normal file
24
cloud/tests/ConfigTest.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace App\Tests;
|
||||
use App\Config;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ConfigTest extends TestCase
|
||||
{
|
||||
public function testTypedGettersWithDefaults(): void
|
||||
{
|
||||
$c = Config::fromArray(['db_dsn' => 'sqlite::memory:']);
|
||||
$this->assertSame('sqlite::memory:', $c->dbDsn());
|
||||
$this->assertSame(300, $c->timestampWindow());
|
||||
$this->assertSame(60, $c->rateLimitPerMin());
|
||||
$this->assertSame(86400, $c->nonceTtl());
|
||||
}
|
||||
|
||||
public function testOverrides(): void
|
||||
{
|
||||
$c = Config::fromArray(['db_dsn' => 'x', 'timestamp_window' => 120, 'rate_limit_per_min' => 30]);
|
||||
$this->assertSame(120, $c->timestampWindow());
|
||||
$this->assertSame(30, $c->rateLimitPerMin());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue