Empfohlene Praktiken
Dieser Abschnitt beschreibt die empfohlenen Praktiken für die Entwicklung von Modulen und Anwendungen mit dem DotApp PHP Framework. Der Kernel ist von Grund auf geschrieben — ultraleicht, hoch skalierbar, ohne extra Composer-Abhängigkeiten — damit diese Konventionen Teams und KI-Agenten auf denselben sicheren, portablen Modulen halten. Wenn Sie diese Praktiken einhalten, bleiben Ihre Module über Anwendungen hinweg teilbar und anpassbar an jede Serverkonfiguration, einschließlich unterschiedlicher Sitzungstreiber (z. B. Redis, dateibasiert, Datenbank) und Datenbanktreiber (PDO, MySQLi).
Philosophie im Überblick
Das DotApp-Framework ist darauf ausgelegt, portable und wartbare Module zu schaffen, die in unterschiedlichen Umgebungen reibungslos funktionieren. Mit diesen Praktiken passen sich Ihre Module dem Sitzungstreiber des Anwenders (z. B. Redis, Datenbank) und dem Datenbanktreiber (PDO, MySQLi) an, ohne dass Codeänderungen nötig sind. So bleibt Ihre Anwendung flexibel und teilbar — im Einklang mit der Kernphilosophie von DotApp: Modularität und Anpassungsfähigkeit.
Ein zentraler Aspekt der DotApp-Philosophie ist die Eingabesicherheit. Eingehende GET/POST-Werte werden automatisch geschützt (escapet), damit ein vergessener Sanitizer keine XSS-/Injection-Ära-Lücke öffnet.
$request->data() ist diese geschützte Kopie — sicher zum Ausgeben.
$request->data(true) ist das Original-Array; nach dem Channel-Unwrap liegen Felder in $request->data(true)['data'].
Originaldaten verwenden Sie für Passwörter, Entschlüsselung, Hashes und jeden Vergleich.
DotApp::DotApp()->unprotect($variable) gibt es weiterhin für einen Wert, den Sie bereits halten (Zeichenkette oder Array, per Referenz, rekursiv). Bevorzugen Sie data(true) am Request.
$safe = $request->data(); // protected — OK to print
$raw = $request->data(true); // original values
$password = $raw['data']['password'] ?? '';
// Legacy: a value you already hold (by reference — do not reassign)
DotApp::DotApp()->unprotect($variable);
Rufen Sie unprotect als DotApp::DotApp()->unprotect($variable) auf, ohne den Rückgabewert zuzuweisen (vermeiden Sie $variable = DotApp::DotApp()->unprotect($variable)).
Entwickler müssen Variablen nicht manuell schützen — sie sind standardmäßig sicher — müssen die Originalform aber ausdrücklich anfordern.
Zugriff auf die DotApp-Instanz
Der DotApp-Kern ist als DotApp::DotApp() verfügbar. Verwenden Sie ihn für unprotect, ajaxReply und call. Routing, Abfragen, Views, Konfiguration und Sitzungen nutzen Fassaden.
use Dotsystems\App\DotApp;
DotApp::DotApp()->unprotect($htmlFromEditor);
DotApp::DotApp()->ajaxReply(['status' => 1], 200);
DotApp::call('HelloWorld:Home@index!', $request);
initialize($dotApp) ist die erforderliche Signatur. Darin registrieren Sie Dienste mit DotApp::DotApp()->bind / singleton / resolve (nicht die kaputte Injector-Fassade). Überall sonst Fassaden bevorzugen.
Fassaden verwenden
Fassaden sind die öffentliche API für Kerndienste.
Zum Beispiel:
Renderer::new()->module(self::moduleName())->setView("dotapper-cli.eng")->setViewVar("variables", $viewVars)->renderView();
Die Fassade Renderer hält den Code knapp. Eigene Renderer:
Renderer::add("Docs.code.replace", function($code) { /* logic */ });
Häufige Fassaden
Renderer::new(): Gibt ein zurücksetzbares Renderer-Objekt zurück.Renderer::add(): Fügt einen eigenen Renderer hinzu.Router::get(): Definiert eine GET-Route, z. B.Router::get(['/helloworld', '/helloworld/'], "HelloWorld:Home@index!", Router::STATIC_ROUTE);.
Fassaden verbessern die Lesbarkeit und passen zur DotApp-Philosophie von klarem, wartbarem Code.
Dependency Injection
Registrieren Sie eigene Dienste in initialize($dotApp):
public function initialize($dotApp) {
\Dotsystems\App\DotApp::DotApp()->singleton('cache', function () {
return new CacheService();
});
}
Controller rendern mit Renderer::new():
public static function index($request) {
return Renderer::new()->module('HelloWorld')->setView('hello')->renderView();
}
Datenbankpraktiken
Damit Ihre Module portabel und treiberunabhängig bleiben, verlangt die DotApp-Philosophie den Zugriff auf die Datenbank über die Fassade DB::module(). Diese Fassade wählt anhand der Konfiguration automatisch den konfigurierten Treiber und die Datenbank und sorgt so für Konsistenz in der gesamten Anwendung.
DB::module() verwenden
Verwenden Sie DB::module("ORM") oder DB::module("RAW") für Datenbankabfragen:
DB::module("RAW")->q(function ($qb) use ($token) {
$qb
->select('user_id', Config::get("db","prefix").'users_rmtokens')
->where('token', '=', $token);
})->execute(
function ($result) {
// $result is an array of rows in RAW mode
},
function ($error) {
\Dotsystems\App\Parts\Logger::use()->error('query failed', ['msg' => is_object($error) ? $error->getMessage() : (string) $error]);
}
);
Callbacks verwenden
Übergeben Sie execute() stets Erfolgs- und Fehler-Callbacks. Der Erfolgs-Callback erhält im RAW-Modus ein Array von Zeilen.
- Erfolgs-Callback:
function($result, $db, $debug)—$resultist im RAW-Modus ein Array von Zeilen. - Fehler-Callback:
function($error, $db, $debug)— erforderlich, damit Fehlschläge behandelt werden.
DB::module("RAW")->q(function ($qb) use ($token) {
$qb
->select('user_id', Config::get("db","prefix").'users_rmtokens')
->where('token', '=', $token);
})->execute(
function ($result, $db, $debug) use (&$data) {
if ($result === null || $result === []) {
$data = [];
setcookie('dotapp_'.Config::get("app","name_hash"), "", [
'expires' => time() - 3600,
'path' => Config::session("path"),
]);
} else {
$db->q(function ($qb) use (&$data, $result) {
$qb
->select(['username', 'password'], Config::get("db","prefix").'users')
->where('id', '=', $result['user_id']);
})->execute(function ($result, $db, $debug) use (&$data) {
$data['username'] = $result[0]['username'];
$data['passwordHash'] = $result[0]['password'];
$data['stage'] = 0;
\Dotsystems\App\Parts\Auth::login($data, true);
}, function ($error, $db, $debug) {
// Handle error, e.g., log or display error message
$data['error'] = $error->getMessage();
});
}
},
function ($error, $db, $debug) {
// Handle initial query error
error_log("Database error: " . $error->getMessage());
}
);
In diesem Beispiel:
- Der
success-Callback verarbeitet das Array$result, das treiberunabhängig ist (z. B.$result[0]['user_id']). - Die verschachtelte Abfrage verwendet ein weiteres
executemit eigenensuccess- underror-Callbacks, um Ergebnisse oder Fehler zu behandeln. - Der
error-Callback protokolliert oder behandelt Datenbankfehler und verhindert so ungefangene Exceptions.
Führen Callbacks zu komplexem Code (Callback-Hölle), können Sie Ergebnisse in einer Variable speichern, um die Logik zu vereinfachen:
$dbreturn = null;
DB::module("RAW")->q(function ($qb) use ($token) {
$qb
->select('user_id', Config::get("db","prefix").'users_rmtokens')
->where('token', '=', $token);
})->execute(
function ($result, $db, $debug) use (&$dbreturn) {
$dbreturn = $result;
},
function ($error, $db, $debug) {
error_log("Database error: " . $error->getMessage());
}
);
// Continue logic with $dbreturn
Wichtig: Vermeiden Sie die Rückgabe roher Treiberobjekte (z. B. $returnDB = DB::module("RAW")->q(...)->execute()), da diese treiberspezifisch sind (MySQLi oder PDO). Callbacks stellen sicher, dass Ihr Modul mit jedem Treiber funktioniert — im Einklang mit der DotApp-Philosophie.
Sitzungsverwaltung mit DSM
Der DotApp Session Manager (DSM) ist eine erforderliche Komponente für die Sitzungsverwaltung und ersetzt die direkte Nutzung von $_SESSION. DSM abstrahiert den zugrunde liegenden Sitzungstreiber (z. B. Standard, Datei, Datenbank, Redis), sodass Ihre Anwendung oder Ihr Modul in unterschiedlichen Umgebungen portabel bleibt.
DSM verwenden
Importieren und verwenden Sie DSM wie folgt:
use \Dotsystems\App\Parts\DSM;
$dsm = new DSM("MyModuleStorage");
$dsm->load();
$dsm->set('variable1', "hello");
Alternativ verwenden Sie die DSM-Fassade für klareren Code (empfohlen):
DSM::use("MyModuleStorage")->set('variable1', "hello");
echo DSM::use("MyModuleStorage")->get('variable1'); // Outputs: hello
Jedes Modul sollte einen eigenen Speicher anlegen (z. B. MyModuleStorage), um Konflikte mit anderen Modulen zu vermeiden. Variablen in unterschiedlichen Speichern können denselben Namen tragen, ohne sich zu überschneiden.
Wichtige DSM-Methoden
set($name, $value): Setzt eine Sitzungsvariable.get($name): Liest eine Sitzungsvariable.delete($name): Entfernt eine Sitzungsvariable.clear(): Löscht alle Variablen im Speicher.start(): Wird automatisch im Konstruktor aufgerufen.destroy(): Zerstört den Speicher (optional).session_id(): Gibt die Sitzungs-ID zurück.load(): Lädt die Sitzung (mit der Fassade nicht nötig).save(): Speichert die Sitzung (automatisch bei der Zerstörung).
Die am häufigsten verwendeten Methoden sind:
DSM::use("MyModuleStorage")->set('variable1', "hello");
DSM::use("MyModuleStorage")->get('variable1');
DSM::use("MyModuleStorage")->delete('variable1');
DSM::use("MyModuleStorage")->clear();
Warum DSM? DSM statt $_SESSION stellt sicher, dass Ihr Modul unabhängig vom Sitzungstreiber bleibt. Der Fassadenansatz erspart manuelle load()-Aufrufe und macht den Code klarer und wartbarer.
Beispiele ansehen
Praktische Beispiele zu diesen empfohlenen Praktiken, einschließlich Datenbankabfragen mit DB::module() und Sitzungsverwaltung mit DSM, finden Sie im Abschnitt Beispiele. Diese Beispiele zeigen, wie Sie die Praktiken in realen Szenarien anwenden.