Framework DotApp Aktualizované: 2026-08-27
O autorovi
Volám sa Štefan Miščík a som senior fullstack web vývojár v Dotsystems s.r.o. (WEB)
Ciele návrhu
DotApp nie je ďalší bežný PHP framework, akých sú stovky. Je napísaný od nuly, bez extra Composer závislostí a bez Laravel či Symfony stacku pod kapotou. Jadro je ultralahké a vysoko škálovateľné: smerovanie, vykresľovanie, bezpečnosť a databázová vrstva zdieľajú jedno runtime prostredie a jednu sadu konvencií.
Aplikačná logika žije v moduloch. Každý modul vlastní svoje trasy, kontroléry, middleware, views a assets — tím si tak vie rozdeliť prácu bez kolízií a AIRULES povedia AI agentovi tú istú zmluvu. Bezpečnosť je v runtime (chránené vstupy, fo-rm, šifrované identifikátory), nie ako pridaný balík.
Práce na DotApp sa začali v roku 2014 ako kompletná aplikačná architektúra, nie ako obal okolo cudzieho stromu závislostí.
Novinky
Aktualizácie jadra od DotApp 2.0. Staré moduly ostávajú funkčné. Prehľad podľa dátumu: What's new in DotApp PHP Framework.
URL {not:} — vylúčenie prefixov pred matchom (NEW – 26. 8. 2026)
Router má operátor {not:mask|mask}. Vylúčenia bežia pred pozitívnym vzorom (strpos / substr na prefixe s koncovým *). Verejný catch-all ostane jeden reťazec a predsa sa vyhne /admin, /api/v1 a /assets.
Router::get('/{path*}{not:/admin*|/api/v1*|/assets*}', 'Shop:Public@page!');
- Záleží na poradí:
/admin/loginproti/{path*}{not:/admin*}skončí na exclude, nie na{path*}. /admin*vs/admin/*:/admin/*nesedí na presné/admin. Keď musí vypadnúť aj index adminu, použite{not:/admin*}.- Rovnaká syntax na wake zoznamoch
Module::initializeRoutes()/Listeners::initializeRoutes(). Verejné/{path*}, ktoré/adminodreže až vinitializeCondition, modul aj tak zobudí —{not:}dajte na wake reťazec.
Docs: AIRULES/03-MODULES-AND-ROUTING.md (parametre cesty).
Návod: Ako fungujú URL selektory {not:}.
Triggery, Extender a samostatné routy listenerov (NEW – 22. 8. 2026)
Zbernica udalostí a načítavanie modulov sa rozšírili bez narušenia starých modulov. Zodpovedajúce listenere sa vždy zaregistrujú skôr, ako sa inicializujú zodpovedajúce moduly.
Events::triggerWithVeto()a nová triedaDotsystems\App\Parts\Veto— explicitné zastavenie pred vratnou akciou. Bežnýtrigger()naďalej ignoruje návraty listenerov, vrátane objektuVeto.Dotsystems\App\Parts\Extender— uvážená opt-in náhrada významného výstupu pre tento request. Vlastník použijeexists()/call(); bežný výsledok ho nahradí aisOriginal()pokračuje v pôvodnej logike iba pre jedinečný markeroriginal(). VListeners::register()sa iba prihláste nadotapp.module.shop.loading;extend()volajte v tom callbacku reťazcom ako'Loyalty:Pricing@quote!'.Listeners::initializeRoutes()— listener sa môže zobudiť na vlastných maskách URL bez spusteniainitialize()modulu. Ak metódu vynecháte, zdedí mapu modulu.php dotapper.php --optimize-moduleszapisuje formát optimalizátora v2 ($modules,$listeners,$modulesAutoLoaderVersion = 2). Súbor v1, ktorý exportuje len$modules, ostáva kompatibilný.dotapp.catchallstále beží ako prvý na každom inomtrigger()(aj natriggerWithVeto()), aby ste všetky udalosti videli na jednom mieste. Len debug — z catchall nepersistujte.
Návody: trigger with veto
· samostatné routy listenerov
· Extender
· dotapp.catchall.
Konvencie
Verejné API používa fasády, modulové kontroléry a malú sadu konvencií:
Fasády
Fasády (Router, Route, DB, Request, Renderer::new()) sú verejné API pre kľúčové služby. Aplikačné trasy sa registrujú v module.init.php každého modulu.
Fasády Router a Route
Použite fasády Router a Route (sú to vzájomné aliasy) v module.init.php. Príklad: 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);
Fasáda DB
Použite fasádu DB. Dopyty vykonávajte cez DB::module('RAW').
DB::module('RAW')->q(function ($qb) {
$qb->select(['id', 'title'])->from('helloworld_notes')->where('id', '=', 1);
})->all();
Fasáda Request
V kontroléroch čítajte aktuálnu požiadavku z argumentu $request. Fasáda Request je k dispozícii, keď ste mimo callbacku kontroléra.
Prichádzajúce hodnoty sú automaticky chránené. data() je escapovaná kópia (bezpečná na výpis). data(true) sú pôvodné hodnoty — heslá, dešifrovanie, persistencia.
Polia kanála: $request->data(true)['data'].
Request::getPath(); // Get the current request path
Request::getMethod(); // Get the HTTP method (e.g., GET, POST)
Request::data(); // protected/escaped copy — OK to print
Request::data(true); // original values — passwords, decrypt, compare
$request->form(['POST'], 'myForm', function ($request) {
return 'Form submitted!';
}, function () {
return 'Invalid form';
});
Inštancia DotApp
Uprednostnite fasády: Router::, DB::, Renderer::new(), Config::, Events::, Bridge::listen, DSM::use(). Keď potrebujete samotné jadro (DI bind/resolve, unprotect, ajaxReply, reaktívny polling), získajte ho takto:
use \Dotsystems\App\DotApp;
$dotApp = DotApp::DotApp();
Trasy registrujte pomocou Router::get (a ostatných metód HTTP slovies) v metóde initialize($dotApp) modulu.
Kľúčové vlastnosti DotApp
Jednoduchosť bez kompromisov
DotApp spája intuitívny návrh s vysokým výkonom. Nepotrebujete zložité nastavenia ani nadmerné konfigurácie – stačí definovať trasy a moduly a všetko ostatné sa spravuje samo. Trasy sa spracúvajú len tam, kde sú potrebné, a na zachovanie výkonu nie sú potrebné žiadne ďalšie kroky – všetko je automatické a efektívne.
// 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"
Dôraz na nízku spotrebu zdrojov
DotApp drží požiadavky na pamäť na minime – namiesto načítavania obrovských štruktúr trás a konfigurácií spracúva len to, čo je práve potrebné. To znamená rýchlejší štart a výborný výkon aj na slabších serveroch.
Rýchle spracovanie trás
DotApp inteligentne filtruje iba relevantné moduly a ich trasy, čím odstraňuje zbytočné vyhľadávanie. Výsledkom je rýchle načítanie aj pri tisícoch trás.
Príklad
Ukážka rýchlosti smerovania: Pred zobrazením tejto stránky sa do routera automaticky a náhodne pridalo 1000 jedinečných statických a 1000 jedinečných dynamických, zámerne neusporiadaných trás. Cieľom bolo ukázať rýchle načítanie napriek 2000 extra zbytočným trasám. Žiadna z nich nezodpovedá aktuálnej URL, takže všetky musia prejsť procesom párovania v routeri.
$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
Zobrazenie stránky vrátane vytvorenia trás, smerovania a generovania kódu šablónovým systémom trvalo:
Script execution time: 0.065923 s
Memory used by the script: 1.05 MB
Peak memory usage: 1.66 MB
Loaded modules: 6
Modulárna efektivita s obojsmerným prepojením
DotApp spracúva iba trasy aktívneho modulu, čím šetrí zdroje. Moduly sa môžu navzájom načítavať: listener jedného modulu môže načítať iný a nadradený modul môže aktivovať podmoduly. Kombinácie zostávajú explicitné v module.listeners.php a initializeRoutes(). Listener môže mať vlastné masky, takže sa zobudí bez spustenia initialize() modulu.
Kaskádové načítanie modulov
Ak modul závisí od iného (napr. BBB potrebuje XXX), DotApp automaticky načíta XXX pred dokončením BBB. To zaisťuje spoľahlivosť – žiadne chyby v dôsledku chýbajúcich závislostí – a systém zostáva ľahký, pretože sa načítava len to, čo je potrebné.
Dynamická správa závislostí cez triggery a listenere
Každý modul má triggery ako init.start, loading, loaded a ďalšie, na ktoré listenere reagujú. Napríklad listener dotapp.module.Module1.loading môže spustiť načítanie modulu 2, ak je modul 1 aktívny. Funkcia load() zaisťuje, že sa modul načíta iba raz, či už kaskádovo (zhora nadol) alebo obojsmerne (zdola nahor).
Poznámka: Názvy triggerov nerozlišujú veľkosť písmen, takže dotapp.module.Module1.loading a Dotapp.Module.Module1.Loading sú ekvivalentné, ale pre konzistenciu odporúčame formát dotapp.module.ClassName.eventName.
Každý Events::trigger() aj Events::triggerWithVeto() okrem samotného dotapp.catchall najprv spustí túto debug udalosť, aby ste všetky triggery videli na jednom mieste.
Použite ju len na ladenie. Výnimka v catchall listeneri preskočí pomenovanú udalosť.
Kontrakt a ukážka: Events and listeners — dotapp.catchall.
Zastavenie pred akciou: trigger with veto (trieda Veto).
Listenere môžu mať vlastné routy: samostatné routy listenerov.
use Dotsystems\App\DotApp;
use Dotsystems\App\Parts\Events;
Events::on("dotapp.module.shop.loading", function () {
DotApp::DotApp()->module("Cart")->load();
});
Automatické riešenie závislostí a DI
Moduly a ich závislosti sa načítavajú automaticky – stačí definovať logiku v initializeCondition() alebo v listeneroch. Dependency Injection (DI) je jednoduchá a efektívna – služby sa registrujú (napr. singleton) a DotApp ich dodá tam, kde sú potrebné, bez zbytočnej réžie.
Služby registrujte v initialize($dotApp) modulu pomocou singleton / bind. Kontroléry sú public static a prijímajú $request.
public function initialize($dotApp) {
\Dotsystems\App\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";
}
}
Prvý callback vyhráva
Pre každú URL sa zachová iba prvý zodpovedajúci callback – následné pokusy o registráciu sa ignorujú, čo zvyšuje výkon a predchádza konfliktom.
Router::get('/documentation/test1', "HelloWorld:Home@index!");
Router::get('/documentation/test1', function () { return "Ignored"; });
// Only the first definition is used
Škálovateľnosť pre malé aj veľké projekty
DotApp je ideálny pre malé weby aj komplexné aplikácie – nízke nároky a vysokú rýchlosť si zachováva bez ohľadu na rozsah projektu. Veľké moduly môžete rozdeliť na menšie časti, ktoré sa podľa potreby načítavajú rekurzívne.
Žiadna zbytočná réžia
DotApp sa sústreďuje na podstatu – rýchle smerovanie, minimálne využitie zdrojov a jednoduchosť použitia. Nezaťažuje vás funkciami, ktoré nepotrebujete.
Šablónový systém
Views a layouts žijú v module. Hodnoty vypisujte pomocou {{ var: $title }}, fragmenty vkladajte cez {{ layout:partials/header }} a z kontroléra vykresľujte cez Renderer::new()->module('HelloWorld')->setView('hello'). Úplná referencia: Šablónový systém.
DotApp Bridge
Živé prepojenie – most medzi frontendom a backendom. Stačí použiť jednoduchý kód:
<button {{ dotbridge:on(click)="newsletter.subscribe(newsletter.email)" }}>Subscribe</button>
a na strane PHP v initialize() modulu:
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);
Tlačidlo sa automaticky prepojí s PHP funkciou; bohaté možnosti budú predstavené v dokumentácii.
Príklad vygenerovaného kódu:
DotApp je šitý na mieru vývojárom, ktorí chcú efektívny nástroj bez zbytočností. Ponúka rýchlosť, nízke nároky a jednoduchosť, ktorá uľahčuje prácu. Je to framework, ktorý dokazuje, že menej môže byť viac – s výsledkami, ktoré hovoria samy za seba.
Vyskúšajte DotApp a presvedčte sa sami!