rebuild to module
This commit is contained in:
@@ -13,6 +13,8 @@ final class App
|
||||
private I18n $i18n;
|
||||
private Flash $flash;
|
||||
private ?\PDO $pdo;
|
||||
private ?\PDO $basePdo;
|
||||
private ModuleManager $modules;
|
||||
|
||||
private function __construct(private Config $config)
|
||||
{
|
||||
@@ -22,6 +24,9 @@ final class App
|
||||
$this->i18n = new I18n($config, 'en');
|
||||
$this->flash = new Flash($this->session);
|
||||
$this->pdo = Database::createPdo($config);
|
||||
$this->basePdo = Database::createBasePdo($config);
|
||||
$this->modules = new ModuleManager($this->basePdo, __DIR__ . '/../../modules');
|
||||
$this->modules->bootEnabled();
|
||||
}
|
||||
|
||||
public static function init(Config $config): self
|
||||
@@ -47,4 +52,6 @@ final class App
|
||||
public function i18n(): I18n { return $this->i18n; }
|
||||
public function flash(): Flash { return $this->flash; }
|
||||
public function pdo(): ?\PDO { return $this->pdo; }
|
||||
public function basePdo(): ?\PDO { return $this->basePdo; }
|
||||
public function modules(): ModuleManager { return $this->modules; }
|
||||
}
|
||||
|
||||
144
src/App/BaseSchema.php
Normal file
144
src/App/BaseSchema.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
final class BaseSchema
|
||||
{
|
||||
public static function ensure(\PDO $pdo): void
|
||||
{
|
||||
$driver = (string)$pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
|
||||
if ($driver === 'pgsql') {
|
||||
self::ensurePgsql($pdo);
|
||||
return;
|
||||
}
|
||||
if ($driver === 'sqlite') {
|
||||
self::ensureSqlite($pdo);
|
||||
return;
|
||||
}
|
||||
self::ensureGeneric($pdo);
|
||||
}
|
||||
|
||||
private static function ensurePgsql(\PDO $pdo): void
|
||||
{
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_modules (
|
||||
name TEXT PRIMARY KEY,
|
||||
title TEXT,
|
||||
version TEXT,
|
||||
enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
installed_at TIMESTAMPTZ,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_module_settings (
|
||||
name TEXT PRIMARY KEY,
|
||||
settings TEXT NOT NULL DEFAULT '{}',
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'user',
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)"
|
||||
);
|
||||
}
|
||||
|
||||
private static function ensureSqlite(\PDO $pdo): void
|
||||
{
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_modules (
|
||||
name TEXT PRIMARY KEY,
|
||||
title TEXT,
|
||||
version TEXT,
|
||||
enabled INTEGER NOT NULL DEFAULT 0,
|
||||
installed_at TEXT,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_module_settings (
|
||||
name TEXT PRIMARY KEY,
|
||||
settings TEXT NOT NULL DEFAULT '{}',
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'user',
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)"
|
||||
);
|
||||
}
|
||||
|
||||
private static function ensureGeneric(\PDO $pdo): void
|
||||
{
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_modules (
|
||||
name VARCHAR(190) PRIMARY KEY,
|
||||
title VARCHAR(190),
|
||||
version VARCHAR(64),
|
||||
enabled TINYINT NOT NULL DEFAULT 0,
|
||||
installed_at DATETIME,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_module_settings (
|
||||
name VARCHAR(190) PRIMARY KEY,
|
||||
settings TEXT NOT NULL,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_settings (
|
||||
`key` VARCHAR(190) PRIMARY KEY,
|
||||
`value` TEXT,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
|
||||
$pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_users (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
email VARCHAR(190) NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'user',
|
||||
is_active TINYINT NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,23 @@ class Config
|
||||
public bool $dbAutoInit;
|
||||
public ?string $dbInitScript;
|
||||
public ?string $dbInitCmd;
|
||||
public string $keaDbVersion;
|
||||
public array $baseDb;
|
||||
public bool $baseDbEnabled;
|
||||
|
||||
public function __construct(
|
||||
public array $db,
|
||||
public bool $dbEnabled = true
|
||||
public bool $dbEnabled = true,
|
||||
array $baseDb = [],
|
||||
bool $baseDbEnabled = false
|
||||
) {
|
||||
$this->assetVersion = defined('ASSET_VERSION') ? ASSET_VERSION : '';
|
||||
$this->dbAutoInit = defined('APP_DB_AUTO_INIT') ? (bool)APP_DB_AUTO_INIT : false;
|
||||
$this->dbInitScript = defined('APP_DB_INIT_SCRIPT') ? (string)APP_DB_INIT_SCRIPT : null;
|
||||
$this->dbInitCmd = defined('APP_DB_INIT_CMD') ? (string)APP_DB_INIT_CMD : null;
|
||||
$this->keaDbVersion = defined('APP_KEA_DB_VERSION') ? (string)APP_KEA_DB_VERSION : '';
|
||||
$this->baseDb = $baseDb;
|
||||
$this->baseDbEnabled = $baseDbEnabled;
|
||||
}
|
||||
|
||||
public function primaryUrl(): string
|
||||
|
||||
@@ -11,39 +11,14 @@ final class Database
|
||||
return null;
|
||||
}
|
||||
|
||||
$db = $config->db;
|
||||
$driver = (string)($db['driver'] ?? '');
|
||||
|
||||
if ($driver === '') {
|
||||
throw new \RuntimeException('DB enabled but config/db.php missing "driver"');
|
||||
}
|
||||
|
||||
$dsn = match ($driver) {
|
||||
'mysql' => self::buildMysqlDsn($db),
|
||||
'pgsql' => self::buildPgsqlDsn($db),
|
||||
'sqlite' => self::buildSqliteDsn($db),
|
||||
default => throw new \RuntimeException('Unsupported PDO driver: ' . $driver),
|
||||
};
|
||||
|
||||
try {
|
||||
$pdo = new \PDO(
|
||||
$dsn,
|
||||
// sqlite braucht user/pass nicht, PDO ignoriert es aber; wir geben leer zurück
|
||||
(string)($db['user'] ?? ''),
|
||||
(string)($db['password'] ?? ''),
|
||||
(array)($db['options'] ?? [])
|
||||
);
|
||||
|
||||
// Optional: PostgreSQL schema/search_path setzen
|
||||
if ($driver === 'pgsql' && !empty($db['schema'])) {
|
||||
// Minimaler Schutz gegen Injection über schema
|
||||
$schema = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$db['schema']);
|
||||
if ($schema !== '') {
|
||||
$pdo->exec('SET search_path TO ' . $schema);
|
||||
}
|
||||
}
|
||||
|
||||
self::ensureSchema($pdo, $config);
|
||||
$pdo = self::createFromArray($config->db);
|
||||
self::ensureKeaSchema($pdo, [
|
||||
'auto_init' => $config->dbAutoInit,
|
||||
'init_cmd' => $config->dbInitCmd,
|
||||
'init_script' => $config->dbInitScript,
|
||||
'kea_db_version' => $config->keaDbVersion,
|
||||
]);
|
||||
|
||||
return $pdo;
|
||||
} catch (\PDOException $e) {
|
||||
@@ -63,7 +38,55 @@ final class Database
|
||||
}
|
||||
}
|
||||
|
||||
private static function ensureSchema(\PDO $pdo, Config $config): void
|
||||
public static function createBasePdo(Config $config): ?\PDO
|
||||
{
|
||||
if (!$config->baseDbEnabled || empty($config->baseDb)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return self::createFromArray($config->baseDb);
|
||||
} catch (\PDOException $e) {
|
||||
http_response_code(500);
|
||||
$details = 'Base database connection error.';
|
||||
error_log('[Base DB] ' . $e->getMessage());
|
||||
echo $details;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public static function createFromArray(array $db): \PDO
|
||||
{
|
||||
$driver = (string)($db['driver'] ?? '');
|
||||
if ($driver === '') {
|
||||
throw new \RuntimeException('DB config missing "driver"');
|
||||
}
|
||||
|
||||
$dsn = match ($driver) {
|
||||
'mysql' => self::buildMysqlDsn($db),
|
||||
'pgsql' => self::buildPgsqlDsn($db),
|
||||
'sqlite' => self::buildSqliteDsn($db),
|
||||
default => throw new \RuntimeException('Unsupported PDO driver: ' . $driver),
|
||||
};
|
||||
|
||||
$pdo = new \PDO(
|
||||
$dsn,
|
||||
(string)($db['user'] ?? ''),
|
||||
(string)($db['password'] ?? ''),
|
||||
(array)($db['options'] ?? [])
|
||||
);
|
||||
|
||||
if ($driver === 'pgsql' && !empty($db['schema'])) {
|
||||
$schema = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$db['schema']);
|
||||
if ($schema !== '') {
|
||||
$pdo->exec('SET search_path TO ' . $schema);
|
||||
}
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
public static function ensureKeaSchema(\PDO $pdo, array $options): void
|
||||
{
|
||||
$driver = (string)$pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
|
||||
if ($driver !== 'pgsql') {
|
||||
@@ -71,8 +94,8 @@ final class Database
|
||||
}
|
||||
|
||||
if (!self::tableExists($pdo, 'hosts')) {
|
||||
if ($config->dbAutoInit) {
|
||||
self::initKeaSchema($pdo, $config);
|
||||
if (!empty($options['auto_init'])) {
|
||||
self::initKeaSchema($pdo, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,15 +118,20 @@ final class Database
|
||||
return (bool)$stmt->fetchColumn();
|
||||
}
|
||||
|
||||
private static function initKeaSchema(\PDO $pdo, Config $config): void
|
||||
private static function initKeaSchema(\PDO $pdo, array $options): void
|
||||
{
|
||||
if ($config->dbInitCmd) {
|
||||
self::runInitCommand($config->dbInitCmd);
|
||||
if (!empty($options['init_cmd'])) {
|
||||
self::runInitCommand((string)$options['init_cmd']);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($config->dbInitScript) {
|
||||
self::execSqlFile($pdo, $config->dbInitScript);
|
||||
$script = $options['init_script'] ?? null;
|
||||
if (!$script && !empty($options['kea_db_version'])) {
|
||||
$script = __DIR__ . '/../../tools/sql/kea/' . $options['kea_db_version'] . '/dhcpdb_create.pgsql';
|
||||
}
|
||||
|
||||
if ($script) {
|
||||
self::execSqlFile($pdo, (string)$script);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
247
src/App/ModuleManager.php
Normal file
247
src/App/ModuleManager.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
final class ModuleManager
|
||||
{
|
||||
private array $modules = [];
|
||||
private array $callbacks = [];
|
||||
|
||||
public function __construct(
|
||||
private ?\PDO $basePdo,
|
||||
private string $modulesPath
|
||||
) {
|
||||
if ($this->basePdo) {
|
||||
BaseSchema::ensure($this->basePdo);
|
||||
}
|
||||
$this->scanModules();
|
||||
}
|
||||
|
||||
public function all(): array
|
||||
{
|
||||
return $this->modules;
|
||||
}
|
||||
|
||||
public function get(string $name): ?array
|
||||
{
|
||||
return $this->modules[$name] ?? null;
|
||||
}
|
||||
|
||||
public function isEnabled(string $name): bool
|
||||
{
|
||||
$module = $this->get($name);
|
||||
return (bool)($module['enabled'] ?? false);
|
||||
}
|
||||
|
||||
public function setEnabled(string $name, bool $enabled): void
|
||||
{
|
||||
if (!$this->basePdo) {
|
||||
return;
|
||||
}
|
||||
|
||||
$module = $this->get($name);
|
||||
if (!$module) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = $this->basePdo->prepare(
|
||||
"INSERT INTO nexus_modules (name, title, version, enabled, installed_at, updated_at)
|
||||
VALUES (:name, :title, :version, :enabled, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(name) DO UPDATE SET
|
||||
enabled = excluded.enabled,
|
||||
title = excluded.title,
|
||||
version = excluded.version,
|
||||
updated_at = CURRENT_TIMESTAMP"
|
||||
);
|
||||
|
||||
$stmt->execute([
|
||||
'name' => $name,
|
||||
'title' => (string)($module['title'] ?? $name),
|
||||
'version' => (string)($module['version'] ?? ''),
|
||||
'enabled' => $enabled ? 1 : 0,
|
||||
]);
|
||||
|
||||
$this->modules[$name]['enabled'] = $enabled;
|
||||
}
|
||||
|
||||
public function settings(string $name): array
|
||||
{
|
||||
if (!$this->basePdo) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$stmt = $this->basePdo->prepare(
|
||||
"SELECT settings FROM nexus_module_settings WHERE name = :name LIMIT 1"
|
||||
);
|
||||
$stmt->execute(['name' => $name]);
|
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
if (!$row || empty($row['settings'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = json_decode((string)$row['settings'], true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
public function saveSettings(string $name, array $settings): void
|
||||
{
|
||||
if (!$this->basePdo) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = json_encode($settings, JSON_UNESCAPED_UNICODE);
|
||||
if ($payload === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = $this->basePdo->prepare(
|
||||
"INSERT INTO nexus_module_settings (name, settings, updated_at)
|
||||
VALUES (:name, :settings, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(name) DO UPDATE SET
|
||||
settings = excluded.settings,
|
||||
updated_at = CURRENT_TIMESTAMP"
|
||||
);
|
||||
$stmt->execute([
|
||||
'name' => $name,
|
||||
'settings' => $payload,
|
||||
]);
|
||||
}
|
||||
|
||||
public function modulePdo(string $name, array $fallback = []): ?\PDO
|
||||
{
|
||||
$settings = $this->settings($name);
|
||||
$db = $settings['db'] ?? $fallback;
|
||||
if (!is_array($db) || empty($db)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($db['options'])) {
|
||||
$db['options'] = [
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
|
||||
];
|
||||
}
|
||||
|
||||
$pdo = Database::createFromArray($db);
|
||||
|
||||
if ($name === 'kea' && !empty($settings['kea_auto_init'])) {
|
||||
Database::ensureKeaSchema($pdo, [
|
||||
'auto_init' => true,
|
||||
'init_cmd' => $settings['kea_init_cmd'] ?? null,
|
||||
'init_script' => $settings['kea_init_script'] ?? null,
|
||||
'kea_db_version' => $settings['kea_db_version'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
public function resolvePage(string $name, string $page): ?string
|
||||
{
|
||||
$module = $this->get($name);
|
||||
if (!$module) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $page)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = $module['path'] . '/pages/' . $page . '.php';
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function bootEnabled(): void
|
||||
{
|
||||
foreach ($this->modules as $name => $module) {
|
||||
if (!empty($module['enabled'])) {
|
||||
$bootstrap = $module['path'] . '/bootstrap.php';
|
||||
if (is_file($bootstrap)) {
|
||||
require_once $bootstrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function registerFunction(string $module, string $name, callable $fn): void
|
||||
{
|
||||
$key = $module . ':' . $name;
|
||||
$this->callbacks[$key] = $fn;
|
||||
}
|
||||
|
||||
public function call(string $module, string $name, mixed ...$args): mixed
|
||||
{
|
||||
$key = $module . ':' . $name;
|
||||
if (!isset($this->callbacks[$key])) {
|
||||
throw new \RuntimeException("Module callback not found: {$key}");
|
||||
}
|
||||
return ($this->callbacks[$key])(...$args);
|
||||
}
|
||||
|
||||
private function scanModules(): void
|
||||
{
|
||||
$this->modules = [];
|
||||
if (!is_dir($this->modulesPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (glob($this->modulesPath . '/*', GLOB_ONLYDIR) as $dir) {
|
||||
$name = basename($dir);
|
||||
$manifest = $dir . '/module.json';
|
||||
if (!is_file($manifest)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$raw = file_get_contents($manifest);
|
||||
$data = $raw ? json_decode($raw, true) : null;
|
||||
if (!is_array($data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$module = [
|
||||
'name' => $name,
|
||||
'title' => $data['title'] ?? $name,
|
||||
'version' => $data['version'] ?? '',
|
||||
'description' => $data['description'] ?? '',
|
||||
'setup' => $data['setup'] ?? [],
|
||||
'db_defaults' => $data['db_defaults'] ?? [],
|
||||
'path' => $dir,
|
||||
'enabled' => false,
|
||||
];
|
||||
|
||||
$module['enabled'] = $this->loadEnabledState($name, $module);
|
||||
$this->modules[$name] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
private function loadEnabledState(string $name, array $module): bool
|
||||
{
|
||||
if (!$this->basePdo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt = $this->basePdo->prepare(
|
||||
"SELECT enabled FROM nexus_modules WHERE name = :name LIMIT 1"
|
||||
);
|
||||
$stmt->execute(['name' => $name]);
|
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
if ($row !== false) {
|
||||
return (bool)$row['enabled'];
|
||||
}
|
||||
|
||||
$stmt = $this->basePdo->prepare(
|
||||
"INSERT INTO nexus_modules (name, title, version, enabled, installed_at, updated_at)
|
||||
VALUES (:name, :title, :version, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
);
|
||||
$stmt->execute([
|
||||
'name' => $name,
|
||||
'title' => (string)$module['title'],
|
||||
'version' => (string)$module['version'],
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,16 @@ function t(string $key, $default = '', array $vars = []): string
|
||||
return app()->i18n()->get($key, $default, $vars);
|
||||
}
|
||||
|
||||
function modules(): \App\ModuleManager
|
||||
{
|
||||
return app()->modules();
|
||||
}
|
||||
|
||||
function module_fn(string $module, string $name, mixed ...$args): mixed
|
||||
{
|
||||
return modules()->call($module, $name, ...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt ein Template-Partial.
|
||||
*
|
||||
@@ -56,6 +66,24 @@ function tpl(string $name, string $folder = 'landing', array $data = []): void
|
||||
require $path;
|
||||
}
|
||||
|
||||
function module_tpl(string $module, string $name, array $data = []): void
|
||||
{
|
||||
$base = __DIR__ . '/../../modules/' . $module . '/partials/';
|
||||
foreach ([$module, $name] as $value) {
|
||||
if (preg_match('/[^a-zA-Z0-9_\-]/', $value)) {
|
||||
echo "<!-- module_tpl(): invalid parameter -->";
|
||||
return;
|
||||
}
|
||||
}
|
||||
$path = $base . $name . '.php';
|
||||
if (file_exists($path)) {
|
||||
extract($data);
|
||||
require $path;
|
||||
} else {
|
||||
echo "<!-- module_tpl(): not found: {$module}/{$name} -->";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML Escaping Helper.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user