Doc:Dev/Jadro
Autor: Juraj Šimlovič
Vrstvy systému
Aplikácia webAlbumizer je rozdelená do štyroch samostatných vrstiev: databáza, vrstva entít, aplikačná vrstva, grafické rozhranie.
Databáza a vrstva entít
Databáza obsahuje tabuľky s výhradne základnými integritnými obmedzeniami a reláciami medzi tabuľkami. Priamo v databáze nie sú žiadne vložené procedúry, funkcie ani triggre.
Procedúry, funkcie a triggre sú implementované až vo vrstve entít, ktoré s databázovými tabuľkami pracujú a oddeľujú ich od daľších vrstiev. Dôvodom tohto prístupu bola predovšetkým slabá podpora procedúr a triggrov v MySQL v čase návrhu riešenia. Vrstva entít navyše poskytuje zapúzdrené API rozhranie k databáze. Aplikačná vrstva tak pristuje k datam vyhradne cez inštancie entít.
Aplikačná vrstva a grafické rozhranie
Aplikačná vrstva je od grafického rozhrania (tj. výstupu do prehliadača) oddelená predošetkým časovo. Pri každom požiadavku uživateľa sa najskôr vykonajú všetky potrebné operácie (napr. načítanie z databáze, úprava v databáze, odoslanie spáv a pod.); až potom sa generuje samotný výstup do prehliadača.
Keďže generovanie výstupu je vždy kompletne oddelené od spracovania požiadavku, je možné spracovávať akékoľvek požiadavky na pozadí a bez zbytočného výstupu. Eventuelne by bolo tiež možné implementovať rôzne druhy výstupných formátov (XHTML, XML, atd.) bez nutnosti akokoľvek upravovať aktuálnu aplikačnú logiku.
Jadro systému
Jadro aplikácie sa skladá zo štyroch základných častí: databáze, vrstvy entít, statickej a nestatickej časti systémových objektov .
Databáza
Aplikácia ukladá všetky (väčšinu) dáta do databáze. Táto databáza môže byť umiestnená i na inom stroji a komunikácia medzi aplikáciou a databázou používa jazyk SQL. Ku komunikácií pritom používa dve spojenia, jedno výhradne na čítanie a druhé na úpravy. Takýto prístup umožňuje napríklad použitie viacerých slave serverov (ktoré by replikovali dáta master serveru). Aplikácia samotná už však nerieši problém výberu vhodného slave/master serveru.
Statická časť
Statická časť jadra obsahuje predovšetkým triedy, ktoré nijak nesúvisia s aktuálne bežiacimi požiadavkami užívateľov. Sú to napríklad triedy obsluhujúce nastavenia systému; podporné triedy určené na validné generovanie výstupného XHTML formátu; ďalej triedy obsluhujúce dotazy do databáz; a nakoniec triedy poskytujúce preklad do rôznych jazykov.
Nestatická časť
Nestatická časť jadra obsahuje triedy, ktoré sú priamo závislé na aktuálne bežiacej požiadavke užívateľa (napr. zobrazenie zoznamu fotiek). Sú to napríklad triedy riadiace spracovanie požiadavky a následného grafického výstupu, ďalej triedy určené k spracovaniu vstupných dát; a v neposlednej rade i triedy určené k spracovaniu výstupných formátov.
Entity
Entity, vzhľadom na svoju úlohu v systéme patria v podstate jednak do nestatickej časti jadra a jednak do aplikačnej logiky. Ich primárnou a jedinou úlohou je oddeliť databázu od zvyšku aplikácie a zapuzdriť SQL volania do databáze v logických metódach.
Databáza
Návrh databázovej štruktúry vyplynul priamo z analýzy a počas vývoja projektu sme v ňom boli nútený robiť len minimálne zmeny. Do databáze sme nevkladali žiadne procedúry ani triggre. Logiku nad možnosti základných dátových obmedzení sme vždy delegovali do vrstvy entít.
Kompletná štruktúra databáze je uvedená prehľadne v kóde triedy InstallMakeDB a je pomerne obšírna, pretože tabuľky obsahujú množstvo stĺpcov nepodstatných atribútov (name, description, location, atd).
Skrátená verzia databázovej štruktúry, v ktorej sú ponechané iba skutočne významné stĺpce (ako sú napríklad primárne a cudzie kľúče, prípadne vyhľadávacie kľúče) je nasledovná:
table_user
Tabuľka všetkých užívateľov.
`uid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `login` VARCHAR UNIQUE KEY NOT NULL, `state` ENUM('waiting-mail', 'waiting-approval', 'approved', 'banned') NOT NULL DEFAULT 'waiting-mail', INDEX (`state`), `session` VARCHAR UNIQUE KEY, `photo` INT UNSIGNED REFERENCES table_photo (pid) ON DELETE SET NULL, INDEX (`photo`),
table_user_settings
Tabuľka nastavení a oprávnení užívateľov. Dôvodom na oddelenie užívateľov od ich nastavení bolo veľké množstvo stĺpcov. Tabuľka užívateľov predstavuje atribúty, podľa ktorých sa dá filtrovať a triediť. Naopak tabuľka user_settings obsahuje dáta, ktoré sú podstatné len pre aktuálne prihláseného užívateľa.
`user` INT UNSIGNED PRIMARY KEY REFERENCES table_user (`uid`) ON DELETE CASCADE,
table_password
Tabuľka hesiel užívateľov. Nemá primárny kľúč, pretože užívateľ si môže to isté heslo definovať teoreticky i viac krát.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `passwd` CHAR(32) NOT NULL, INDEX (`user`, `passwd`), `once` BOOL NOT NULL,
table_friend
Tabuľka priateľov.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `friend` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, PRIMARY KEY (`user`, `friend`),
table_enemy
Tabuľka nepriateľov.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `enemy` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, PRIMARY KEY (`user`, `enemy`),
table_mail
Tabuľka neodoslaných mailov.
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, INDEX (`user`),
table_image
Tabuľka obrázkov a ich originálnych dát. Po úspešnom uploade súboru sa vždy nahrajú originálne dáta do tejto tabuľky a zostávajú tak v databáze, nie mimo nej (napr. v súborovom systéme).
`iid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `md5` CHAR(32) NOT NULL, `md5ex` INT UNSIGNED NOT NULL, UNIQUE INDEX (`md5`, `md5ex`), `data` LONGBLOB NOT NULL,
table_photo
Tabuľka fotiek. Tabuľka fotiek replikuje niektoré z informačných stĺpcov (widht, height, size, type), aby nebolo nutné prehľadávať i tabuľku image, keď sa vyhľadáva a filtruje vo fotkách.
`pid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `owner` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE CASCADE, INDEX (`owner`), `image` INT UNSIGNED NOT NULL REFERENCES table_image (`iid`) ON DELETE CASCADE, INDEX (`image`),
table_photo_tag
Tabuľka tagov fotiek.
`photo` INT UNSIGNED NOT NULL REFERENCES table_photo (pid) ON DELETE CASCADE, `tag` VARCHAR NOT NULL, PRIMARY KEY (`photo`, `tag`),
table_photo_preview
Tabuľka zmenšených náhľadov na fotky. Tabuľka obsahuje dáta zmenšených obrázkov, pokial zápis do filesystému nie je možný. Zmenšené obrázky sa v takom prípade vždy ukladajú a čítajú z databáze.
`photo` INT UNSIGNED NOT NULL REFERENCES table_photo (pid) ON DELETE CASCADE, `watermark` BOOL NOT NULL, `resolution` INT UNSIGNED NOT NULL, PRIMARY KEY (`photo`, `watermark`, `resolution`), `data` LONGBLOB,
table_group_category
Tabuľka kategórií skupín.
`gcid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `parent` INT UNSIGNED REFERENCES table_group_category (`gcid`) ON DELETE RESTRICT, `name` VARCHAR NOT NULL, UNIQUE KEY (`parent`, `name`), `icon` INT UNSIGNED REFERENCES table_photo (`pid`) ON DELETE SET NULL, INDEX (`icon`),
table_group
Tabuľka skupín.
`gid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `category` INT UNSIGNED NOT NULL REFERENCES table_group_category (`gcid`) ON DELETE RESTRICT, INDEX (`category`), `owner` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, INDEX (`owner`), `icon` INT UNSIGNED REFERENCES table_photo (`pid`) ON DELETE SET NULL, INDEX (`icon`), `name` VARCHAR UNIQUE KEY NOT NULL,
table_group_member
Tabuľka členov skupín. Vyjadruje reláciu m:n medzi užívateľmi a skupinami.
`group` INT UNSIGNED NOT NULL REFERENCES table_group (`gid`) ON DELETE CASCADE, `user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, PRIMARY KEY (`group`, `user`), INDEX (`user`),
table_album_directory
Tabuľka adresárov albumov.
`adid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `parent` INT UNSIGNED REFERENCES table_album_directory (`adid`) ON DELETE RESTRICT, `name` VARCHAR NOT NULL, UNIQUE KEY (`parent`, `name`), `icon` INT UNSIGNED REFERENCES table_photo (`pid`) ON DELETE SET NULL, INDEX (`icon`),
table_album
Tabuľka albumov.
`aid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `directory` INT UNSIGNED NOT NULL REFERENCES table_album_directory (`adid`) ON DELETE RESTRICT, INDEX (`directory`), `owner` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, INDEX (`owner`), `icon` INT UNSIGNED REFERENCES table_photo (`pid`) ON DELETE SET NULL, INDEX (`icon`), `name` VARCHAR NOT NULL, INDEX (`directory`, `name`),
table_album_photo
Tabuľka fotiek pridaných do albumov. Vyjadruje reláciu m:n medzi fotkami a albumami.
`album` INT UNSIGNED NOT NULL REFERENCES table_album (`aid`) ON DELETE CASCADE, `photo` INT UNSIGNED NOT NULL REFERENCES table_photo (`pid`) ON DELETE CASCADE, PRIMARY KEY (`photo`, `album`),
table_album_group
Tabuľka skupín priradených k albumom.Vyjadruje reláciu m:n medzi albumami a skupinami.
`album` INT UNSIGNED NOT NULL REFERENCES table_album (`aid`) ON DELETE CASCADE, `group` INT UNSIGNED NOT NULL REFERENCES table_group (`gid`) ON DELETE CASCADE, PRIMARY KEY (`group`, `album`), INDEX (`album`),
table_photo_comment
Tabuľka komentárov k fotkám.
`cid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `thread` INT UNSIGNED REFERENCES table_photo_comment (`cid`) ON DELETE RESTRICT, INDEX (`thread`), `parent` INT UNSIGNED REFERENCES table_photo_comment (`cid`) ON DELETE RESTRICT, INDEX (`parent`), `photo` INT UNSIGNED NOT NULL REFERENCES table_photo (`pid`) ON DELETE CASCADE, INDEX (`photo`), `user` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE SET NULL, INDEX (`user`),
table_group_discussion
Tabuľka diskusných príspevkov v skupinách.
`cid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `thread` INT UNSIGNED REFERENCES table_photo_comment (`cid`) ON DELETE RESTRICT, INDEX (`thread`), `parent` INT UNSIGNED REFERENCES table_group_discussion (`cid`) ON DELETE RESTRICT, INDEX (`parent`), `group` INT UNSIGNED NOT NULL REFERENCES table_group (`gid`) ON DELETE CASCADE, INDEX (`group`), `user` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE SET NULL, INDEX (`user`),
table_album_discussion
Tabuľka diskusných príspevkov v albumoch.
`cid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `thread` INT UNSIGNED REFERENCES table_photo_comment (`cid`) ON DELETE RESTRICT, INDEX (`thread`), `parent` INT UNSIGNED REFERENCES table_album_discussion (`cid`) ON DELETE RESTRICT, INDEX (`parent`), `album` INT UNSIGNED NOT NULL REFERENCES table_album (`aid`) ON DELETE CASCADE, INDEX (`album`), `user` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE SET NULL, INDEX (`user`),
table_photo_notification
Tabuľka notifikácií na fotkách.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `photo` INT UNSIGNED NOT NULL REFERENCES table_photo (`pid`) ON DELETE CASCADE, PRIMARY KEY (`user`, `photo`), INDEX (`photo`),
table_group_notification
Tabuľka notifikácií na skupinách.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `group` INT UNSIGNED NOT NULL REFERENCES table_group (`gid`) ON DELETE CASCADE, PRIMARY KEY (`user`, `group`), INDEX (`group`),
table_album_notification
Tabuľka notifikácií na albumoch.
`user` INT UNSIGNED NOT NULL REFERENCES table_user (`uid`) ON DELETE CASCADE, `album` INT UNSIGNED NOT NULL REFERENCES table_album (`aid`) ON DELETE CASCADE, PRIMARY KEY (`user`, `album`), INDEX (`album`),
table_ugly
Tabuľka nevhodného obsahu. Tabuľka je schopná spájať objekty ako nevhodný obsah (napríklad fotka je nevhodná iba v konkrétnom albume).
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `user` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE CASCADE, INDEX (`user`), `photo` INT UNSIGNED REFERENCES table_photo (`pid`) ON DELETE CASCADE, INDEX (`photo`), `group` INT UNSIGNED REFERENCES table_group (`gid`) ON DELETE CASCADE, INDEX (`group`), `album` INT UNSIGNED REFERENCES table_album (`aid`) ON DELETE CASCADE, INDEX (`album`), `reporter` INT UNSIGNED REFERENCES table_user (`uid`) ON DELETE SET NULL, INDEX (`reporter`),
table_hash
Tabuľka slúžiaca na ukladanie hodnôt za ich alebo nahodné hashe.
`hash` VARCHAR(255) PRIMARY KEY, `str` VARCHAR(255)
Entity
Vrstva entít zabezpečuje komunikáciu medzi databázou a aplikačnou vrstvou systému. Okrem dvoch statických entít (Password a PhotoTag) a jednej pomocnej entity (Storage). Sú všetky ostatné koncipované rovnakým spôsobom:
- Definujú konštanty reprezentujúce podporované hodnoty atribútov; podporované hodnoty filtrov; a podporované hodnoty triedení.
- napr. APPROVED, BANNED, SUGGESTED ako stavy albumu.
- napr. FILTER_NAME, FILTER_OWNER ako filtre fotiek.
- napr. SORTBY_NAME, SORTBY_OWNER ako triedenia fotiek.
- Ponúkajú atribúty reprezentujúce stĺpce v príslušnej tabuľke.
- napr. $name, $description, $author u fotky.
- Ponúkajú zapúzdrený prístup k reláciám nad tabuľkami, tj. k asociovaným entitám.
- napr. GetParent(), SetParent() u adresáru.
- napr. HasOwner(), GetOwner(), SetOwner() u fotky.
- Doplňujú metódy počítajúce dodatočné informácie nad atribútmi s tabuľky.
- napr. GetDisplayableName() u užívateľa, ktorá hľadá zobraziteľné meno.
- napr. GetScore() u fotky, ktorá počíta priemer známok.
- Doplňujú metódy overujúce oprávnenia užívateľa nad danou entitou.
- napr. CanView(), CanEdit(), CanDelete(), CanComment() u fotky.
- Poskytujú zapúzdrené a inteligentné metódy na úpravu dát databáze.
- napr. generické Insert(), Update(), Delete().
- napr. špecializované UpdateSession(),UpdateState().
- Poskytujú zapúzdrené metódy na načítanie entít z databáze.
- napr. LoadById(), LoadByOwner(), LoadByFilter().
- Poskytujú zapúzdrené metódy na počítanie entít v databáze.
- napr. CountByOwner(), CountByFilter().
- Automaticky používajú cache na načítané entity
- napr. Dve prekrývajúce sa požiadavky na dáta z databáze generujú iba jeden skutočný SQL dotaz. Napríklad pokiaľ LoadByOwner() načíta entitu s nejakým ID, tak LoadById() je potom túto entitu schopné vrátiť z lokálnej cache bez ďalšieho prístupu do databáze.
Dátové štruktúry a zapúzdrennie
Vďaka tomu, že entity jasne definujú štruktúru objektov z databáze, celá aplikačná logika používa tieto entity ako dátové štruktúry na vzájomnú komunikáciu. Vďaka zapúzdrenosti relácií nad tabuľkami do metód je pre aplikačnú logiku možné použiť pomerne jednoduché$group->GetOwner()->GetProfilePhoto()->GetImage()->GetData();
Poznámka: Password a PhotoTag nie sú koncipované ako ostatné entity predovšetkým pre svoju funkčnú odlišnosť od ostatných entít. Password napríklad neposkytuje LoadyBy() ani Update() metódy, ale Verify(), ktorá napríklad automaticky maže jednorazové heslá po ich úspešnom overení. U PhotoTag triedy je zase zbytočné vytvárať entitu ako objekt, keď je tag v skutočnosti iba jednoduchý reťazec znakov.
Poznámka: Trieda Storage sa na entitu v mnohom podobá, neobsahuje však žiadne metódy na úpravu dát v databáze, keďže žiadna tabuľka storage v skutočnosti neexistuje. Storage je len abstrakciou zodpovednosti a funkcionality nad pojmom photo storage, čo je v skutočnosti množina entít v tabuľke fotiek, patriacich rovnakému užívateľovi.
EntryPoint, Body, Page, SubPage
O spracovanie požiadavku užívateľa sa starajú triedy implementujúce interface EntryPoint a Body. Spojenie týchto interface je v triede Page, ktorá tvorí základ každej našej užívateľské požiadavky spracúvajúcej triedy.
EntryPoint, Body
EntryPoint je interface, ktorý definuje tzv. vstupný bod do aplikácie. Jednotlivé vstupné body sú navonok reprezentované URL adresami, na ktoré užívateľ cez prehliadač posiela svoje požiadavky. EntryPoint samotný nemá žiadne metódy, ale predpisuje konvenciu na statické metódy MakeLink(), ktoré majú za úlohu vytvoriť linku na samého seba.
Body je naopak interface, ktorý definuje výstupný bod z aplikácie, tj. miesto, kde sa spracuje užívateľská požiadavka a následne sa vygeneruje výstup do prehliadača. Body definuje dve metódy, a to Run() a Display(). Prvá z nich je určená k spracovaniu požiadavku; druhá zas naopak ku generovaniu výstupu.
Page, SubPage
Tieto dva interface (EntryPoint a Body) sú spojené v jednej abstraktnej triede Page, ktorá pre jednotlivé stránky pripravuje prostredie. Potomkovia triedy Page implementujú jednak statické vytváranie liniek (URL) na seba a jednak implementujú rutiny na obslúženie požiadaviek, ktoré tie linky predstavujú. Inými slovami, každý potomok triedy Page je zodpovedný jak za vytvorenie linky na akcie, ktoré poskytuje a jednak za ich následné obslúženie.
Špeciálnym typom stánok sú tzv. podstránky (obvykle sú to napr. editačné formuláre a pod.), ktoré nemajú vlastný EntryPoint. Tieto fungujú ako samostatné komponenty, ktoré poskytujú volajúcim stránkam istú vopred definovanú funkčnosť (napríklad zobrazenie editačného formuláru a následné uloženie dát do databáze). Tieto podstránky majú spoločného predka SubPage, ktorý implementuje iba interface Body.
Request, Link, PATH_INFO
Základný stavebný prvok pre linkovanie medzi stránkami tvorí dvojica tried Link a Request. Tá prvá ma na starosti vytváranie (na pohľad pokiaľ možno príjemných, ale zároveň) parametrizovaných URL, ktoré využívajú technológie ako PATH_INFO a pod. Request na druhej strane takúto URL po prijatí od prehliadača rozoberie na pôvodné parametre.
Význam použitia týchto objektov spočíva predovšetkým v netriviálnosti používania polí v rámci URL, ktoré pre nás boli často nevyhnutné (napr. formuláre položiek s checkboxami u každej položky). Druhou nie menej významnou úlohou je jednotné skrášľovanie týchto URL použitím dynamických PATH_INFO.
PATH_INFO je rozšírenie web serveru Apache (i ďalších web serverov), ktoré umožňuje za názvom skutočného súboru stránky špecifikovať sub-cestu, ktorá v skutočnosti už neexistuje; a to i bez použitia rozšírení ako mod_rewrite (rovnako rozšírenie Apache, umožňujúce programovateľné prepisovanie URL na iné URL).
Jednoduchým príkladom takejto PATH_INFO je URL http://example.com/dir/script.php, v ktorej /dir/script.php je skutočne existujúca stránka, a /path/info je doplňujúca cesta, presnejšie postupnosť znakov, ktorá v samotnom súborovom systéme neexistuje. Táto technológia je napríklad využitá v známom projekte wikipédia.
Link, Request
Trieda Link dokáže napríklad miesto URI tvaru /index.php?action=list&type=public&page=2 vygenerovať výrazne jednoduchšiu URI v tvare /index.php/list/public/2. K tomu využíva tzv. pathInfoMap, ktoré dodá vždy cieľová stránka (viď interface EntryPoint v predošlej kapitole). Táto pathInfoMap špecifikuje poradie a význam jednotlivých PATH_INFO častí. Prípadné ďalšie parametre, ktoré nie sú v pathInfoMap obsiahnuté sa do linky potom zakomponujú štandardným CGI spôsobom (tj. ...?name=value).
Je očividné, že druhom prípade sa z URI stratili informácie o názvoch parametrov. To však v skutočnosti nie je úplne pravda, pretože z poradia tých parametrov sa dá ich význam v čase potreby spätne rekonštruovať. Preto na druhej strane cieľová stránka použije triedu Request, poskytne mu ten istý pathInfoMap, Request podľa neho rozoberie PATH_INFO a následne vráti stránke k požadovanému parametru skutočnú hodnotu.
pathInfoMap
Jednotlivé stránky si pathInfoMap volia sami. Komunikácia parametrov medzi stránkami i v rámci stránky samotnej je viazaná výhradne na mená parametrov, takže zmena v definícií pathInfoMap by nemala nikdy vyžadovať úpravu ďalšieho kódu.
Na druhú stranu, samotné pathInfoMap sledujú hierarchiu stránok a podstránok. Niektoré stránky napríklad definujú význam prvého PATH_INFO parametru a až jej podstránky sú zodpovedné za definíciu ďalších zložiek výslednej pathInfoMap. Takto je možné, aby vedľa seba koexistovali dve rozdielne stránky a jedna využívala URI typu /index.php/albums/list/$page, a druhá URI typu /index.php/ albums/detail/$id, pričom časť /index.php/albums/ je definovaná i obsluhovaná spoločnou nad stránkou.
Output a Errors
Za riadenie výstupu je zodpovedná predovšetkým trieda Output. Táto ma jednak na starosti prácu z tzv. skinmi (popísané v ďalších kapitolách) a jednak má na starosti dohliadanie na samotný požadovaný formát výstupu.
Je to predovšetkým informačná trieda, obsahujúca množstvo nastaviteľných atribútov, nevynímajúc možnosti nastavenia automatického HTTP presmerovania, nastavovanie cookies, kódovanie stránky či titulok stránky. Obsluhuje i tzv. QuickBoxy (popísané v ďalších kapitolách).
Errors
Súčasťou triedy Output je trieda Errors, ktorá slúži na automatizované zobrazovanie správ pre užívateľa. Takéto správy sa delia na 5 typov: NOTICE, WARNING, ERROR, FATAL a QUESTION. Doplňujúcim typom je typ DEBUG, ktorý okrem samotnej správy prikladá i aktuálny back-trace k danej správe. Typ QUESTION okrem textu obsahuje i tlačítka (napríklad YES, NO, CANCEL).
Automatizované spracovanie užívateľských správ má výhody napríklad v tom, že všetky správy pre užívateľa majú rovnaký (resp. podobný) vzhľad a rovnaké umiestnenie na výstupnej stránke, ktoré je ďalej upravované konkrétnym skinom stránky (popísané v ďalších kapitolách). Samotná trieda Errors poskytuje stránkam tiež automatickú obsluhu prekladu do jazykov (stránka zadá iba číslo správy, ktorá sa má preložiť).
Exceptions
Chyby v systéme, či už chyby užívateľského charakteru, alebo fatálne chyby ako napríklad nedostupná databáza, sú ošetrované systémom typových výnimiek. Tieto výnimky môžu triedy spracovávajúce aktuálnu požiadavku odchytávať sami a reagovať podľa potreby. Neodchytené výnimky sa potom automaticky zachytávajú na úrovni triedy Process, kde sa z nich generujú užívateľsky zrozumiteľné chybové hlásenia.
Hierarchia výnimiek je nasledovná:
- DevException – najviac všeobecná výnimka obvykle používaná na testovanie.
- DBException – všeobecná výnimka spôsobená chybou z databáze.
- DBDuplicateException – výnimka spôsobená chybou na UNIQUE kľúčoch.
- MsgException – všeobecná výnimka obsahujúca správu chybového hlásenia.
- ErrorMsgException – výnimka obsahujúca správu o užívateľskej chybe.
- AccessDeniedException – výnimka obsahujúca správu o nepovolenom prístupe.
- NotFoundException – výnimka obsahujúca správu o chýbajúcich dátach.
- FatalMsgException – výnimka obsahujúca správu o fatálnej chybe.
- InternalErrorException – výnimka obsahujúca správu o fatálnej chybe na úrovni zdrojového kódu (užívateľ pravdepodobne našiel bug v našom kóde).
- MalformedRequestException – výnimka obsahujúca správu o fatálnej chybe spôsobenej užívateľom a jeho manipuláciou s URL adresami. Túto výnimku sme dali do kategórie fatálnych chýb predovšetkým kvôli navýšeniu bezpečnosti. Fatálne chyby sa totiž odchytávajú výhradne na úrovni procesu. Tým je zaručené, že po fatálnej chybe sa už systém nebude pokúšať niečo vykonávať.
- MistakeMsgException – výnimka obsahujúca správu o chybe či neúspešnosti požadovanej akcie z dôvodu odstrániteľných príčin.
- ActionFailedException - výnimka obsahujúca správu o chybe či neúspešnosti požadovanej akcie z dôvodu odstrániteľných príčin. Takou príčinou môže byť napríklad špatne vyplnený formulár alebo nesprávne zadané heslo.
- ErrorMsgException – výnimka obsahujúca správu o užívateľskej chybe.
- DBException – všeobecná výnimka spôsobená chybou z databáze.
Debug
Trieda Debug nám počas vývoja projektu významne pomáhala pri hľadaní chýb. Vzhľadom k tomu, že pre jazyk PHP neexistuje veľa nástrojov určených na podobné účely (breakpointy a pod.), vytvorili sme si vlastný spôsob, ktorého hlavným bodom bola tvorba trace súboru. Takýto trace súbor obsahoval informácie o tom, čo a v akom čase kód približne vykonával, aké triedy k tomu potreboval načítať, aké SQL dotazy boli posielané do databáze a pod.
Zjednodušený príklad trace súboru:
cookie[__foto_foto_session] = "b3d87e084d3179e41d265d510e377a7d"
path[0] = "intro"