Framework DotApp Aktualisiert: 2026-08-19
Über den Autor
Mein Name ist Štefan Miščík und ich bin Senior-Fullstack-Webentwickler bei Dotsystems s.r.o. (WEB)
Designziele
DotApp ist ein PHP-Framework für Anwendungen jeder Größe. Die Anwendungslogik liegt in Modulen. Jedes Modul besitzt seine eigenen Routen, Controller, Middleware, Views und Assets.
Die Arbeit an DotApp begann 2014 als vollständige Anwendungsarchitektur: Routing, Rendering, Sicherheit und die Datenbankschicht teilen sich eine Laufzeitumgebung und ein gemeinsames Regelwerk.
Konventionen
Die öffentliche API verwendet Fassaden, Modul-Controller und eine kleine Menge an Konventionen:
Fassaden
Fassaden (Router, Route, DB, Request, Renderer::new()) sind die öffentliche API für Kerndienste. Anwendungsrouten werden in der module.init.php jedes Moduls registriert.
Router- und Route-Fassaden
Verwenden Sie die Fassaden Router und Route (sie sind Aliase voneinander) in module.init.php. Beispiel: Router::get('/helloworld', 'HelloWorld:Home@index!', Router::STATIC_ROUTE).
// app/modules/HelloWorld/module.init.php → initialize($dotApp)
Router::get('/helloworld', fn() => 'Hello World', Router::STATIC_ROUTE);
Route::get('/helloworld', fn() => 'Hello World', Router::STATIC_ROUTE);
Router::get('/helloworld', 'HelloWorld:Home@index!', Router::STATIC_ROUTE);
Route::get('/helloworld', 'HelloWorld:Home@index!', Router::STATIC_ROUTE);
DB-Fassade
Verwenden Sie die DB-Fassade. Abfragen erfolgen mit DB::module('RAW').
DB::module('RAW')->q(function ($qb) {
$qb->select(['id', 'title'])->from('helloworld_notes')->where('id', '=', 1);
})->all();
Request-Fassade
In Controllern lesen Sie die aktuelle Anfrage aus dem Argument $request. Die Request-Fassade steht zur Verfügung, wenn Sie sich außerhalb eines Controller-Callbacks befinden.
Request::getPath(); // Get the current request path
Request::getMethod(); // Get the HTTP method (e.g., GET, POST)
Request::data(); // Access request data (e.g., POST or JSON payload)
$request->form(['POST'], 'myForm', function ($request) {
return 'Form submitted!';
}, function () {
return 'Invalid form';
});
Die DotApp-Instanz
Routing, Datenbank, Rendering, Konfiguration und Sitzungsspeicher verwenden Fassaden: Router::, DB::, Renderer::new(), Config::, DSM::use(). Wenn Sie den Kernel selbst benötigen (Ereignisse, unprotect, ajaxReply, call), holen Sie ihn mit:
use \Dotsystems\App\DotApp;
$dotApp = DotApp::DotApp();
Registrieren Sie Routen mit Router::get (und den übrigen Verb-Methoden) innerhalb der Methode initialize($dotApp) des Moduls.
Wichtige Funktionen von DotApp
Einfachheit ohne Kompromisse
DotApp verbindet intuitives Design mit hoher Leistung. Sie benötigen keine komplexen Setups oder übermäßige Konfiguration – definieren Sie einfach Routen und Module, und alles andere organisiert sich selbst. Routen werden nur dort verarbeitet, wo sie benötigt werden, und es sind keine zusätzlichen Schritte erforderlich, um die Leistung zu halten – alles läuft automatisch und effizient.
// Example of simplicity when working with the DotApp framework
namespace Dotsystems\App\Modules\HelloWorld\Controllers;
class TestController1 extends \Dotsystems\App\Parts\Controller {
public static function testMiddlewareFn($request) {
return "Hello " . $request->body(); // Adds text at the beginning
}
public static function mainFn($request) {
return $request->body() . "World"; // Adds text at the end
}
}
// Simple controller call
// app/modules/HelloWorld/module.init.php → initialize($dotApp)
Router::get("/home", "HelloWorld:TestController1@mainFn!", Router::STATIC_ROUTE)
->before("HelloWorld:TestController1@testMiddlewareFn!");
// Result for /home: "Hello World"
Fokus auf geringen Ressourcenverbrauch
DotApp hält den Speicherbedarf auf einem Minimum – statt massive Routenstrukturen und Konfigurationen zu laden, verarbeitet es nur, was gerade benötigt wird. Das bedeutet schnelleren Start und gute Leistung auch auf schwächeren Servern.
Schnelle Routenverarbeitung
DotApp filtert intelligent nur relevante Module und deren Routen und vermeidet unnötige Suchvorgänge. Das Ergebnis ist schnelles Laden selbst bei Tausenden von Routen.
Beispiel
Demonstration der Routing-Geschwindigkeit: Vor der Anzeige dieser Seite wurden automatisch 1000 eindeutige statische und 1000 eindeutige dynamische, absichtlich unsortierte Routen zufällig zum Router hinzugefügt. Ziel war es, das schnelle Laden trotz 2000 zusätzlicher, unnötiger Routen zu zeigen. Keine davon passt zur aktuellen URL, sodass alle den Matching-Prozess des Routers durchlaufen müssen.
$p = rtrim((string) Config::module('Docs', 'prefix'), '/') ?: '/documentation';
for ($i = 0; $i < 1000; $i++) {
$path = $p . '/_routa' . $i;
Router::any($path, function () use ($path) {
return "This is route: " . $path;
}, Router::STATIC_ROUTE);
}
for ($i = 0; $i < 1000; $i++) {
$path = $p . '/_routa' . $i . '(?:/{language})?';
Router::any($path, function () use ($path) {
return "This is route: " . $path;
});
}
// Try it out: /documentation/_routa7
Die Anzeige der Seite inklusive Routenerstellung, Routing und Codegenerierung über das Vorlagensystem dauerte:
Script execution time: 0.033089 s
Memory used by the script: 1023.03 KB
Peak memory usage: 1.55 MB
Loaded modules: 6
Modulare Effizienz mit bidirektionaler Verbindung
DotApp verarbeitet nur die Routen des aktiven Moduls und spart so Ressourcen. Module können einander laden: Der Listener eines Moduls kann ein anderes laden, und ein übergeordnetes Modul kann Kindmodule aktivieren. Kombinationen bleiben in module.listeners.php und initializeRoutes() explizit.
Kaskadierendes Laden von Modulen
Wenn ein Modul von einem anderen abhängt (z. B. BBB benötigt XXX), lädt DotApp XXX automatisch, bevor BBB abgeschlossen wird. Das gewährleistet Zuverlässigkeit – keine Fehler durch fehlende Abhängigkeiten – und hält das System schlank, indem nur das Nötige geladen wird.
Dynamische Abhängigkeitsverwaltung über Trigger und Listener
Jedes Modul hat Trigger wie init.start, loading, loaded und weitere, auf die Listener reagieren. Zum Beispiel kann der Listener dotapp.module.Module1.loading das Laden von Modul 2 auslösen, wenn Modul 1 aktiv ist. Die Funktion load() stellt sicher, dass ein Modul nur einmal geladen wird, unabhängig davon, ob kaskadierend (von oben nach unten) oder bidirektional (von unten nach oben).
Hinweis: Triggernamen sind unabhängig von Groß- und Kleinschreibung, daher sind dotapp.module.Module1.loading und Dotapp.Module.Module1.Loading gleichwertig. Für Konsistenz empfehlen wir jedoch das Format dotapp.module.ClassName.eventName.
use Dotsystems\App\DotApp;
use Dotsystems\App\Parts\Events;
Events::on("dotapp.module.Shop.loading", function () {
DotApp::DotApp()->module("Cart")->load();
});
Automatische Auflösung von Abhängigkeiten und DI
Module und ihre Abhängigkeiten werden automatisch geladen – definieren Sie die Logik einfach in initializeCondition() oder in Listenern. Dependency Injection (DI) ist einfach und effizient – Dienste werden registriert (z. B. singleton), und DotApp liefert sie dort, wo sie benötigt werden, ohne unnötigen Overhead.
Registrieren Sie Dienste in der initialize($dotApp) des Moduls mit singleton / bind. Controller sind public static und nehmen $request entgegen.
public function initialize($dotApp) {
$dotApp->singleton('cache', function () {
return new CacheService();
});
}
namespace Dotsystems\App\Modules\HelloWorld\Controllers;
class Home extends \Dotsystems\App\Parts\Controller {
public static function index($request) {
$cache = \Dotsystems\App\DotApp::DotApp()->resolve('cache');
return "Hello World";
}
}
Der erste Callback gewinnt
Für jede URL wird nur der erste passende Callback behalten – nachfolgende Registrierungsversuche werden ignoriert. Das steigert die Leistung und verhindert Konflikte.
Router::get('/documentation/test1', "HelloWorld:Home@index!");
Router::get('/documentation/test1', function () { return "Ignored"; });
// Only the first definition is used
Skalierbarkeit für kleine und große Projekte
DotApp eignet sich gleichermaßen für kleine Websites und komplexe Anwendungen – es behält niedrige Anforderungen und hohe Geschwindigkeit unabhängig vom Projektumfang bei. Große Module können in kleinere Teile aufgeteilt werden, die bei Bedarf rekursiv geladen werden.
Kein unnötiger Overhead
DotApp konzentriert sich auf das Wesentliche – schnelles Routing, minimaler Ressourcenverbrauch und einfache Nutzung. Es belastet Sie nicht mit Funktionen, die Sie nicht brauchen.
Vorlagensystem
Views und Layouts liegen im Modul. Geben Sie mit {{ var: $title }} aus, binden Sie Fragmente mit {{ layout:partials/header }} ein, und rendern Sie aus einem Controller mit Renderer::new()->module('HelloWorld')->setView('hello'). Vollständige Referenz: Vorlagensystem.
DotApp Bridge
Live-Verbindung – eine Brücke zwischen Frontend und Backend. Verwenden Sie einfach folgenden Code:
<button {{ dotbridge:on(click)="newsletter.subscribe(newsletter.email)" }}>Subscribe</button>
und auf der PHP-Seite in der initialize() des Moduls:
use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;
$urls = ['/newsletter', '/newsletter/'];
Bridge::listen($urls, "newsletter.subscribe", function ($request) {
$email = $request->data(true)['data']['newsletter.email'] ?? '';
return ['ok' => true, 'email' => $email];
}, Router::STATIC_ROUTE);
Die Schaltfläche wird automatisch mit der PHP-Funktion verknüpft; die Dokumentation stellt die vielfältigen Möglichkeiten vor.
Beispiel für generierten Code:
DotApp ist maßgeschneidert für Entwickler, die ein effizientes Werkzeug ohne Ballast wollen. Es bietet Geschwindigkeit, geringe Anforderungen und eine Einfachheit, die die Arbeit erleichtert. Es ist ein Framework, das beweist, dass weniger mehr sein kann – mit Ergebnissen, die für sich sprechen.
Probieren Sie DotApp aus und überzeugen Sie sich selbst!