Add MySQL schema dump for phpMyAdmin

This commit is contained in:
Thomas
2025-10-28 14:08:03 +01:00
parent f956a735ca
commit 8e608d03ec
49 changed files with 1929 additions and 1 deletions

93
app/Core/Config.php Normal file
View File

@@ -0,0 +1,93 @@
<?php
namespace App\Core;
class Config
{
private static ?self $instance = null;
/** @var array<string, mixed> */
private array $values = [];
private function __construct()
{
$this->loadEnv();
$this->loadConfigFiles();
}
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function get(string $key, $default = null)
{
$segments = explode('.', $key);
$value = $this->values;
foreach ($segments as $segment) {
if (!is_array($value) || !array_key_exists($segment, $value)) {
return $default;
}
$value = $value[$segment];
}
return $value;
}
/**
* @param array<string, mixed> $config
*/
public function set(array $config): void
{
$this->values = array_replace_recursive($this->values, $config);
}
private function loadEnv(): void
{
$envPath = base_path('.env');
if (!file_exists($envPath)) {
return;
}
$lines = file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines === false) {
return;
}
foreach ($lines as $line) {
if (str_starts_with(trim($line), '#')) {
continue;
}
[$name, $value] = array_map('trim', explode('=', $line, 2) + [1 => '']);
$value = trim($value, "\"' ");
$_ENV[$name] = $value;
putenv("{$name}={$value}");
}
}
private function loadConfigFiles(): void
{
$configDir = base_path('config');
if (!is_dir($configDir)) {
return;
}
$files = glob($configDir . '/*.php');
if ($files === false) {
return;
}
foreach ($files as $file) {
$key = basename($file, '.php');
/** @var array<string, mixed> $data */
$data = require $file;
$this->values[$key] = $data;
}
}
}

17
app/Core/Controller.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace App\Core;
class Controller
{
protected function view(string $template, array $data = []): Response
{
$content = View::render($template, $data);
return new Response($content);
}
protected function redirect(string $url): Response
{
return new Response('', 302, ['Location' => $url]);
}
}

44
app/Core/Database.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
namespace App\Core;
use PDO;
use PDOException;
class Database
{
private static ?PDO $connection = null;
public static function connection(): PDO
{
if (self::$connection === null) {
$config = config('database');
$dsn = sprintf(
'mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
$config['host'],
$config['port'],
$config['database']
);
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
self::$connection = new PDO(
$dsn,
$config['username'],
$config['password'],
$options
);
} catch (PDOException $exception) {
throw new \RuntimeException('Database connection failed: ' . $exception->getMessage());
}
}
return self::$connection;
}
}

39
app/Core/Response.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
namespace App\Core;
class Response
{
private string $body;
private int $status;
/** @var array<string, string> */
private array $headers;
/**
* @param array<string, string> $headers
*/
public function __construct(string $body = '', int $status = 200, array $headers = [])
{
$this->body = $body;
$this->status = $status;
$this->headers = $headers;
}
public function getBody(): string
{
return $this->body;
}
public function getStatus(): int
{
return $this->status;
}
/**
* @return array<string, string>
*/
public function getHeaders(): array
{
return $this->headers;
}
}

97
app/Core/Router.php Normal file
View File

@@ -0,0 +1,97 @@
<?php
namespace App\Core;
class Router
{
/** @var array<string, array<int, array{path:string,action:callable,middleware:array}>> */
private array $routes = [];
/** @var array<int, array<int, class-string>> */
private array $middlewareStack = [];
public function get(string $path, callable $action, array $middleware = []): void
{
$this->addRoute('GET', $path, $action, $middleware);
}
public function post(string $path, callable $action, array $middleware = []): void
{
$this->addRoute('POST', $path, $action, $middleware);
}
public function put(string $path, callable $action, array $middleware = []): void
{
$this->addRoute('PUT', $path, $action, $middleware);
}
public function delete(string $path, callable $action, array $middleware = []): void
{
$this->addRoute('DELETE', $path, $action, $middleware);
}
public function group(array $attributes, \Closure $callback): void
{
$groupMiddleware = $attributes['middleware'] ?? [];
$this->middlewareStack[] = $groupMiddleware;
$callback($this);
array_pop($this->middlewareStack);
}
/**
* @param array<int, class-string> $middleware
*/
private function addRoute(string $method, string $path, callable $action, array $middleware = []): void
{
$stackedMiddleware = [];
foreach ($this->middlewareStack as $group) {
$stackedMiddleware = array_merge($stackedMiddleware, $group);
}
$combinedMiddleware = array_merge($stackedMiddleware, $middleware);
$this->routes[$method][] = [
'path' => $path,
'action' => $action,
'middleware' => $combinedMiddleware,
];
}
public function dispatch(string $method, string $uri): Response
{
$uri = parse_url($uri, PHP_URL_PATH) ?? '/';
$routes = $this->routes[$method] ?? [];
foreach ($routes as $route) {
$pattern = '#^' . preg_replace('#\{(.*?)\}#', '(?P<$1>[^/]+)', $route['path']) . '$#';
if (preg_match($pattern, $uri, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
$handler = $this->applyMiddleware($route['action'], $route['middleware']);
$result = $handler($params);
if ($result instanceof Response) {
return $result;
}
return new Response((string) $result);
}
}
return new Response('Not Found', 404);
}
/**
* @param callable $action
* @param array<int, class-string> $middleware
*/
private function applyMiddleware(callable $action, array $middleware): callable
{
return array_reduce(
array_reverse($middleware),
function ($next, $middlewareClass) {
$middlewareInstance = new $middlewareClass();
return fn(array $params) => $middlewareInstance->handle($params, $next);
},
$action
);
}
}

19
app/Core/View.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Core;
class View
{
public static function render(string $template, array $data = []): string
{
$path = base_path('resources/views/' . $template . '.php');
if (!file_exists($path)) {
throw new \RuntimeException('View not found: ' . $template);
}
extract($data, EXTR_SKIP);
ob_start();
include $path;
return (string) ob_get_clean();
}
}