Empfohlene Praktiken
Dieser Abschnitt beschreibt die empfohlenen Praktiken für die Entwicklung von Modulen und Anwendungen mit dem DotApp PHP Framework. Wenn Sie diese Praktiken einhalten, bleiben Ihre Module portabel, über Anwendungen hinweg teilbar und anpassbar an jede Serverkonfiguration, einschließlich unterschiedlicher Sitzungstreiber (z. B. Redis, dateibasiert, Datenbank) und Datenbanktreiber (PDO, MySQLi). Das Befolgen der Framework-Philosophie garantiert konsistente Ergebnisse unabhängig von den zugrunde liegenden Treibern.
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. Standardmäßig sind alle Eingaben automatisch gegen gängige Schwachstellen wie Cross-Site Scripting (XSS) geschützt. Dieses Design hält die Anwendung sicher, selbst wenn eine einzelne Eingabe vergessen wird. Um den ursprünglichen, ungeschützten Wert zu erhalten — etwa beim Speichern von HTML — verwenden Sie DotApp::DotApp()->unprotect($variable). Die Methode akzeptiert eine Zeichenkette oder ein Array per Referenz und entfernt den Schutz rekursiv. Zum Beispiel:
use \Dotsystems\App\DotApp;
$variable = $_POST['variable'];
DotApp::DotApp()->unprotect($variable); // $variable now contains the original, unprotected value
Beachten Sie, dass unprotect die Variable per Referenz ändert. Rufen Sie sie daher als DotApp::DotApp()->unprotect($variable) auf, ohne das Ergebnis neu zuzuweisen (also vermeiden Sie $variable = DotApp::DotApp()->unprotect($variable)). Dieser Ansatz unterstreicht die DotApp-Philosophie: Entwickler müssen Variablen nicht manuell schützen, da sie standardmäßig sicher sind, können ungeschützte Werte aber gezielt abrufen, wenn das ausdrücklich nötig ist.
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);
In initialize($dotApp) ist der Kern das Methodenargument. Registrieren Sie Dienste mit $dotApp->bind / singleton / resolve. Controller verwenden DotApp::DotApp() oder Fassaden.
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) {
$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.