Volám sa Štefan Miščík a som senior fullstack web developer v spoločnosti Dotsystems s.r.o. (WEB)
Prečo som vyvinul DotApp?
1. Chcel som si zjednodušiť prácu.
Väčšina frameworkov ma nútila ísť kamiónom aj pre nákup špagiet. Preto som vytvoril DotApp – je škálovateľný a dokáže byť nákupnou taškou, vozíkom aj kamiónom, plne automaticky podľa veľkosti nákupu. DotApp je framework navrhnutý na zjednodušenie vývoja webových aplikácií – rýchly, efektívny a bez zbytočností. Ponúka schopnosti, ktoré ho robia ideálnym pre projekty všetkých veľkostí.
2. Chcel som otestovať svoje schopnosti.
Písal sa rok 2014, a ja som chcel vedieť, ako na tom vedomostne som. Používanie existujúcich frameworkov je pohodlné, no lákala ma výzva vytvoriť niečo vlastné. Nechcel som skončiť pri priemernom riešení, ale vybudovať framework, ktorý by obstál aj v náročných podmienkach. DotApp tak pre mňa predstavoval príležitosť posunúť svoje zručnosti na vyššiu úroveň a presvedčiť sa, čoho som schopný.
Kľúčové vlastnosti DotApp
Jednoduchosť bez kompromisov
DotApp kombinuje intuitívny dizajn s vysokým výkonom. Nepotrebujete zložité nastavenia ani prehnané konfigurácie – stačí definovať routy a moduly, a všetko ostatné sa spravuje samo. Routy sa spracovávajú iba tam, kde je to potrebné, a nepotrebujete žiadne dodatočné kroky na udržanie výkonu – všetko je automatické a efektívne.
// Ukážka jednoduchosti práce s DotApp frameworkom
namespace Dotsystems\App\Modules\DotAppDoc\Controllers;
class TestController1 {
public static function testMiddlewareFn($request) {
return "Ahoj " . $request->body(); // Pridá text na začiatok
}
public static function mainFn($request) {
return $request->body() . "Svet"; // Pridá text na koniec
}
}
// Jednoduché zavolanie controllera
$dotApp->router
->get("/home", "dotappdoc:TestController1@mainFn")
->before("dotappdoc:TestController1@testMiddlewareFn");
// Výsledok pre /home: "Ahoj Svet"
Zameranie na nízku spotrebu výpočtových zdrojov
DotApp udržuje pamäťové nároky na minime – namiesto načítania obrovských štruktúr routov a konfigurácií spracováva iba to, čo je aktuálne potrebné. To znamená rýchlejší štart a skvelý výkon aj na slabších serveroch.
Rýchle spracovanie routovania
DotApp inteligentne filtruje iba relevantné moduly a ich routy, čím eliminuje zbytočné prehľadávanie. Výsledkom je svižné načítanie aj pri tisícoch routách.
Ukážka
Demonštrácia rýchlosti routovania: Pred zobrazením tejto stránky bolo automaticky náhodne pridaných 1000 jedinečných statických a 1000 jedinečných dynamických a zámerne neorganizovaných routov do routera. Cieľom bolo ukázať svižné načítanie aj napriek 2000 zbytočným routam navyše. Žiadna z nich nezodpovedá aktuálnej URL adrese, čím je zabezpečené, že všetky musia prejsť procesom párovania v routeri.
for ($i = 0; $i < 1000; $i++) {
$this->dotApp->router->any($this->getData("base_url") . "_routa" . $i, function () use ($dotApp, $i) {
$dotApp->unprotect($_POST);
echo "Toto je routa: " . $this->getData("base_url") . "_routa" . $i;
}, true);
}
for ($i = 0; $i < 1000; $i++) {
$this->dotApp->router->any($this->getData("base_url") . "_routa" . $i . "(?:/{language})?", function () use ($dotApp, $i) {
$dotApp->unprotect($_POST);
echo "Toto je routa: " . $this->getData("base_url") . "_routa" . $i . "(?:/{language})?";
});
}
// Skúste si to: /documentation/_routa7
$this->dotApp->router->get($this->getData("base_url") . "intro", function () use ($dotApp) {
/*
Pre info:
$this->moduleName - premenná automaticky nachádzajúca sa v každom inicializovanom module
$this->getData("base_url") - pri registrácii listenerov modulu je v module dokumentácie nastavené base_url modulu (/documentation/)
$dotApp->on("dotapp.module_dotappdoc.init.start", function ($moduleObj) {
$moduleObj->setData("base_url", "/documentation/");
});
Vysvetlené v dokumentácii modulov.
*/
$viewVars['seo']['description'] = "Description";
$viewVars['seo']['keywords'] = "Keywords";
$viewVars['seo']['title'] = "Dokumentácia k PHP frameworku DotApp";
return $dotApp->router->renderer->module($this->moduleName)->setView("index")->setViewVar("variables", $viewVars)->renderView();
});
Zobrazenie stránky, vrátane vytvorenia routov, routovania a generovania kódu pomocou šablónovacieho systému, trvalo:
Modulárna efektivita s obojsmernou prepojiteľnosťou
DotApp spracováva iba routy aktívneho modulu, čím šetrí zdroje. Moduly sú navzájom prepojiteľné v oboch smeroch – môžu aktivovať svoje závislosti (napr. modul 3 načíta modul 1 cez $dotApp->module("Module1")->load()) alebo byť spustené nadradeným modulom (napr. modul 1 aktivuje modul 2 a 3 cez listenery). Táto flexibilita umožňuje dynamicky kombinovať moduly podľa potreby projektu.
Kaskádové načítavanie 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 kvôli chýbajúcim závislostiam – a udržuje systém ľahký, pretože sa načítajú iba potrebné časti.
Dynamická správa závislostí cez triggery a listenery
Každý modul má triggery ako init.start, loading, loaded a ďalšie, na ktoré reagujú listenery. 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 modul sa načíta iba raz, či už kaskádovo (zhora nadol) alebo obojsmerne (zdola nahor).
Poznámka: Názvy triggerov sú case-insensitive, takže dotapp.module.Module1.loading a Dotapp.Module.Module1.Loading sú ekvivalentné, ale odporúčame používať formát dotapp.module.NázovTriedy.názovUdalosti pre konzistenciu.
// Listener pre kaskádové načítavanie
$dotApp->on("dotapp.module.Module1.loading", function () use ($dotApp) {
$dotApp->module("Module2")->load(); // Načíta Module2 iba ak je potrebný
});
Automatické riešenie závislostí a DI
Moduly a ich závislosti sa načítajú automaticky – stačí definovať logiku v initializeCondition() alebo listeneroch. Dependency Injection (DI) je jednoduché a efektívne – služby sa registrujú (napr. singleton) a DotApp ich podá tam, kde sú potrebné, bez zbytočného zaťaženia.
// Registrácia singletonu v module
$this->singleton(DotApp::class, function () { return $this; });
// Použitie DI v controlleri
namespace Dotsystems\App\Modules\DotAppDoc\Controllers;
use Dotsystems\App\DotApp;
class TestController2 {
public static function injectionTest(DotApp $dotApp) {
echo "Automaticky injektovaný DotApp";
}
}
Prvý callback víťazí
Pre každú URL sa uchováva iba prvý zodpovedajúci callback – ďalšie pokusy o registráciu sa ignorujú, čo zvyšuje výkon a predchádza konfliktom.
$dotApp->router->get('/documentation/test1', "dotappdoc:className@fnName");
$dotApp->router->get('/documentation/test1', function () { return "Ignorované"; });
// Použije sa iba prvá definícia
Škálovateľnosť pre malé aj veľké projekty
DotApp je ideálny pre malé stránky aj komplexné aplikácie – zachováva nízke nároky a vysokú rýchlosť bez ohľadu na rozsah projektu. Veľké moduly sa dajú rozdeliť na menšie časti, ktoré sa načítajú rekurzívne podľa potreby.
Žiadne zbytočné réžie
DotApp sa sústreďuje na podstatu – rýchle routovanie, minimálna spotreba zdrojov a jednoduché použitie. Nenúti vás niesť bremeno funkcií, ktoré nepotrebujete.
DotApp Bridge
Živé prepojenie – most medzi frontendom a backendom. Stačí jednoduchý kód:
DotApp je ako stvorený pre vývojárov, 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 – a to s výsledkami, ktoré hovoria sami za seba.
Vyskúšajte DotApp a presvedčte sa sami!
Inštalácia
Aplikácia DotApp sa neinštaluje štandardným spôsobom cez composer install, pretože nejde o knižnicu, ale o kompletnú aplikáciu s vlastnou architektúrou. Namiesto toho postupujte podľa nasledujúcich krokov:
Rozbaľte ho do priečinka, kam potrebujete aplikáciu umiestniť.
2. Nastavenie a použitie:
Po naklonovaní alebo rozbalení aplikácie ju nastavte podľa vašich potrieb (napr. konfigurácia databázy, prostredia atď.).
3. Používanie Composer:
Hoci samotná aplikácia nie je inštalovateľná cez Composer, po jej nainštalovaní môžete v priečinku aplikácie používať Composer na pridanie ďalších závislostí, ktoré potrebujete pre váš projekt. Stačí spustiť:
Táto sekcia popisuje minimálne nastavenia po inštalácii DotApp frameworku. Ak nepotrebujete pracovať s databázami alebo preferujete vlastné riešenie namiesto vstavanej knižnice, stačí vykonať nasledujúce kroky:
1. Definujte __ROOTDIR__ konštantu v index.php v koreňovom adresári (bez lomítka na konci)
define('__ROOTDIR__', "/var/www/html");
Uistite sa, že __ROOTDIR__ zodpovedá skutočnému umiestneniu na serveri, inak framework nemusí správne fungovať.
2. Nastavte bezpečný kľúč na šifrovanie $dotApp->encKey v súbore ./App/config.php
Pri nastavovaní encKey použite unikátny a dostatočne dlhý reťazec (odporúča sa aspoň 32 znakov).
3. (Voliteľné) Ak chcete používať vstavaný driver pre prácu s DB, odkomentujte a vyplňte ukážkovú sekciu v súbore ./App/config.php
Poznámka: Podmienku if (!__MAINTENANCE__) môžete pokojne odstrániť.
if (!__MAINTENANCE__) {
/* Database setup */
$dotApp->db->driver("mysqli");
// Príklad použitia: $dotApp->db->add("nazov_ako_chcete_volat_databazu", "server 127.0.0.1", "meno", "heslo", "nazov_databazy_napr_db_w4778", "kodovanie spojenia UTF8");
// Zadefinujme si parametre pre prvú databázu
$dotApp->db->add("zdrojovaDB", "127.0.0.1", "meno", "heslo", "ws_477854", "UTF8");
// Zadefinujme si parametre pre druhú databázu
$dotApp->db->add("cielovaDB", "127.0.0.1", "meno2", "heslo2", "ar_994475", "UTF8");
// Načítanie modulov je povinné pre správne fungovanie frameworku. Môžete ho umiestniť do bloku if alebo mimo neho podľa vašich potrieb.
$dotApp->loadModules();
}
Spustenie frameworku
Teraz je všetko pripravené. Framework DotApp zabezpečí bezpečný a rýchly beh vašej aplikácie. Uistite sa, že všetky nastavenia aj vlastný kód vložíte pred volaním funkcie $dotApp->run(); (alebo jej aliasu $dotApp->davajhet();).
// Všetko pripravené? Spustite framework! - Ako vidíte v súbore index.php
$dotApp->davajhet();
/*
Poznámka: $dotApp->davajhet() je alias pre $dotApp->run().
Pochádzam z východného Slovenska, tak som pridal kúsok nášho "davaj het!"
*/
Pridanie prvej routy
Prázdna stránka a ERROR 404?
Ak ste postupovali podľa návodu a po spustení vidíte prázdnu stránku so stavovým kódom 404, nebojte sa. Je to logické. Router je prázdny, a preto pre adresu / vo vašom prehliadači nenašiel routu a správne zobrazil 404.
Váš framework nemá žiadne moduly, žiadne routy a preto robí to, čo má. Poďme si teda pridať prvú routu. Pred kód $dotApp->run(); / $dotApp->davajhet(); pridáme prvú routu.
// Pridanie prvej routy pre domovskú stránku
$dotApp->router->get("/", function () {
return "Ahoj svet!";
});
// Spustenie frameworku
$dotApp->davajhet();
Po spustení vidíme stránku s obsahom:
Ahoj svet!
DotApp Router
Router je kľúčovou súčasťou DotApp Frameworku, ktorá spravuje routovanie HTTP požiadaviek v aplikácii. Umožňuje definovať, ako sa majú požiadavky (napr. GET, POST) mapovať na konkrétne callback funkcie, controllery alebo middleware. Router je navrhnutý tak, aby zvládal statické aj dynamické routy, podporoval hooks (before a after) a poskytoval flexibilitu pri tvorbe webových aplikácií.
1.1 Čo je Router?
Router v DotApp Frameworku je trieda Dotsystems\App\Parts\Router, ktorá spracováva prichádzajúce HTTP požiadavky a smeruje ich na príslušné handlery. Pracuje v súčinnosti s objektom Request, ktorý obsahuje informácie o požiadavke (cesta, metóda, premenné). Jeho hlavnou úlohou je zjednodušiť definovanie rout a zabezpečiť, aby sa správny kód spustil pre danú URL a HTTP metódu.
Router je integrovaný priamo do jadra frameworku, takže ho nemusíte samostatne inštalovať ani konfigurovať – stačí ho používať cez $dotApp->router.
1.2 Kľúčové vlastnosti
Router ponúka širokú škálu funkcií, ktoré uľahčujú vývoj aplikácií:
Podpora HTTP metód: Definovanie rout pre GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD, TRACE a univerzálnu metódu ANY.
Dynamické routy: Použitie premenných (napr. {id}) a regulárnych výrazov na zachytenie častí URL.
Middleware: Podpora before a after hooks na vykonávanie logiky pred a po hlavnom handleri.
Request objekt: Prenáša informácie o požiadavke do callbackov a controllerov.
Flexibilita: Možnosť použiť anonymné funkcie, controllery alebo middleware pomocou reťazca (napr. "modul:controller@funkcia").
Chaining: Reťazenie metód pre prehľadnejší kód.
1.3 Základné princípy routingu
Router porovnáva aktuálnu URL (získanú z request->getPath()) a HTTP metódu (z request->getMethod()) s definovanými routami. Ak sa nájde zhoda:
Spustia sa prípadné before hooks.
Vykoná sa hlavná logika (callback, controller alebo middleware).
Spustia sa prípadné after hooks.
Routy môžu byť:
Statické: Presná zhoda URL (napr. /home).
Dynamické: Obsahujú premenné alebo wildcardy (napr. /user/{id}).
Prvý match víťazí: Prvý match obsadí routu. Ostatné sa dropnú.
Router resolvuje požiadavky pomocou metódy resolve(), ktorá je zvyčajne volaná automaticky v rámci životného cyklu DotApp.
Príklad základnej routy:
$dotApp->router->get('/home', function ($request) {
return "Vitajte na domovskej stránke!";
});
Po zadaní URL http://example.com/home sa zobrazí text "Vitajte na domovskej stránke!".
2. Začíname
Táto kapitola vás prevedie základmi práce s Routerom v DotApp Frameworku – od inicializácie až po definovanie prvej routy.
2.1 Inicializácia Routeru
Router je automaticky inicializovaný ako súčasť inštancie $dotApp pri vytvorení aplikácie v DotApp Frameworku. Nie je potrebné ho manuálne vytvárať ani konfigurovať – stačí pristúpiť k nemu cez $dotApp->router. Pri inicializácii sa nastavia predvolené hodnoty, ako napríklad adresár pre controllery (__ROOTDIR__/App/Parts/Controllers/) a prázdne polia pre routy a hooks.
Technické detaily:
Router je inštancia triedy Dotsystems\App\Parts\Router.
Pri konštrukcii prijíma $dotAppObj (inštanciu hlavnej triedy DotApp), ktorá mu poskytuje prístup k objektu Request a ďalším službám frameworku.
2.2 Prístup k Routeru v DotApp
K Routeru pristupujete cez globálnu inštanciu $dotApp, ktorá je dostupná kdekoľvek v aplikácii po jej bootstrape. Objekt Request je automaticky dostupný cez $dotApp->router->request a prenáša informácie o aktuálnej požiadavke (cesta, metóda, premenné).
Príklad prístupu:
// Overenie aktuálnej cesty
echo $dotApp->router->request->getPath(); // Napr. "/home"
// Overenie HTTP metódy
echo $dotApp->router->request->getMethod(); // Napr. "get"
2.3 Prvé definovanie routy
Najjednoduchší spôsob, ako začať s Routerom, je definovať základnú routu pomocou niektorej z HTTP metód (napr. get()). Routa môže byť spojená s anonymnou funkciou (callbackom), controllerom alebo middleware.
Príklad prvej routy s callbackom:
$dotApp->router->get('/home', function ($request) {
return "Vitajte na domovskej stránke!";
});
Vysvetlenie:
/home: Statická URL cesta.
function($request): Callback, ktorý prijíma objekt Request a vracia odpoveď.
Po zavolaní http://example.com/home sa zobrazí text "Vitajte na domovskej stránke!".
Príklad s controllerom:
Predpokladajme, že máte controller HomeController v __ROOTDIR__/App/Parts/Controllers/HomeController.php s funkciou index:
// HomeController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class HomeController {
public static function index($request) {
return "Toto je domovská stránka z controlleru!";
}
}
// Definícia routy
$dotApp->router->get('/home', 'HomeController@index');
Vysvetlenie:
'HomeController@index': Odkaz na statickú metódu index v triede HomeController.
Router automaticky načíta a zavolá túto metódu s objektom Request.
Spustenie routingu:
Router spracuje požiadavky po zavolaní $dotApp->router->resolve(), ktoré je zvyčajne v hlavnom skripte aplikácie (napr. index.php). Ak je framework správne nastavený, toto volanie môže byť automatické.
// index.php
require_once 'vendor/autoload.php';
$dotApp = new Dotsystems\App\DotApp();
$dotApp->router->get('/home', function ($request) {
return "Vitajte!";
});
$dotApp->router->resolve();
3. Definovanie rout
Táto kapitola popisuje, ako definovať routy v Routeri DotApp Frameworku. Router podporuje rôzne spôsoby definovania – od základných HTTP metód až po dynamické routy s premennými a prácu s controllermi.
3.1 Základné HTTP metódy (GET, POST, atď.)
Router poskytuje metódy pre všetky štandardné HTTP metódy: get(), post(), put(), delete(), patch(), options(), head() a trace(). Každá metóda definuje routu pre konkrétnu HTTP požiadavku.
Príklad GET routy:
$dotApp->router->get('/about', function ($request) {
return "Toto je stránka O nás!";
});
Príklad POST routy:
$dotApp->router->post('/submit', function ($request) {
return "Formulár bol odoslaný!";
});
Poznámka: Každá metóda prijíma URL cestu ako prvý parameter a callback (alebo odkaz na controller) ako druhý parameter. Callback vždy dostane objekt $request.
3.2 Metóda match() pre viaceré metódy a URL
Metóda match() umožňuje definovať routu pre viacero HTTP metód naraz alebo pre pole URL adries. Je to flexibilnejší spôsob oproti samostatným metódam ako get() či post().
Príklad s viacerými metódami:
$dotApp->router->match(['get', 'post'], '/contact', function ($request) {
return "Toto je kontaktná stránka!";
});
Táto routa funguje pre GET aj POST požiadavky na /contact.
Príklad s viacerými URL:
$dotApp->router->match(['get'], ['/home', '/index'], function ($request) {
return "Vitajte na domovskej stránke!";
});
Routa zachytí požiadavky na /home aj /index.
3.3 Statické vs. dynamické routy
Router rozlišuje medzi statickými a dynamickými routami:
Statické routy: Presná zhoda URL (napr. /home).
Dynamické routy: Obsahujú premenné alebo wildcardy (napr. /user/{id}).
Príklad statickej routy:
$dotApp->router->get('/profile', function ($request) {
return "Toto je statický profil!";
});
Príklad dynamickej routy:
$dotApp->router->get('/user/{id}', function ($request) {
return "Profil používateľa s ID: " . $request->matchData()['id'];
});
Pri URL /user/123 sa zobrazí "Profil používateľa s ID: 123".
3.4 Použitie premenných v routách
Dynamické routy môžu obsahovať premenné označené zloženými zátvorkami (napr. {id}). Tieto premenné sú automaticky extrahované a dostupné cez $request->matchData().
Základné použitie:
$dotApp->router->get('/article/{slug}', function ($request) {
return "Článok: " . $request->matchData()['slug'];
});
Pre /article/how-to-cook sa zobrazí "Článok: how-to-cook".
Funguje len pre čísla, napr. /user/123, ale nie /user/abc.
3.5 Práca s controllermi a middleware
Okrem anonymných funkcií môžete routy mapovať na controllery alebo middleware pomocou reťazca v tvare "modul:controller@funkcia" alebo "modul:\\middleware\\middleware1@funkcia1".
Príklad s controllerom:
// app/parts/controllers/UserController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class UserController {
public static function show($request) {
return "Zobrazenie používateľa!";
}
}
// Definícia routy
$dotApp->router->get('/user', 'UserController@show');
Príklad s middleware:
// app/parts/middleware/AuthMiddleware.php
namespace Dotsystems\App\Parts\Middleware;
use Dotsystems\App\DotApp;
class AuthMiddleware {
public static function check($request) {
return "Overenie autentifikácie!";
}
}
// Definícia routy
$dotApp->router->get('/secure', 'parts:\\Middleware\\AuthMiddleware@check');
Poznámka: Funkcie musia byť definované ako public static a prijímať $request ako parameter.
4. Práca s Request objektom
Objekt Request je neoddeliteľnou súčasťou Routera v DotApp Frameworku. Prenáša informácie o aktuálnej HTTP požiadavke a je automaticky odovzdaný do callbackov, controllerov a middleware. Táto kapitola vysvetlí, ako funguje a ako ho efektívne používať.
4.1 Čo je Request?
Request je inštancia triedy Dotsystems\App\Parts\Request, ktorá slúži ako rozhranie pre prácu s dátami požiadavky. Obsahuje informácie o ceste, HTTP metóde, premenných z dynamických rout a ďalších atribútoch požiadavky. Je automaticky vytvorený pri inicializácii Routera a dostupný cez $dotApp->router->request.
Kľúčové vlastnosti:
Získavanie aktuálnej URL cesty a metódy.
Prístup k premenným z dynamických rout cez matchData().
Prenos dát do callbackov a hooks.
4.2 Prístup k dátam z Requestu
Objekt Request poskytuje metódy na získanie základných informácií o požiadavke:
getPath(): Vráti aktuálnu URL cestu (napr. /home).
getMethod(): Vráti HTTP metódu (napr. get, post).
matchData(): Vráti pole premenných extrahovaných z dynamickej routy.
hookData(): Vráti dáta priradené hooks (používa sa pri samostatných before/after).
Pri požiadavke na /user/123 sa zobrazí: "Cesta: /user/123, Metóda: get, ID: 123".
4.3 Využitie Requestu v callbackoch
Objekt Request je automaticky odovzdaný ako parameter do všetkých callbackov, controllerov a middleware definovaných v routách. Umožňuje vám pracovať s dátami požiadavky priamo v logike routy.
// app/parts/controllers/ProfileController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class ProfileController {
public static function show($request) {
$name = $request->matchData()['name'];
return "Profil pre: $name";
}
}
// Definícia routy
$dotApp->router->get('/profile/{name}', 'ProfileController@show');
Výsledok je rovnaký ako pri anonymnej funkcii.
Príklad s middleware:
// app/parts/middleware/CheckMiddleware.php
namespace Dotsystems\App\Parts\Middleware;
use Dotsystems\App\DotApp;
class CheckMiddleware {
public static function verify($request) {
$path = $request->getPath();
return "Overená cesta: $path";
}
}
// Definícia routy
$dotApp->router->get('/check', 'parts:\\Middleware\\CheckMiddleware@verify');
Pri /check sa zobrazí: "Overená cesta: /check".
Poznámka:matchData() vracia prázdne pole, ak routa neobsahuje dynamické premenné. Pred použitím si overte existenciu kľúča, napr. isset($request->matchData()['id']), aby ste predišli chybám.
5. Middleware (Before a After Hooks)
Middleware v Routeri DotApp Frameworku umožňuje vykonávať dodatočnú logiku pred alebo po hlavnom handleri routy. Tieto "hooks" sú definované pomocou metód before() a after() a sú ideálne na úlohy ako autentifikácia, logovanie alebo úprava odpovedí.
5.1 Čo sú hooks?
Hooks sú funkcie, ktoré sa spúšťajú automaticky v určitých fázach spracovania routy:
before: Spustí sa pred hlavnou logikou routy (napr. callbackom alebo controllerom).
after: Spustí sa po hlavnej logike, s prístupom k výsledku routy.
Hooks prijímajú objekt $request ako parameter a môžu byť definované globálne, pre konkrétnu routu alebo metódu s routou.
5.2 Definovanie before()
Metóda before() sa používa na pridanie logiky, ktorá sa vykoná pred hlavným handlerom. Môže byť použitá tromi spôsobmi:
Globálne: Pre všetky routy.
Pre konkrétnu routu: Len pre zadanú cestu.
Pre metódu a routu: Špecificky pre HTTP metódu a cestu.
Globálne before:
$dotApp->router->before(function ($request) {
return "Pred každou routou!";
});
$dotApp->router->get('/test', function ($request) {
return "Testovacia stránka";
});
Hook sa spustí pre všetky routy, napr. pri /test sa najskôr vykoná "Pred každou routou!".
$dotApp->router->before('get', ['/page1', '/page2'], function ($request) {
return "Pred stránkami";
});
$dotApp->router->get('/page1', function ($request) {
return "Stránka 1";
});
$dotApp->router->get('/page2', function ($request) {
return "Stránka 2";
});
Poznámka: Výstup z hooks sa pridáva k odpovedi routy. Ak chcete meniť odpoveď, pracujte s $request->response->body priamo v hooku (viac v pokročilých funkciách).
6. Správa chýb a výnimiek
Router v DotApp Frameworku umožňuje vývojárom spravovať chyby a výnimky, ktoré vznikajú pri spracovaní požiadaviek. Táto kapitola popisuje, ako riešiť štandardné chyby ako 404 a implementovať vlastnú logiku spracovania chýb pomocou callbackov a hooks.
6.1 Riešenie 404 chýb
Ak Router nenájde zhodu pre požiadavku (ani statickú, ani dynamickú routu), automaticky nastaví HTTP kód 404. Predvolené správanie nezobrazí žiadny výstup, takže je na vývojárovi, aby definoval vlastnú logiku na zachytenie a zobrazenie chyby.
Príklad s globálnym after hookom:
$dotApp->router->after("*", function ($request) {
if (http_response_code() === 404) {
return "Stránka nenájdená: " . $request->getPath();
}
});
$dotApp->router->get('/home', function ($request) {
return "Domovská stránka";
});
Pri požiadavke na /about (neexistujúca routa) sa zobrazí: "Stránka nenájdená: /about". Hook s "*" sa spustí pre všetky routy a overí stavový kód.
Príklad s ukončením skriptu:
$dotApp->router->after("*", function ($request) {
if (http_response_code() === 404) {
echo "404 - Nenájdená stránka!";
exit;
}
});
$dotApp->router->get('/home', function ($request) {
return "Domovská stránka";
});
Pri /about sa zobrazí "404 - Nenájdená stránka!" a skript sa ukončí.
6.2 Vlastné spracovanie chýb
Vývojári môžu implementovať vlastnú logiku spracovania chýb priamo v callbackoch alebo middleware pomocou podmienok a HTTP kódov.
Príklad s podmienkou v callbacku:
$dotApp->router->get('/user/{id:i}', function ($request) {
$id = $request->matchData()['id'];
if ($id > 100) {
http_response_code(403);
return "Zakázaný prístup pre ID väčšie ako 100!";
}
return "Profil používateľa: $id";
});
Pri /user/150 sa zobrazí "Zakázaný prístup pre ID väčšie ako 100!" s kódom 403.
Poznámka: Použitie http_response_code() v callbackoch alebo hooks umožňuje nastaviť vlastné chybové stavy. Je na vývojárovi, či skript ukončí pomocou exit alebo vráti chybovú správu.
7. Pokročilé funkcie
Router v DotApp Frameworku ponúka pokročilé funkcie, ktoré rozširujú jeho možnosti. Táto kapitola popisuje reťazenie metód, dynamické porovnávanie URL, detailné vysvetlenie tvorby dynamických adries a definovanie API endpointov.
7.1 Reťazenie metód (Chaining)
Router podporuje reťazenie metód, čo umožňuje definovať routy, hooks a ďalšie nastavenia v jednom príkaze. To zlepšuje čitateľnosť a organizáciu kódu.
Pri /profile/123 sa postupne spustí before, hlavná logika a after.
7.2 Dynamické porovnávanie rout (matchUrl())
Metóda matchUrl() slúži na manuálne porovnanie URL s routovacím vzorom. Vráti pole extrahovaných premenných, ak sa vzor zhoduje, alebo false, ak nie. Je užitočná pre vlastné validácie alebo testovanie rout.
Dynamické adresy v Routeri umožňujú definovať routy s premennými a voliteľnými časťami pomocou špeciálnej syntaxe. Tieto vzory sú rozpoznávané všade rovnako (napr. v get(), post(), match()) a premenné sú dostupné cez $request->matchData(). Nasleduje podrobné vysvetlenie na príklade a zoznam najčastejších vzorov.
Poznámka: Tieto vzory sú flexibilné a kombinovateľné. Používajte {?:} pre voliteľné časti a typy (:i, :s, :l) pre presné obmedzenia.
7.4 Definovanie API endpointov pomocou apiPoint
Metóda apiPoint v Routeri poskytuje pohodlný spôsob, ako definovať API endpointy s podporou verzovania, modulov a dynamických parametrov. Umožňuje flexibilitu pri definovaní vlastných ciest a metód, pričom v kombinácii s vstavanou abstraktnou triedou Controller a jej metódami apiDispatch (hlavná logika) a api (kratší alias) ponúka automatické rozbočovanie požiadaviek na špecifické metódy v controlleroch s podporou dependency injection (DI).
Definícia metódy apiPoint:
public function apiPoint($verzia, $modul, $controller, $custom = null) {
$apiRouty = array();
if ($custom !== null) {
if (is_array($custom)) {
foreach ($custom as $value) {
$apiRouty[] = "/api/v".$verzia."/".$modul."/".$value;
}
} else {
$apiRouty[] = "/api/v".$verzia."/".$modul."/".$custom;
}
} else {
$apiRouty[] = "/api/v".$verzia."/".$modul."/{resource}(?:/{id})?";
}
$this->any($apiRouty, $controller);
}
Parametre:
$verzia: Verzia API (napr. "1" pre v1).
$modul: Názov modulu (napr. "dotcmsfe").
$controller: Callback alebo reťazec vo formáte "Controller@metoda" (napr. "PostsController@apiDispatch", "PostsController@api", alebo vlastná metóda).
$custom (voliteľné): Špecifická cesta (reťazec) alebo pole ciest. Podporuje regulárne výrazy (napr. (?:/{id})?).
Ak $custom nie je zadaný, použije sa predvolená dynamická cesta /api/v{verzia}/{modul}/{resource}(?:/{id})?. Ak je zadaný, použijú sa iba cesty z $custom. Prvá routa vyhráva! Statické cesty musia byť uvedené pred dynamickými, aby sa predišlo prekrytiu dynamickou logikou.
Vstavaný Controller a metódy apiDispatch/api:
Framework poskytuje abstraktnú triedu Dotsystems\App\Parts\Controller s metódou apiDispatch, ktorá automaticky rozbočuje požiadavky na špecifické metódy v tvare (napr. postUsers, getPosts) na základe HTTP metódy a hodnoty dynamického parametra resource. Stačí nasmerovať apiPoint na Controller@apiDispatch (alebo Controller@api ako kratší alias), a automatické rozbočovanie funguje, ak cesta obsahuje {resource}. Na rozdiel od iných frameworkov (napr. Laravel, Django) nepotrebujete definovať routy pre každý endpoint – apiDispatch to urobí za vás s plnou podporou DI cez self::$di->callStatic.
// Výňatok z Dotsystems\App\Parts\Controller
public static function apiDispatch($request) {
$method = strtolower($request->getMethod());
$resource = $request->matchData()['resource'] ?? null;
$id = $request->matchData()['id'] ?? null;
// Zostavíme názov metódy:
if ($resource) {
$targetMethod = $method . ucfirst($resource);
if (method_exists(static::class, $targetMethod)) {
return self::$di->callStatic($targetMethod, [$request]);
}
}
// Skúsime volať error404, ak existuje
if (method_exists(static::class, 'error404')) {
return self::$di->callStatic('error404', [$request]);
}
// Predvolená odpoveď, ak error404 neexistuje
http_response_code(404);
return "API: Resource '$resource' not found or method '$method' not supported in " . static::class;
}
public static function api($request) {
// Alias kratší
self::apiDispatch($request);
}
Výhody použitia Controller@apiDispatch s DI:
Metóda apiDispatch využíva DI kontajner na volanie špecifických metód, čím prináša automatickú injekciu závislostí. To znamená, že metódy v controlleroch môžu prijímať ďalšie parametre (napr. služby ako \SomeService), ktoré sú automaticky injektované z DI kontajnera bez potreby manuálneho vytvárania inštancií. Tento prístup zjednodušuje kód, zvyšuje flexibilitu a odlišuje DotApp od iných frameworkov tým, že eliminuje potrebu explicitného routovania pre každý endpoint pri použití automatiky.
Prispôsobenie chýb:
Ak cieľová metóda (napr. postUsers) neexistuje, apiDispatch najprv skontroluje, či controller definuje metódu error404. Ak áno, zavolá ju a umožní používateľovi definovať vlastnú logiku pre 404 chyby (napr. JSON odpoveď, logovanie). Ak error404 neexistuje, vráti predvolenú chybovú hlášku s HTTP kódom 404.
Použitie s automatickým rozbočovaním:
Automatické rozbočovanie cez apiDispatch (alebo api) funguje iba vtedy, ak cesta obsahuje dynamický parameter {resource} na správnom mieste (napr. /api/v1/dotcmsfe/{resource}). Ak $custom nezachová tento formát, automatika nebude fungovať a je potrebné použiť vlastnú metódu.
Výsledné cesty: Tu automatické rozbočovanie nefunguje, pretože chýba {resource}. Logika závisí od implementácie customMethod.
GET /api/v1/dotcmsfe/users/details - Spustí customMethod.
POST /api/v1/dotcmsfe/posts/summary - Spustí customMethod.
Príklad controlleru s DI a vlastnou chybou:
namespace Dotsystems\App\Modules\Dotcmsfe\Controllers;
class PostsController extends \Dotsystems\App\Parts\Controller {
public static function postUsers($request, \SomeService $service) {
return "Vytvorenie používateľov: " . $service->process($request->getPath());
}
public static function getPosts($request) {
$id = $request->matchData()['id'] ?? null;
return "Zoznam príspevkov" . ($id ? " s ID: $id" : "");
}
public static function error404($request) {
http_response_code(404);
return json_encode([
'error' => 'Not Found',
'message' => "Resource '{$request->matchData()['resource']}' not found or method '{$request->getMethod()}' not supported",
'path' => $request->getPath()
]);
}
public static function customMethod($request) {
return "Vlastná metóda pre cestu: " . $request->getPath();
}
}
Poznámka: Vstavaný Controller zjednodušuje prácu s API cez apiDispatch (alebo api), ak cesta obsahuje {resource}. Pre vlastné routy bez {resource} môžete použiť vlastné metódy, ale automatické rozbočovanie nebude fungovať. Poradie ciest v $custom je kritické – statické cesty musia byť pred dynamickými.
8. Praktické príklady
Táto kapitola prináša praktické príklady použitia Routera v DotApp Frameworku. Ukazuje, ako kombinovať základné a pokročilé funkcie na riešenie bežných scenárov vo webových aplikáciách.
8.1 Jednoduchá GET routa
Najzákladnejší príklad definovania statickej routy s jednoduchou odpoveďou.
Príklad:
$dotApp->router->get('/welcome', function ($request) {
return "Vitajte v aplikácii!";
});
Pri požiadavke na /welcome sa zobrazí: "Vitajte v aplikácii!".
Použitie: Ideálne pre statické stránky, ako sú úvodné stránky alebo "O nás".
8.2 Dynamická routa s premennými
Príklad dynamickej routy s extrakciou premenných na zobrazenie údajov o používateľovi.
Pri /user/123/Jano sa zobrazí: "Používateľ ID: 123, Meno: Jano".
Použitie: Vhodné pre profily, detaily produktov alebo iné zdroje s identifikátormi.
8.3 Použitie middleware
Príklad kombinácie routy s before a after hooks na overenie a logovanie.
Príklad:
$dotApp->router->get('/dashboard', function ($request) {
return "Vitajte v dashboarde!";
})->before(function ($request) {
$user = "guest"; // Simulácia overenia
if ($user === "guest") {
http_response_code(403);
return "Prístup zamietnutý!";
}
})->after(function ($request) {
return "Dashboard zobrazený o " . date('H:i:s');
});
Pri /dashboard sa zobrazí "Prístup zamietnutý!" s kódom 403 (keďže simulácia overenia zlyhá). Ak by bolo overenie úspešné, zobrazilo by sa "Vitajte v dashboarde!" a následne čas zobrazenia.
Použitie: Autentifikácia, logovanie prístupu alebo úprava odpovedí.
8.4 Kombinácia s controllermi
Príklad integrácie routy s controllerom na oddelenie logiky od routingu.
Príklad:
// app/parts/controllers/ArticleController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class ArticleController {
public static function detail($request) {
$slug = $request->matchData()['slug'];
return "Detail článku: $slug";
}
}
// Definícia routy
$dotApp->router->get('/article/{slug:s}', 'ArticleController@detail');
Pri /article/how-to-code sa zobrazí: "Detail článku: how-to-code".
Použitie: Väčšie aplikácie, kde je potrebná organizácia kódu do controllerov.
9. Tipy a triky
Táto kapitola ponúka praktické tipy a triky na efektívne využitie Routera v DotApp Frameworku. Pomôžu vám optimalizovať kód, ladiť problémy a dodržiavať osvedčené postupy.
9.1 Optimalizácia routingu
Router v DotApp Frameworku funguje na princípe "prvý match víťazí" – prvá zhoda v poradí definovania routy sa použije a ostatné sa ignorujú, bez ohľadu na to, či je routa statická alebo dynamická. Poradie definovania je preto kľúčové pre optimalizáciu.
Definujte najdôležitejšie routy najskôr: Keďže prvý match víťazí, umiestnite kritické alebo častejšie používané routy na začiatok.
Používajte špecifické vzory: Napr. {id:i} namiesto {id}, aby ste zabránili nechceným zhôdám na nesprávnych routách.
Zoskupte podobné routy: Použite match() s poľom ciest na zníženie duplicity kódu, ale dávajte pozor na poradie.
Príklad optimalizácie:
$dotApp->router->get('/user/{id:i}', function ($request) { // Prvá dynamická routa
return "Dynamický používateľ ID: " . $request->matchData()['id'];
});
$dotApp->router->get('/user/123', function ($request) { // Statická routa druhá
return "Statický používateľ 123";
});
Pri /user/123 sa vždy použije prvá routa ("Dynamický používateľ ID: 123"), pretože bola definovaná ako prvá, aj keď druhá je statická a presnejšia. Ak chcete prioritu pre statickú routu, definujte ju skôr.
Príklad s prepísaním poradia:
$dotApp->router->get('/user/123', function ($request) { // Statická routa prvá
return "Statický používateľ 123";
});
$dotApp->router->get('/user/{id:i}', function ($request) { // Dynamická routa druhá
return "Dynamický používateľ ID: " . $request->matchData()['id'];
});
Teraz pri /user/123 vyhrá "Statický používateľ 123", lebo je definovaná ako prvá.
9.2 Ladenie rout
Pri ladení problémov s routami použite dostupné nástroje Routera a PHP na identifikáciu, ktorá routa sa skutočne spúšťa, najmä pri "prvom matchi".
Skontrolujte cestu: Použite $request->getPath() na overenie, akú URL Router spracováva.
Výpis premenných: Vypíšte $request->matchData(), aby ste videli, aké hodnoty boli extrahované.
Testujte poradie: Pridajte dočasné výpisy (napr. echo) do callbackov, aby ste zistili, ktorá routa sa spustila.
Príklad ladenia:
$dotApp->router->get('/page/{id}', function ($request) {
echo "Spustila sa dynamická routa pre ID: " . $request->matchData()['id'];
return "Dynamická stránka " . $request->matchData()['id'];
});
$dotApp->router->get('/page/1', function ($request) {
echo "Spustila sa statická routa pre /page/1";
return "Statická stránka 1";
});
Pri /page/1 sa zobrazí "Spustila sa dynamická routa pre ID: 1" a "Dynamická stránka 1", pretože dynamická routa je definovaná ako prvá. Zmena poradia by uprednostnila statickú routu.
9.3 Best practices pre štruktúru rout
Dodržiavanie osvedčených postupov pomáha udržať prehľadnosť a predvídateľnosť routingu.
Logické poradie: Definujte routy od najšpecifickejších po najvšeobecnejšie, aby ste využili pravidlo "prvý match víťazí".
Komentáre: Pridávajte komentáre nad routy, aby bolo jasné, prečo sú v danom poradí.
Oddelenie logiky: Používajte controllery pre komplexné routy namiesto inline callbackov.
Príklad best practices:
// Najšpecifickejšia statická routa
$dotApp->router->get('/api/users/guest', function ($request) {
return "Hosťovský používateľ";
});
// Špecifická dynamická routa
$dotApp->router->get('/api/users/{id:i}', function ($request) {
return "Používateľ ID: " . $request->matchData()['id'];
});
// Všeobecná routa na konci
$dotApp->router->get('/api/{resource}', function ($request) {
return "Zdroj: " . $request->matchData()['resource'];
});
Pri /api/users/guest sa spustí prvá routa, pri /api/users/5 druhá a pri /api/products tretia, vďaka logickému poradiu.
10. Záver
Táto kapitola uzatvára dokumentáciu Routera v DotApp Frameworku. Zhŕňa jeho výhody a ponúka pohľad na jeho budúci vývoj a komunitu.
10.1 Prečo používať Router v DotApp?
Router v DotApp Frameworku je jednoduchý, no výkonný nástroj na správu routingu vo webových aplikáciách. Jeho hlavné výhody zahŕňajú:
Flexibilita: Podpora statických aj dynamických rout s premennými a voliteľnými časťami.
Jednoduchosť: Intuitívne rozhranie na definovanie rout cez HTTP metódy ako get() a post().
Middleware: Možnosť pridania before a after hooks pre rozšírenú logiku.
Prvý match víťazí: Predvídateľné správanie založené na poradí definovania rout, čo dáva vývojárom plnú kontrolu.
Integrácia: Bezproblémová spolupráca s controllermi a objektom Request na spracovanie požiadaviek.
Či už tvoríte malú aplikáciu alebo komplexný systém, Router vám poskytne nástroje na rýchle a efektívne mapovanie požiadaviek na logiku.
Dependency Injection a Middleware v DotApp
Táto kapitola popisuje dependency injection (DI) a middleware v DotApp frameworku. Zameriava sa na flexibilné volania kontrolerov a middleware cez stringy, polia, callable objekty a anonymné funkcie, s automatickým vkladaním závislostí cez stringToCallable a vylepšenú metódu di.
1. Dependency Injection a Middleware v DotApp
Táto kapitola popisuje dependency injection (DI) a middleware v DotApp frameworku. Vysvetľuje DI kontajner, jeho registráciu závislostí cez bind a singleton, a ako sú tieto závislosti resolvované pomocou resolve. Tiež popisuje flexibilné volania kontrolerov a middleware cez stringy, polia, callable objekty a anonymné funkcie s automatickým DI.
1.1. Čo je Dependency Injection a Middleware?
Dependency Injection (DI) je technika, ktorá umožňuje automaticky vkladať závislosti (napr. DotApp) do metód a funkcií namiesto ich manuálneho vytvárania. V DotApp je DI spravované cez DI kontajner v triede DotApp, ktorý registruje závislosti a resolvuje ich pri volaniach.
Middleware sú funkcie alebo triedy, ktoré spracúvajú požiadavky pred alebo po hlavnej logike, využívajúc DI pre prístup k registrovaným závislostiam.
1.2. DI Kontajner v DotApp
DI kontajner v DotApp je jadrom správy závislostí a pozostáva z troch hlavných metód:
1.2.1. bind(string $key, callable $resolver)
Registruje závislosť, ktorá sa vytvorí nanovo pri každom volaní resolve. Používa sa pre nezdieľané (non-shared) inštancie.
$DotApp->bind('logger', function () {
return new Logger();
});
$logger = $DotApp->resolve('logger'); // Vytvorí novú inštanciu
$logger2 = $DotApp->resolve('logger'); // Vytvorí ďalšiu novú inštanciu
Poznámka: Každé volanie resolve vráti novú inštanciu, pretože shared je nastavené na false.
1.2.2. singleton(string $key, callable $resolver)
Registruje závislosť ako singleton – vytvorí sa iba raz a následne sa zdieľa pri všetkých volaniach resolve. Používa sa pre zdieľané inštancie, ako je napríklad samotný DotApp.
// V konštruktore DotApp
$this->singleton(DotApp::class, function () {
return $this;
});
$dotApp1 = $DotApp->resolve(DotApp::class); // Vráti tú istú inštanciu
$dotApp2 = $DotApp->resolve(DotApp::class); // Vráti tú istú inštanciu
Poznámka: Singleton zaručuje, že existuje iba jedna inštancia danej závislosti, uložená v $this->instances.
1.2.3. resolve(string $key)
Resolvuje zaregistrovanú závislosť. Ak je to singleton, vráti zdieľanú inštanciu; ak je to bind, vytvorí novú.
Syntax:resolve(string $key)
Príklad:
$DotApp->singleton('db', function () {
return new Database();
});
$db = $DotApp->resolve('db'); // Vráti singleton inštanciu
Výnimka: Ak kľúč nie je registrovaný, vyhodí Exception.
1.2.4. Ako funguje DI v praxi
DI kontajner ukladá závislosti v poli $this->bindings s informáciou, či sú zdieľané (shared). Pri resolúcii kontroluje, či už existuje inštancia (pre singletony) alebo volá resolver (pre bind). V konštruktore DotApp je napríklad DotApp::class zaregistrovaný ako singleton, aby bol prístupný všade:
$this->singleton(DotApp::class, function () { return $this; });
1.3. Možnosti volania kontrolerov a middleware
DotApp využíva DI kontajner na automatické vkladanie závislostí do callbackov:
$DotApp->bind('logger', function () {
return new Logger();
});
$DotApp->router->get('/log', function (DotApp $dotApp, Logger $logger) {
echo "Log: " . $logger->getLogId() . ", Metóda: " . $dotApp->router->request->getMethod();
});
Výstup pri GET /log:
Log: 12345, Metóda: GET
1.6. Poznámky
Singleton vs. Bind: Používajte singleton pre zdieľané inštancie (napr. DotApp, databáza), bind pre nové inštancie pri každom volaní.
Closure DI: Funguje automaticky v routeri a middleware vďaka di.
Middleware parametre: Dynamické parametre z middlewareCall ešte nie sú implementované – odovzdávajte manuálne.
Best practice: Registrujte kľúčové služby ako singletony v inicializácii modulu.
DotBridge
DotBridge je kľúčovou súčasťou DotApp Frameworku, ktorá zabezpečuje bezpečnú a efektívnu komunikáciu medzi PHP na strane servera a JavaScriptom na strane klienta prostredníctvom AJAX požiadaviek. Umožňuje definovať PHP funkcie, ktoré sú volateľné z front-endu, spravovať vstupy a chrániť komunikáciu pred neoprávneným prístupom alebo zneužitím. DotBridge je navrhnutý tak, aby poskytoval flexibilitu, bezpečnosť a jednoduchú integráciu dynamických funkcií do webových aplikácií.
1.1 Čo je DotBridge?
DotBridge v DotApp Frameworku je trieda Dotsystems\App\Parts\Bridge, ktorá slúži ako most medzi back-endovou logikou v PHP a front-endovými akciami v JavaScripte. Umožňuje volanie PHP funkcií z HTML prvkov (napr. tlačidiel, formulárových vstupov) cez AJAX požiadavky na cestu /dotapp/bridge. Jeho hlavnou úlohou je zjednodušiť prepojenie klient-server, pričom zabezpečuje, aby komunikácia bola overená, šifrovaná a chránená pred útokmi, ako sú CSRF alebo opakované odosielanie požiadaviek.
DotBridge je integrovaný priamo do jadra frameworku, takže ho nemusíte samostatne inštalovať ani konfigurovať – stačí ho používať cez $dotApp->bridge.
1.2 Kľúčové vlastnosti
DotBridge ponúka širokú škálu funkcií, ktoré uľahčujú vývoj bezpečných a dynamických aplikácií:
Bezpečná komunikácia: Používa šifrovanie dát, overovanie kľúčov a CRC kontrolu na ochranu požiadaviek.
Volanie PHP funkcií: Definovanie PHP funkcií volateľných z JavaScriptu s podporou before a after callbackov.
Validačné filtre: Real-time validácia vstupov (napr. email, URL, heslo) s vizuálnou spätnou väzbou na strane klienta.
Rate Limiting: Možnosť nastaviť limity požiadaviek za určitý čas (rateLimit(pocet_sekund,pocet_kliknuti)).
Jednorazové kľúče: Podpora oneTimeUse a regenerateId pre vyššiu bezpečnosť.
Flexibilita: Podpora rôznych udalostí (napr. click, keyup) a dynamických vstupov z HTML.
Chaining: Reťazenie metód pre prehľadnejší kód na strane PHP aj JavaScriptu.
1.3 Základné princípy fungovania
DotBridge spracováva komunikáciu medzi klientom a serverom v nasledujúcich krokoch:
Generuje unikátny kľúč pre reláciu a registruje PHP funkcie na strane servera cez fn().
V HTML sa definujú udalosti (napr. dotbridge:on(click)) a vstupy (napr. dotbridge:input), ktoré sú prepojené s PHP funkciami.
Pri spustení udalosti (napr. kliknutí) sa odošle AJAX požiadavka na /dotapp/bridge s šifrovanými dátami.
Server overí kľúč, dešifruje dáta, skontroluje limity požiadaviek a spustí požadovanú PHP funkciu.
Výsledok sa vráti ako JSON odpoveď, ktorú môže JavaScript ďalej spracovať.
Komunikácia je chránená šifrovaním dát, overovaním kľúčov a limitmi, aby sa predišlo zneužitiu alebo neoprávnenému prístupu.
Po kliknutí na tlačidlo sa zavolá PHP funkcia sayHello a vráti JSON odpoveď s textom "Ahoj zo servera!".
2. Začíname
Táto kapitola vás prevedie základmi práce s DotBridge v DotApp Frameworku – od inicializácie až po definovanie prvej funkcie, pridanie udalosti na front-end a spracovanie odpovede v JavaScripte.
2.1 Inicializácia DotBridge
DotBridge je automaticky inicializovaný ako súčasť inštancie $dotApp pri vytvorení aplikácie v DotApp Frameworku. Prístup k nemu získate cez $dotApp->bridge. Pri inicializácii sa vygeneruje unikátny kľúč relácie (uložený v _bridge.key v relácii) a nastavia sa predvolené hodnoty, ako sú limity požiadaviek a vstavané validačné filtre.
Technické detaily:
Bridge je inštancia triedy Dotsystems\App\Parts\Bridge.
Prijíma referenciu na $dotApp, čím získava prístup k šifrovacím metódam, reláciám (dsm) a routeru.
Automaticky registruje cestu /dotapp/bridge v routeri pre spracovanie AJAX požiadaviek.
2.2 Definovanie PHP funkcie
Na strane servera definujete volateľnú PHP funkciu pomocou metódy fn(), ktorá prijíma názov funkcie a callback. Callback dostane parameter $data, ktorý obsahuje dáta odoslané z front-endu (napr. hodnoty vstupov). Funkcia by mala vrátiť pole s kľúčmi ako status a status_txt pre konzistentnú odpoveď.
Funkcia sendMessage je teraz pripravená na volanie z front-endu a vráti JSON odpoveď s prijatou správou.
2.3 Pridanie udalosti na front-end
V HTML použite atribút {{ dotbridge:on(event)="functionName(params)" }} na prepojenie udalosti (napr. click, keyup) s PHP funkciou. Môžete definovať vstupy pomocou {{ dotbridge:input="name" }} a pridať parametre ako rateLimit(60,10) alebo oneTimeUse pre kontrolu správania.
Po kliknutí na tlačidlo sa hodnota z inputu user.message pošle do funkcie sendMessage s limitom 10 požiadaviek za minútu.
2.4 Spracovanie odpovede v JavaScripte
Na strane klienta môžete pomocou $dotapp.bridge() definovať before a after callbacky na spracovanie stavu pred odoslaním požiadavky a po prijatí odpovede. Tieto callbacky umožňujú dynamicky meniť UI na základe odpovede od servera.
Pred odoslaním sa text tlačidla zmení na "Odosiela sa..." a po prijatí odpovede sa zobrazí správa z PHP funkcie.
3. Pokročilé použitie
Táto kapitola pokrýva pokročilé funkcie DotBridge, ako sú validačné filtre, rate limiting, chaining metód a práca s dynamickými dátami. Tieto nástroje umožňujú vytvárať robustnejšie a bezpečnejšie aplikácie s väčšou kontrolou nad správaním.
3.1 Validačné filtre
DotBridge poskytuje vstavané validačné filtre na overovanie vstupov v reálnom čase priamo na strane klienta. Filtre, ako email, url, phone alebo password, aplikujú regulárne výrazy a vizuálnu spätnú väzbu (CSS triedy) na základe validity vstupu. Používajú sa v HTML cez atribút dotbridge-result="0" dotbridge-input="name".
Dostupné argumenty:
filter: Názov filtra (napr. email).
start_checking_length: Minimálny počet znakov pre začatie validácie.
Input user.email sa začne validovať po zadaní 5 znakov. Ak je email platný, pridá sa trieda valid-email, ak nie, invalid-email.
3.2 Rate Limiting a bezpečnostné mechanizmy
DotBridge umožňuje obmedziť počet požiadaviek pomocou parametrov rateLimit(sekundy,kliknutia), čím chráni aplikáciu pred zneužitím. Ďalšie bezpečnostné funkcie zahŕňajú oneTimeUse (jednorazové použitie kľúča) a regenerateId (regenerácia ID po každom použití).
Použitie:
rateLimit(sekundy,kliknutia): Maximálne kliknutia požiadaviek za počet sekúnd sekundy.
oneTimeUse: Kľúč je platný iba pre jedno použitie.
regenerateId: Vygeneruje nový kľúč po každom volaní.
1. príklad - Tlačidlo umožní maximálne 10 kliknutí za minútu, 100 za hodinu.
2. príklad - Tlačidlo umožní len jedno kliknutie a listener zanikne.
3. príklad - Tlačidlo regeneruje ID na každom kliknutí.
3.3 Chaining metód
DotBridge podporuje reťazenie metód na strane PHP aj JavaScriptu, čo zjednodušuje definovanie funkcií a callbackov. Na PHP použite fn(), before() a after(), na JS $dotapp.bridge() s before() a after().
Pred spracovaním sa vstup očistí (before), po spracovaní sa pridá časová pečiatka (after) a na klientovi sa zobrazí stav načítavania.
3.4 Práca s dynamickými dátami
DotBridge umožňuje posielať a spracovávať dynamické dáta z viacerých vstupov definovaných v HTML. Vstupy sú identifikované pomocou dotbridge:input a odoslané v $_POST['data'], kde ich PHP funkcia môže spracovať.
Po kliknutí sa hodnoty z inputov user.name a user.email pošlú do funkcie saveUser a vrátia sa v odpovedi.
4. Best Practices a tipy
Táto kapitola ponúka odporúčania a tipy na efektívne a bezpečné používanie DotBridge. Zahŕňa optimalizáciu bezpečnosti, ladenie problémov a integráciu s ostatnými časťami DotApp Frameworku.
4.1 Optimalizácia bezpečnosti
Bezpečnosť je kľúčovým aspektom pri používaní DotBridge. Nasledujúce odporúčania pomôžu minimalizovať riziká a zabezpečiť robustnú komunikáciu:
Používajte rate limiting: Vždy nastavte rateLimitM a rateLimitH pre akcie citlivé na opakované volania, aby ste predišli zneužitiu (napr. brute force útokom).
Aktivujte jednorazové kľúče: Pre kritické operácie (napr. odoslanie formulára) použite oneTimeUse alebo regenerateId, čím zabránite opakovanému použitiu rovnakého kľúča.
Overujte vstupy: Kombinujte validačné filtre s dodatočnou kontrolou na serveri (napr. filter_var()), aby ste zaistili konzistentnú validáciu.
Monitorujte relácie: Pravidelne kontrolujte a čistite staré kľúče v _bridge.objects, aby ste predišli preplneniu pamäte.
Používajte šifrovanie: Využite vstavané šifrovanie DotApp (encrypt(), decrypt()) pre citlivé dáta v komunikácii.
Tento príklad obmedzuje akciu na 2 volania za minútu a umožňuje iba jedno použitie kľúča.
4.2 Ladenie a riešenie problémov
Pri práci s DotBridge sa môžu vyskytnúť chyby. Tu sú bežné problémy a ich riešenia:
CRC check failed (error_code 1): Overte, či dáta odoslané z front-endu neboli modifikované. Skontrolujte integritu JavaScript kódu a sieťové požiadavky.
Bridge key does not match (error_code 2): Uistite sa, že kľúč v relácii (_bridge.key) zodpovedá tomu, čo posiela klient. Môže ísť o problém s vypršanou reláciou.
Function not found (error_code 3): Skontrolujte, či je funkcia správne zaregistrovaná pomocou fn() a či sa názov zhoduje s volaním v HTML.
Rate limit exceeded (error_code 4): Prekročili ste nastavený limit. Zvýšte rateLimitM/rateLimitH alebo informujte používateľa o čakaní.
Tip: Zapnite ladenie v DotApp a sledujte odpovede z /dotapp/bridge v nástrojoch prehliadača (Network tab) pre detailné informácie.
4.3 Integrácia s inými časťami DotApp
DotBridge je navrhnutý na súčinnosť s ostatnými komponentmi DotApp, ako sú Router, Request a databáza. Integrácia umožňuje vytvárať komplexné aplikácie s minimálnym úsilím.
Príklady integrácie:
S Routerom:DotBridge automaticky využíva $dotApp->router na registráciu cesty /dotapp/bridge.
S Requestom: Dáta z $_POST sú sprístupnené v callbacku ako $data.
S databázou: Môžete priamo vkladať dáta z front-endu do databázy cez $dotApp->db.
Po kliknutí sa email overí a uloží do databázy, pričom sa vráti odpoveď o úspechu alebo chybe.
Databaser
1. Úvod
1.1. Čo je Databaser?
Databaser je robustná a flexibilná knižnica na správu databázových interakcií, ktorá je integrovanou súčasťou DotApp Frameworku. Navrhnutá je tak, aby poskytovala jednoduchý, bezpečný a efektívny spôsob práce s databázami, či už ide o základné operácie, alebo pokročilé dotazy. Databaser eliminuje potrebu písania surových SQL dotazov (aj keď túto možnosť stále ponúka) a prináša moderný prístup k manipulácii s dátami prostredníctvom intuitívneho QueryBuildera a voliteľného ORM (Object-Relational Mapping) systému. Jeho hlavným cieľom je uľahčiť vývojárom prácu s databázami a zároveň zachovať vysokú mieru prispôsobiteľnosti a výkonu.
Databaser je priamo zabudovaný do jadra DotApp Frameworku, takže nie je potrebné ho samostatne inštalovať ani konfigurovať mimo frameworku. Po nastavení databázových pripojení v rámci DotAppu je pripravený na okamžité použitie.
1.2. Kľúčové vlastnosti
Databaser ponúka širokú škálu funkcií, ktoré ho robia výnimočným nástrojom pre prácu s databázami:
Jednoduché vytváranie a vykonávanie SQL dotazov: Podpora prepared statements zaisťuje bezpečnosť a jednoduchosť pri práci s dátami.
Správa viacerých databázových pripojení: Možnosť definovať a prepínať medzi rôznymi databázami s uloženými prihlasovacími údajmi.
Podpora vlastných driverov: Okrem predvolených driverov (MySQLi a PDO) je možné implementovať vlastné databázové drivery.
Voliteľný ORM: Pre MySQLi aj PDO je k dispozícii ORM s triedami Entity (jednotlivý riadok) a Collection (súbor riadkov), ktoré zjednodušujú prácu s dátami ako s objektmi.
Lazy loading a vzťahy: Podpora vzťahov typu HasOne, HasMany, MorphOne a MorphMany s možnosťou prispôsobiť dotazy pomocou callbackov.
Pokročilé vzťahy: Možnosť upraviť QueryBuilder v rámci vzťahov (napr. pridať limit, orderBy, where) cez voliteľný callback parameter.
Validácia a hromadné operácie: ORM obsahuje vstavanú validáciu dát a podporu hromadných operácií nad kolekciami.
Integrovaný QueryBuilder: Intuitívny nástroj na tvorbu dotazov, ktorý pokrýva od jednoduchých SELECTov až po zložité JOINy a subdotazy.
Callbacky pre SUCCESS a ERROR: Každá operácia vracia výsledky a debugovacie dáta cez callbacky, čo zjednodušuje spracovanie úspechov aj chýb.
Podpora transakcií: Jednoduchá správa transakcií s automatickým commitom alebo rollbackom.
1.3. RAW vs. ORM: Kedy použiť ktorý prístup?
Databaser ponúka dva hlavné spôsoby práce s dátami: RAW a ORM. Výber medzi nimi závisí od potrieb vášho projektu:
RAW MÓD:
Vracajú sa priamo výsledky databázových dotazov (napr. polia alebo databázové zdroje).
Ideálne pre jednoduché aplikácie, rýchle prototypy alebo situácie, kde potrebujete maximálnu kontrolu nad SQL dotazmi.
Príklad použitia: Jednoduchý SELECT na získanie zoznamu používateľov bez potreby objektovej manipulácie.
Výhody: Rýchle vykonanie, minimálna réžia, plná flexibilita pri písaní dotazov.
ORM MÓD:
Dáta sú mapované na objekty (Entity pre jeden riadok, Collection pre viac riadkov), čo uľahčuje prácu s dátami ako s objektmi.
Vhodné pre komplexné aplikácie, kde potrebujete vzťahy medzi tabuľkami, validáciu dát alebo hromadné operácie.
Príklad použitia: Správa používateľov s ich príspevkami (vzťah HasMany) a automatické ukladanie zmien.
Výhody: Objektovo-orientovaný prístup, podpora vzťahov, jednoduchá manipulácia s dátami.
Kedy použiť ktorý prístup?
Ak potrebujete rýchly výkon a jednoduché dotazy, zvoľte RAW.
Ak pracujete s komplexnými dátovými štruktúrami a chcete elegantné riešenie, siahnite po ORM.
1.4. Podpora databázových driverov (MySQLi, PDO)
Databaser podporuje dva hlavné databázové drivery, ktoré pokrývajú väčšinu bežných potrieb:
MySQLi
Legacy aj moderný prístup s ORM.
Vhodný pre projekty, ktoré už používajú MySQLi, alebo pre jednoduchšie aplikácie s MySQL databázami.
Podporuje všetky funkcie QueryBuildera a ORM.
PDO
Moderný prístup s podporou viacerých databáz (MySQL, PostgreSQL, SQLite atď.).
Flexibilnejší vďaka dynamickému DSN (Data Source Name), čo umožňuje pripojenie k rôznym typom databáz.
Rovnako podporuje QueryBuilder aj ORM.
Oba drivery sú navrhnuté tak, aby boli vzájomne zameniteľné – kód napísaný pre jeden driver funguje aj s druhým bez väčších úprav, pokiaľ rešpektujete špecifiká konkrétneho databázového systému.
1.5. Integrovaný QueryBuilder
QueryBuilder je srdcom Databaseru. Umožňuje vytvárať SQL dotazy pomocou reťaziteľných metód, čím zjednodušuje písanie bezpečných a čitateľných dotazov. Podporuje:
Základné operácie: select, insert, update, delete.
Podmienky: where, orWhere, vnorené podmienky cez Closure.
Spojenia tabuliek: join, leftJoin.
Agregácie: groupBy, having.
Zoradenie a obmedzenia: orderBy, limit, offset.
Surové dotazy: raw s podporou otáznikov (?) aj pomenovaných premenných (:name).
QueryBuilder automaticky spravuje prepared statements a bindings, čím zaisťuje ochranu pred SQL injection útokmi. Každá hodnota, ktorá sa použije v dotaze (napr. v podmienkach where alebo pri vkladaní dát cez insert), je automaticky escapovaná a nahradená placeholdermi (? alebo pomenovanými premennými :name). Tým sa minimalizuje riziko bezpečnostných zraniteľností a zároveň sa zvyšuje prehľadnosť kódu.
1.6. Callbacky pre SUCCESS a ERROR
Databaser používa systém callbackov na spracovanie výsledkov a chýb. Každá operácia (napr. execute(), save()) môže prijať dva voliteľné callbacky:
SUCCESS callback
Spustí sa pri úspešnom vykonaní operácie. Dostáva tri parametre:
$result: Výsledok operácie (napr. pole dát v RAW móde, objekt v ORM móde).
$db: Inštancia Databaseru, ktorá umožňuje ďalšie dotazy.
$debug: Debugovacie dáta (napr. vygenerovaný SQL dotaz, bindings).
ERROR callback
Spustí sa pri chybe. Dostáva rovnako tri parametre:
$error: Pole s informáciami o chybe (error – text chyby, errno – kód chyby).
$db: Inštancia Databaseru pre prípadné ďalšie operácie.
$debug: Debugovacie dáta pre analýzu problému.
Tento prístup zjednodušuje asynchrónne spracovanie a umožňuje reťazenie operácií priamo v callbackoch. Napríklad, ak pri vykonaní jedného dotazu potrebujete okamžite spustiť ďalší, môžete to urobiť priamo v SUCCESS callbacku pomocou $db->q(). Tento systém zároveň zvyšuje flexibilitu a čitateľnosť kódu, pretože logika pre úspech a chybu je oddelená a prehľadne definovaná. Ak nie je nastavený ERROR callback, je možné zachytiť chybu pomocou TRY-CATCH bloku. Naopak, ak je ERROR callback nastavený, TRY-CATCH blok nebude fungovať, pretože správa chýb je v tomto prípade plne delegovaná na callback.
2. Začíname
2.1. Inštalácia a konfigurácia Databaseru
Databaser je neoddeliteľnou súčasťou DotApp Frameworku, takže nie je potrebné ho samostatne inštalovať. Ak ste už nastavili DotApp Framework vo vašom projekte, Databaser je automaticky k dispozícii cez inštanciu $DotApp->DB. Predpokladáme, že máte framework nakonfigurovaný a pripravený na použitie.
2.2. Pridanie databázového pripojenia
Databaser umožňuje pridať a spravovať viacero databázových pripojení. Pripojenie sa definuje pomocou metódy add(), ktorá je volaná na inštancii $DotApp->DB. Príklad:
$DotApp->DB->add(
'main', // Názov pripojenia
'localhost', // Server
'root', // Používateľské meno
'password123', // Heslo
'moja_databaza', // Názov databázy
'utf8mb4', // Kódovanie
'mysql' // Typ databázy
);
2.3. Výber drivera (MySQLi alebo PDO)
Databaser podporuje MySQLi aj PDO. Výber drivera:
// Použitie MySQLi drivera
$DotApp->DB->driver('mysqli');
// Použitie PDO drivera
$DotApp->DB->driver('pdo');
2.4. Prvé spojenie s databázou
Po definovaní pripojenia a výbere drivera je potrebné aktivovať pripojenie:
QueryBuilder je kľúčovým nástrojom Databaseru, ktorý umožňuje vytvárať SQL dotazy pomocou reťaziteľných metód. Jeho hlavnou výhodou je jednoduchosť, čitateľnosť a bezpečnosť – automaticky spravuje prepared statements a bindings, čím chráni pred SQL injection útokmi. V tejto kapitole podrobne rozoberieme jeho fungovanie, dostupné metódy a ukážeme príklady od jednoduchých až po zložité dotazy.
3.1. Základné princípy QueryBuildera
QueryBuilder je objekt triedy Dotsystems\App\Parts\QueryBuilder, ktorý sa používa v rámci metódy q() alebo qb() na inštancii $DotApp->DB. Funguje tak, že postupne budujete dotaz volaním metód, pričom každá metóda pridáva časť SQL príkazu (napr. select, where, join). Na konci sa dotaz vykoná pomocou metód ako execute(), first() alebo all().
Základné vlastnosti:
Reťaziteľnosť: Metódy vracajú inštanciu QueryBuildera, takže ich môžete spájať do reťazca.
Prepared Statements: Všetky hodnoty sú automaticky escapované a nahrádzané placeholdermi (?).
Flexibilita: Podpora surových SQL dotazov cez metódu raw() pre špeciálne prípady.
Debugovateľnosť: Po vykonaní dotazu dostanete v $debug vygenerovaný SQL a bindings.
Príklad základného použitia:
$DotApp->DB->q(function ($qb) {
$qb->select('*', 'users')->where('age', '>', 18);
})->execute(
function ($result, $db, $debug) {
echo $debug['query']; // "SELECT * FROM users WHERE age > ?"
var_dump($debug['bindings']); // [18]
var_dump($result);
}
);
3.2. Zoznam metód QueryBuildera
Tu je podrobný prehľad všetkých hlavných metód QueryBuildera s vysvetlením a príkladmi.
3.2.1. select
Metóda select() definuje, ktoré stĺpce a z ktorej tabuľky chcete vybrať dáta.
Syntax:select($columns = '*', $table = null)
Parametre:
$columns: Reťazec alebo pole stĺpcov (napr. 'id, name' alebo ['id', 'name']).
$table: Názov tabuľky (voliteľné, ak použijete from()).
SQL ekvivalent:SELECT stĺpce FROM tabuľka
Príklad:
$qb->select('id, name', 'users');
// SQL: SELECT id, name FROM users
3.2.2. insert
Metóda insert() vloží nový riadok do tabuľky.
Syntax:insert($table, array $data)
Parametre:
$table: Názov tabuľky.
$data: Asociatívne pole s dátami (stĺpec => hodnota).
SQL ekvivalent:INSERT INTO tabuľka (stĺpce) VALUES (hodnoty)
$qb->raw('SELECT * FROM users WHERE age > ?', [18]);
// SQL: SELECT * FROM users WHERE age > ?
// Bindings: [18]
3.3. Príklady od jednoduchých po zložité dotazy
Jednoduchý select
$qb->select('*', 'users');
// SQL: SELECT * FROM users
select s where podmienkou
$qb->select('name', 'users')->where('age', '>', 18);
// SQL: SELECT name FROM users WHERE age > ?
// Bindings: [18]
Vnorené podmienky (Closure)
$qb->select('*', 'users')->where(function ($qb) {
$qb->where('age', '>', 18)->orWhere('name', '=', 'Jano');
});
// SQL: SELECT * FROM users WHERE (age > ? OR name = ?)
// Bindings: [18, 'Jano']
join s viacerými tabuľkami
$qb->select('users.name, posts.title', 'users')
->join('posts', 'users.id', '=', 'posts.user_id')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id');
// SQL: SELECT users.name, posts.title FROM users
// INNER JOIN posts ON users.id = posts.user_id
// LEFT JOIN comments ON posts.id = comments.post_id
Subquery ako hodnota
$qb->select('name', 'users')->where('id', '=', function ($qb) {
$qb->select('user_id', 'posts')->where('title', '=', 'Novinka');
});
// SQL: SELECT name FROM users WHERE id = (SELECT user_id FROM posts WHERE title = ?)
// Bindings: ['Novinka']
raw dotaz s pomenovanými premennými
$qb->raw('SELECT * FROM users WHERE age > :age AND name = :name', [
'age' => 18,
'name' => 'Jano'
]);
// SQL: SELECT * FROM users WHERE age > ? AND name = ?
// Bindings: [18, 'Jano']
4. Práca s Databaserom v DotApp
V tejto kapitole sa zameriame na praktické použitie Databaseru v rámci DotApp Frameworku. Ukážeme, ako nastaviť typ návratu, vykonávať dotazy, pracovať s ORM, spravovať transakcie a debugovať výsledky. Databaser je navrhnutý tak, aby poskytoval flexibilitu a jednoduchosť, či už preferujete RAW prístup, alebo objektovo-orientovaný ORM.
4.1. Nastavenie typu návratu (RAW vs. ORM)
Databaser umožňuje definovať, aký typ dát chcete dostať ako výsledok dotazu. Typ návratu sa nastavuje pomocou metódy return() a ovplyvňuje, ako budú dáta spracované po vykonaní dotazu.
RAW: Vráti surové dáta (napr. pole riadkov alebo databázový zdroj). Predvolený typ.
ORM: Vráti dáta ako objekty (Entity pre jeden riadok, Collection pre viac riadkov).
Syntax:$DotApp->DB->return($type)
$type: Reťazec 'RAW' alebo 'ORM' (nezáleží na veľkosti písmen).
Príklad nastavenia RAW:
$DotApp->DB->return('RAW')->q(function ($qb) {
$qb->select('*', 'users');
})->execute(
function ($result, $db, $debug) {
var_dump($result); // Pole riadkov
}
);
V tejto kapitole ukážeme praktické príklady použitia Databaseru v DotApp Frameworku. Zameriame sa na bežné scenáre, ako sú CRUD operácie (Create, Read, Update, Delete), pokročilé dotazy s join a subquery, práca s transakciami a ladenie chýb. Použijeme metódy insertedId() a affectedRows() namiesto priameho prístupu k $db->statement['execution_data'].
5.1. Základné CRUD operácie v RAW móde
Create (Vytvorenie):
$DotApp->DB->return('RAW')->q(function ($qb) {
$qb->insert('users', ['name' => 'Jano', 'age' => 25]);
})->execute(
function ($result, $db, $debug) {
$id = $db->insertedId(); // Získanie ID nového záznamu
echo "Nový používateľ s ID: $id bol vytvorený.\n";
},
function ($error, $db, $debug) {
echo "Chyba: {$error['error']}\n";
}
);
$DotApp->DB->q(function ($qb) {
$qb->select('*', 'neexistujuca_tabuľka'); // Chybný dotaz
})->execute(
function ($result, $db, $debug) {
echo "Úspech\n";
},
function ($error, $db, $debug) {
echo "Chyba: {$error['error']}\n";
// Možné ďalšie dotazy na opravu
$db->q(function ($qb) {
$qb->select('*', 'users'); // Skúsime inú tabuľku
})->execute(
function ($result, $db, $debug) {
echo "Opravený dotaz úspešný.\n";
}
);
}
);
6. Práca so SchemaBuilderom
SchemaBuilder je výkonný nástroj v Databaseri, ktorý slúži na definovanie a správu databázovej štruktúry. Umožňuje vytvárať, upravovať a odstraňovať tabuľky priamo z kódu bez nutnosti písania surových SQL príkazov na správu schémy. Je integrovaný do QueryBuildera a používa sa cez metódy ako createTable(), alterTable() a dropTable(). V tejto kapitole vysvetlíme jeho funkcie, vstupy a ukážeme praktické príklady.
6.1. Základné princípy SchemaBuildera
SchemaBuilder je trieda Dotsystems\App\Parts\SchemaBuilder, ktorá sa používa v callbacku metód schema() alebo priamo v createTable(), alterTable() a dropTable(). Jeho cieľom je poskytnúť programový spôsob definovania tabuliek, stĺpcov, indexov a cudzích kľúčov. Výsledné príkazy sú automaticky prevedené na SQL a vykonané cez aktívny driver (MySQLi alebo PDO).
Kľúčové vlastnosti:
Reťaziteľné metódy: Podobne ako QueryBuilder, aj SchemaBuilder umožňuje reťazenie.
Abstrakcia: Funguje nezávisle od databázového drivera, hoci niektoré špecifické funkcie môžu závisieť od databázového systému.
Jednoduchosť: Umožňuje rýchlo definovať schému bez hlbokých znalostí SQL syntaxe.
6.2. Dostupné metódy SchemaBuildera
Tu je prehľad hlavných metód s vysvetlením a vstupmi:
6.2.1. id()
Pridá primárny kľúč typu BIGINT UNSIGNED AUTO_INCREMENT.
Kompatibilita: Niektoré funkcie (napr. ON DELETE CASCADE) nemusia fungovať rovnako vo všetkých databázach (napr. SQLite má obmedzenia).
Transakcie: Pri väčších zmenách schémy používajte transact() na zaistenie konzistencie.
Debugovanie: Vždy kontrolujte $debug['query'] na overenie vygenerovaného SQL.
7. CacheDriverInterface
Databaser v DotApp Frameworku podporuje integráciu s cachingom, čo umožňuje ukladať výsledky dotazov a zvyšovať výkon aplikácie pri opakovaných požiadavkách na rovnaké dáta. Aby bolo možné caching využiť, je potrebné implementovať rozhranie CacheDriverInterface, ktoré definuje štandardné metódy pre prácu s cache. V tejto kapitole vysvetlíme, čo toto rozhranie obsahuje, aké metódy musí cache driver podporovať, a ukážeme, ako ho používať s Databaserom.
7.1. Čo je CacheDriverInterface?
CacheDriverInterface je rozhranie, ktoré určuje, ako má vyzerať driver pre ukladanie a načítanie dát z cache. Databaser ho používa na komunikáciu s ľubovoľným caching systémom (napr. Memcached, Redis, súborový systém), pričom logiku ukladania a správy cache si implementuje používateľ. Po nastavení cache drivera cez metódu cache() sa Databaser automaticky pokúsi načítavať výsledky z cache pred vykonaním dotazu a ukladať nové výsledky po jeho úspešnom dokončení.
Výhody:
Zníženie zaťaženia databázy.
Rýchlejší prístup k často používaným dátam.
Flexibilita – môžete použiť akýkoľvek caching systém.
7.2. Zloženie CacheDriverInterface
Rozhranie CacheDriverInterface definuje štyri povinné metódy, ktoré musí každý cache driver implementovať:
interface CacheDriverInterface {
public function get($key);
public function set($key, $value, $ttl = null);
public function delete($key);
public function deleteKeys($pattern);
}
7.2.1. get($key)
Načíta hodnotu z cache na základe kľúča.
Parameter:
$key: Reťazec – unikátny kľúč pre uložené dáta.
Návratová hodnota: Uložená hodnota alebo null, ak kľúč neexistuje.
Účel:Databaser volá túto metódu, aby skontroloval, či už výsledok dotazu existuje v cache.
7.2.2. set($key, $value, $ttl = null)
Uloží hodnotu do cache s daným kľúčom.
Parametre:
$key: Reťazec – kľúč pre uloženie.
$value: Dáta na uloženie (môžu byť pole, objekt atď.).
$ttl: Čas životnosti v sekundách (voliteľné, null znamená bez expirácie).
Návratová hodnota: Žiadna (alebo true/false podľa implementácie).
Účel: Po úspešnom vykonaní dotazu Databaser ukladá výsledok do cache.
7.2.3. delete($key)
Odstráni konkrétny kľúč z cache.
Parameter:
$key: Reťazec – kľúč na odstránenie.
Návratová hodnota: Žiadna (alebo true/false).
Účel: Používa sa na explicitné mazanie konkrétneho záznamu z cache.
7.2.4. deleteKeys($pattern)
Odstráni viacero kľúčov na základe vzoru.
Parameter:
$pattern: Reťazec – vzor kľúčov (napr. "users:*").
Návratová hodnota: Žiadna (alebo počet odstránených kľúčov).
Účel:Databaser volá túto metódu pri aktualizácii dát (napr. save() v ORM), aby invalidoval súvisiace cache záznamy.
7.3. Implementácia vlastného CacheDrivera
Tu je príklad jednoduchej implementácie cache drivera využívajúceho súborový systém:
class FileCacheDriver implements CacheDriverInterface {
private $cacheDir;
public function __construct($cacheDir = '/tmp/cache') {
$this->cacheDir = $cacheDir;
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0777, true);
}
}
public function get($key) {
$file = $this->cacheDir . '/' . md5($key);
if (file_exists($file)) {
$data = unserialize(file_get_contents($file));
if ($data['expires'] === null || $data['expires'] > time()) {
return $data['value'];
}
unlink($file); // Expirované, odstránime
}
return null;
}
public function set($key, $value, $ttl = null) {
$file = $this->cacheDir . '/' . md5($key);
$expires = $ttl ? time() + $ttl : null;
$data = ['value' => $value, 'expires' => $expires];
file_put_contents($file, serialize($data));
return true;
}
public function delete($key) {
$file = $this->cacheDir . '/' . md5($key);
if (file_exists($file)) {
unlink($file);
return true;
}
return false;
}
public function deleteKeys($pattern) {
$count = 0;
foreach (glob($this->cacheDir . '/*') as $file) {
$key = basename($file);
if (fnmatch($pattern, $key)) {
unlink($file);
$count++;
}
}
return $count;
}
}
Vysvetlenie:
get(): Načíta dáta zo súboru, ak neexpirovali.
set(): Uloží dáta do súboru s voliteľným TTL.
delete(): Odstráni konkrétny súbor.
deleteKeys(): Odstráni súbory podľa vzoru (používa fnmatch).
7.4. Použitie CacheDrivera s Databaserom
Po implementácii cache drivera ho nastavíte pomocou metódy cache():
$cacheDriver = new FileCacheDriver('/tmp/myapp_cache');
$DotApp->DB->cache($cacheDriver);
// Príklad dotazu s cachingom
$DotApp->DB->q(function ($qb) {
$qb->select('*', 'users')->where('age', '>', 18);
})->execute(
function ($result, $db, $debug) {
echo "Výsledky (z cache alebo DB):\n";
var_dump($result);
}
);
Ako to funguje:
Databaser vygeneruje kľúč (napr. users:RAW:hash_dotazu).
Skontroluje cache cez get(). Ak nájde platné dáta, vráti ich bez dotazu na DB.
Ak dáta nie sú v cache, vykoná dotaz a uloží výsledok cez set() s TTL (predvolené 3600 sekúnd).
Pri aktualizácii (napr. save() v ORM) invaliduje súvisiace kľúče cez deleteKeys().
Pri save() sa zavolá deleteKeys("users:ORM:*"), čím sa invalidujú všetky ORM záznamy pre users.
7.6. Poznámky a tipy
TTL: Nastavte rozumnú hodnotu TTL (napr. 3600 sekúnd) podľa potreby aplikácie.
Vzory kľúčov:Databaser používa formát tabuľka:typ:hash, takže vzory ako "users:*" sú efektívne.
Výkon: Pre produkčné prostredie zvážte rýchle cache systémy ako Redis namiesto súborov.
Testovanie: Overte, či deleteKeys() správne invaliduje cache, aby ste predišli zastaraným dátam.
8. Práca s Entity
Entity je základnou stavebnou jednotkou ORM (Object-Relational Mapping) v Databaseri, ktorá reprezentuje jeden riadok v databázovej tabuľke ako objekt. Umožňuje jednoduchú manipuláciu s dátami, definovanie vzťahov a validáciu. Táto kapitola podrobne vysvetlí jej štruktúru, všetky dostupné metódy a ukáže ich praktické použitie.
8.1. Čo je Entity?
Entity je dynamicky generovaný objekt, ktorý mapuje riadok tabuľky na objekt s atribútmi zodpovedajúcimi stĺpcom. Vytvára sa automaticky, keď nastavíte typ návratu na 'ORM' a vykonáte dotaz vracajúci jeden riadok (napr. cez first()) alebo viac riadkov (v Collection cez all()). Poskytuje objektovo-orientovaný prístup k dátam, čím zjednodušuje prácu s databázou.
Kľúčové vlastnosti:
Atribúty: Prístup k stĺpcom tabuľky ako k vlastnostiam objektu (napr. $entity->name).
Vzťahy: Podpora hasOne, hasMany, morphOne, morphMany pre prepojenie tabuliek.
Validácia: Možnosť definovať pravidlá pred uložením dát.
Lazy a Eager Loading: Vzťahy sa načítajú lenivo, s možnosťou prednačítania.
8.2. Zloženie Entity
Entity je anonymná trieda definovaná v createMysqliDriver() alebo createPdoDriver(). Obsahuje tieto hlavné prvky:
Súkromné atribúty:
$attributes: Pole aktuálnych hodnôt stĺpcov (napr. ['id' => 1, 'name' => 'Jano']).
$originalAttributes: Pôvodné hodnoty pre sledovanie zmien.
$db: Referencia na inštanciu Databaseru.
$table: Názov tabuľky (odvodený z dotazu alebo odhadnutý).
$primaryKey: Primárny kľúč (predvolené 'id').
$rules: Pole validačných pravidiel.
$relations: Pole načítaných vzťahov (napr. hasMany).
$with: Pole vzťahov pre eager loading.
$morphRelations: Pole polymorfných vzťahov.
Metódy:
with($relations): Nastaví vzťahy pre eager loading.
loadRelations(): Načíta vzťahy definované v $with.
Lazy vs. Eager Loading: Pre časté prístupy k vzťahom vždy používajte with() a loadRelations(), aby ste znížili počet dotazov.
Validácia: Pravidlá kontrolujte pred save(), inak sa uložia nevalidné dáta.
Prispôsobenie: Callbacky v save() a vzťahoch umožňujú flexibilitu bez potreby rozširovania triedy.
9. Práca s Collection
Collection je trieda v ORM (Object-Relational Mapping) vrstve Databaseru, ktorá slúži na správu viacerých Entity objektov – teda súbor riadkov z databázy. Umožňuje iteráciu, filtrovanie, transformáciu a hromadné operácie nad dátami. Táto kapitola podrobne vysvetlí jej štruktúru, všetky dostupné metódy a ukáže ich praktické použitie s HTML výstupmi.
9.1. Čo je Collection?
Collection je dynamicky generovaný objekt, ktorý uchováva zoznam Entity objektov vrátených z dotazu, keď nastavíte typ návratu na 'ORM' a použijete metódu all() alebo získate vzťah typu hasMany/morphMany. Poskytuje objektovo-orientovaný prístup k viacerým záznamom naraz, čím zjednodušuje manipuláciu s dátami.
Kľúčové vlastnosti:
Iterovateľnosť: Implementuje IteratorAggregate pre jednoduchú iteráciu cez foreach.
Hromadné operácie: Podpora metód ako saveAll() na uloženie zmien vo všetkých entitách.
Filtrovanie a transformácia: Metódy ako filter(), map(), pluck() na prácu s dátami.
Vzťahy: Možnosť eager loadingu vzťahov pre optimalizáciu dotazov.
9.2. Zloženie Collection
Collection je trieda definovaná v Databaseri. Obsahuje tieto hlavné prvky:
Súkromné atribúty:
$items: Pole Entity objektov (napr. [0 => Entity, 1 => Entity]).
$db: Referencia na inštanciu Databaseru.
$with: Pole vzťahov pre eager loading (napr. ['hasMany:posts']).
Metódy:
with($relations): Nastaví vzťahy pre eager loading.
loadRelations(): Načíta vzťahy definované v $with.
all(): Vráti pole všetkých Entity objektov.
first(): Vráti prvú Entity alebo null.
filter($callback): Filtruje entity podľa podmienky.
map($callback): Transformuje entity pomocou callbacku.
pluck($field): Extrahuje hodnoty konkrétneho stĺpca.
saveAll($callbackOk = null, $callbackError = null): Uloží zmeny vo všetkých entitách.
Výkon: Pri veľkých kolekciách zvážte použitie limit() v dotaze, aby ste znížili zaťaženie pamäte.
Eager Loading: Používajte with() a loadRelations() na zníženie počtu dotazov pri práci so vzťahmi.
Flexibilita: Reťazenie metód ako filter() a map() umožňuje plynulé spracovanie dát.
10. Migrácie
Migrácie v Databaseri umožňujú definovať a spravovať štruktúru databázy pomocou kódu. Používajú sa na vytváranie, úpravu alebo odstraňovanie tabuliek a ich stĺpcov, pričom podporujú transakcie pre hromadné operácie. Táto kapitola podrobne popisuje prácu s migráciami, vrátane ich definície, dostupných metód a praktických príkladov.
10.2. Čo sú migrácie?
Migrácie sú nástroj na správu databázovej schémy, ktorý umožňuje programovo definovať štruktúru tabuliek a ich vzťahov. V Databaseri sa migrácie realizujú cez SchemaBuilder a môžu byť zabalené do transakcií pomocou metódy transact(). Hlavné výhody:
Automatizácia: Zmena databázy je súčasťou kódu a môže byť verzionovaná.
Transakcie: Hromadné operácie sú bezpečné a reverzibilné pri chybe.
Multiplatformovosť: Podpora rôznych driverov (MySQLi, PDO) s prispôsobením syntaxe.
10.3. Základné princípy migrácií
Migrácie v Databaseri fungujú na základe týchto princípov:
SchemaBuilder: Používa sa na definovanie tabuliek a stĺpcov (napr. id(), string(), foreign()).
Metóda migrate(): Slúži na spúšťanie migrácií ('up' pre vytvorenie, 'down' pre rollback).
Transakcie: Hromadné migrácie sa vykonávajú cez transact(), kde sa viaceré operácie spúšťajú ako jeden celok.
Podpora driverov: MySQLi aj PDO prispôsobujú syntax podľa typu databázy (napr. MySQL, PostgreSQL, SQLite).
10.4. Použitie migrácií
Základné použitie migrácií zahŕňa definovanie štruktúry databázy a jej aplikáciu. Príklad vytvorenia tabuľky:
$DotApp->DB->schema(function ($schema) {
$schema->createTable('users', function ($table) {
$table->id();
$table->string('name');
});
}, function ($result, $db, $debug) {
echo "Tabuľka 'users' bola úspešne vytvorená.\n";
});
$DotApp->DB->schema(function ($schema) {
$schema->alterTable('users', function ($table) {
$table->string('email', 100);
});
}, function ($result, $db, $debug) {
echo "
Email stĺpec pridaný.
";
});
Výstup:
Email stĺpec pridaný.
Rollback migrácie:
$DotApp->DB->migrate('down', function ($result, $db, $debug) {
echo "
Tabuľka 'migrations' odstránená.
";
});
Výstup:
Tabuľka 'migrations' odstránená.
10.7. Poznámky
Transakcie: Používajte transact() pre hromadné migrácie, aby ste zaistili konzistenciu.
Podpora driverov: Syntax sa prispôsobuje podľa drivera (napr. MySQL vs. SQLite), ale niektoré funkcie (napr. ON UPDATE v Oracle) nemusia byť plne podporované.
Obmedzenia: Metóda migrate() aktuálne podporuje len základné operácie; pre komplexné migrácie použite schema() alebo transact().
11. Prípadová štúdia: E-shop s ORM
Táto kapitola predstavuje praktickú prípadovú štúdiu, ktorá ukazuje, ako použiť Databaser a jeho ORM na vytvorenie jednoduchého e-shopu. Navrhneme databázovú štruktúru, vytvoríme tabuľky, naplníme ich dátami a ukážeme, ako pracovať s dátami pomocou Entity a Collection. Súčasťou budú aj error callbacky na správu chýb, aby sa používatelia naučili robustné techniky.
11.1. Návrh databázovej štruktúry
Pre e-shop navrhneme tieto tabuľky:
users: Používatelia (zákazníci a administrátori).
products: Produkty v ponuke.
product_descriptions: Popisy produktov (jeden produkt môže mať viac popisov, napr. v rôznych jazykoch).
orders: Objednávky.
order_items: Položky v objednávkach (prepojenie produktov a objednávok).
SQL na vytvorenie tabuliek
Používateľ môže tieto príkazy skopírovať a spustiť v MySQL databáze:
-- Tabuľka používateľov
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
role ENUM('customer', 'admin') DEFAULT 'customer',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tabuľka produktov
CREATE TABLE products (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tabuľka popisov produktov
CREATE TABLE product_descriptions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT UNSIGNED NOT NULL,
language VARCHAR(10) NOT NULL,
description TEXT NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);
-- Tabuľka objednávok
CREATE TABLE orders (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
status ENUM('pending', 'shipped', 'delivered') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Tabuľka položiek objednávok
CREATE TABLE order_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
quantity INT NOT NULL DEFAULT 1,
price DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);
Predpokladáme, že Databaser je nakonfigurovaný a pripojený k databáze (viď kapitola 2). Použijeme ORM na prácu s týmito tabuľkami, vrátane správy chýb.
11.2.1. Získanie používateľa a jeho objednávok
Ukážeme, ako získať používateľa s jeho objednávkami a položkami.
$user = $DotApp->DB->return('ORM')->q(function ($qb) {
$qb->select('*', 'users')->where('id', '=', 1);
})->first(
function ($user, $db, $debug) {
$user->with(['hasMany:orders']);
$user->loadRelations(
function ($result, $db, $debug) {
echo "Používateľ: {$user->name} ({$user->email})\n";
foreach ($user->hasMany('orders', 'user_id') as $order) {
echo "Objednávka #{$order->id}, Celková cena: {$order->total_price}, Stav: {$order->status}\n";
}
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní vzťahov: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní používateľa: {$error['error']}\n";
}
);
11.2.2. Pridanie nového produktu s popisom
Vytvoríme nový produkt a pridáme mu popis v slovenčine.
$DotApp->DB->transact(function ($db) {
$product = $db->newEntity();
$product->table('products');
$product->name = 'Šál zelený';
$product->price = 19.99;
$product->stock = 30;
$product->save(
function ($result, $db, $debug) {
$productId = $db->insertedId();
$description = $db->newEntity();
$description->table('product_descriptions');
$description->product_id = $productId;
$description->language = 'sk';
$description->description = 'Teplý zelený šál na zimu.';
$description->save(
null,
function ($error, $db, $debug) {
echo "Chyba pri ukladaní popisu: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri ukladaní produktu: {$error['error']}\n";
}
);
}, function ($result, $db, $debug) {
echo "Produkt 'Šál zelený' pridaný s popisom.\n";
}, function ($error, $db, $debug) {
echo "Chyba v transakcii: {$error['error']}\n";
});
11.2.3. Zobrazenie produktu s popismi
Získame produkt a jeho popisy pomocou hasMany.
$product = $DotApp->DB->return('ORM')->q(function ($qb) {
$qb->select('*', 'products')->where('id', '=', 1);
})->first(
function ($product, $db, $debug) {
$product->with('hasMany:product_descriptions');
$product->loadRelations(
function ($result, $db, $debug) {
echo "Produkt: {$product->name}, Cena: {$product->price} €\n";
foreach ($product->hasMany('product_descriptions', 'product_id') as $desc) {
echo "Popis ({$desc->language}): {$desc->description}\n";
}
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní popisov: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní produktu: {$error['error']}\n";
}
);
11.2.4. Vytvorenie objednávky
Vytvoríme novú objednávku pre používateľa a pridáme položky.
$DotApp->DB->transact(function ($db) {
$order = $db->newEntity();
$order->table('orders');
$order->user_id = 1;
$order->total_price = 35.98;
$order->status = 'pending';
$order->save(
function ($result, $db, $debug) {
$orderId = $db->insertedId();
$item = $db->newEntity();
$item->table('order_items');
$item->order_id = $orderId;
$item->product_id = 1;
$item->quantity = 2;
$item->price = 15.99;
$item->save(
function ($result, $db, $debug) {
$product = $db->return('ORM')->q(function ($qb) {
$qb->select('*', 'products')->where('id', '=', 1);
})->first(
function ($product, $db, $debug) {
$product->stock -= 2;
$product->save(
null,
function ($error, $db, $debug) {
echo "Chyba pri aktualizácii skladu: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní produktu: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri ukladaní položky: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri ukladaní objednávky: {$error['error']}\n";
}
);
}, function ($result, $db, $debug) {
echo "Objednávka vytvorená a sklad aktualizovaný.\n";
}, function ($error, $db, $debug) {
echo "Chyba v transakcii: {$error['error']}\n";
});
11.2.5. Zobrazenie objednávky s položkami
Získame objednávku a jej položky.
$order = $DotApp->DB->return('ORM')->q(function ($qb) {
$qb->select('*', 'orders')->where('id', '=', 1);
})->first(
function ($order, $db, $debug) {
$order->with('hasMany:order_items');
$order->loadRelations(
function ($result, $db, $debug) {
echo "Objednávka #{$order->id}, Celková cena: {$order->total_price}, Stav: {$order->status}\n";
foreach ($order->hasMany('order_items', 'order_id') as $item) {
$db->return('ORM')->q(function ($qb) use ($item) {
$qb->select('name', 'products')->where('id', '=', $item->product_id);
})->first(
function ($product, $db, $debug) use ($item) {
echo "Položka: {$product->name}, Množstvo: {$item->quantity}, Cena: {$item->price} €\n";
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní produktu: {$error['error']}\n";
}
);
}
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní položiek: {$error['error']}\n";
}
);
},
function ($error, $db, $debug) {
echo "Chyba pri načítaní objednávky: {$error['error']}\n";
}
);
11.3. Použitie validácie
Pridáme validáciu pre produkt pred uložením.
$product = $DotApp->DB->newEntity();
$product->table('products');
$product->setRules([
'name' => ['required', 'string', 'max:100'],
'price' => ['required', 'numeric', 'min:0'],
'stock' => ['integer', 'min:0']
]);
$product->name = 'Dlhý názov produktu, ktorý presahuje 100 znakov a je neplatný kvôli maximálnej dĺžke';
$product->price = -5;
$product->stock = 10;
$product->save(
function ($result, $db, $debug) {
echo "Produkt úspešne uložený.\n";
},
function ($error, $db, $debug) {
echo "Validácia zlyhala: {$error['error']}\n";
}
);
11.4. Poznámky k štúdii
Transakcie: Použitie transact() zaisťuje konzistenciu; error callbacky informujú o zlyhaniach.
Vzťahy:hasMany a eager loading (with()) zjednodušujú prácu s dátami, s chybovou kontrolou.
Validácia: Pravidlá chránia pred neplatnými dátami, s jasným hlásením chýb.
Chybová správa:error callbacky umožňujú používateľovi reagovať na problémy (napr. logovanie, upozornenia).
12. Tipy a triky
V tejto kapitole ponúkneme praktické rady, ako efektívne využívať Databaser v DotApp Frameworku. Zameriame sa na optimalizáciu dotazov, zabezpečenie bezpečnosti a možnosti rozšírenia.
12.1. Optimalizácia dotazov
Efektívne dotazy sú kľúčom k rýchlej aplikácii. Tu je niekoľko tipov:
Vyberajte len potrebné stĺpce: Namiesto select('*', 'users') používajte konkrétne stĺpce, napr. select('id, name', 'users'). Znižuje to objem prenesených dát.
$name = "Jano'; DROP TABLE users; --";
$DotApp->DB->q(function ($qb) use ($name) {
$qb->raw("SELECT * FROM users WHERE name = '$name'");
})->execute(); // Nebezpečné!
Surové dotazy s RAW: Ak používate raw(), vždy zadávajte hodnoty cez bindings:
$DotApp->DB->q(function ($qb) {
$qb->raw('SELECT * FROM users WHERE age > ?', [18]);
})->execute();
Validačné pravidlá v ORM: Pri ukladaní dát cez Entity nastavte pravidlá: