Na tomto místě bude oficiální zadání vaší práce • Toto zadání je podepsané děkanem a vedoucím katedry, • musíte si ho vyzvednout na studiijním oddělení Katedry počítačů na Karlově náměstí, • v jedné odevzdané práci bude originál tohoto zadání (originál zůstává po obhajobě na katedře), • ve druhé bude na stejném místě neověřená kopie tohoto dokumentu (tato se vám vrátí po obhajobě).
i
ii
České vysoké učení technické v Praze Fakulta elektrotechnická Katedra počítačové grafiky a interakce
Bakalářská práce
Implementační rozdíly ve vývoji IS při použití bezschémové a relační databáze Antonín Daněk
Vedoucí práce: Ing. Martin Kákona
Studijní program: Softwarové technologie a management, Bakalářský Obor: Web a multimedia 25. května 2011
iv
v
Poděkování Chtěl bych poděkovat především rodičům, za umožnění studia a tedy i napsání této práce. Dále také sestře za konzultace gramatické stránky práce a přátelům, kteří tolerovali značné omezení mého volného času. Děkuji také vedoucímu mé bakalářské práce Ing. Martinu Kákonovi, za jeho konzultace a benevolentní přístup.
vi
vii
Prohlášení Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých zákonů (autorský zákon).
V Praze dne 19. 5. 2011
.............................................................
viii
Abstract This thesis addresses comparison of a typical relational database with non-relational one while it focuses on non-relational database MongoDB. The practical result of the work is an information system based on Google Maps. Realization of the system is also described in the work. This system is used to demonstrate how the implementation for individual databases vary, and it is also shown how to minimize these differences.
Abstrakt Tato bakalářská práce se zabývá srovnáním typické relační databáze s databází bezschémovou, detailněji se při tom zaměřuje na bezschémovou databázi MongoDB. Praktickým výsledkem práce je informační systém založený na Google Maps, jehož realizace je v práci též popsána. Na tomto systému je demonstrováno, jak se implementace pro jednotlivé databáze liší a též je ukázána cesta, jak tyto odlišnosti minimalizovat.
ix
x
Obsah
1 Úvod
1
1.1
2
Struktura bakalářské práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Popis problému, specifikace cíle 2.1
Požadavky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.1.1
Funkční požadavky . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.1.1.1
Požadavky týkající se uživatele . . . . . . . . . . . . . . . . .
3
2.1.1.2
Požadavky týkající se pozorovacích míst a událostí . . . . . .
4
2.1.1.3
Ostatní funkční požadavky . . . . . . . . . . . . . . . . . . .
4
Nefunkční požadavky . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Srovnání existujících řešení . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2.1
Řešení v českém jazyce . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2.1.1
astro.cz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2.1.2
astro-forum.cz . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.2.1.3
astronomie.cz . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.2.1.4
vesmir.info . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
Řešení v anglickém jazyce . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.1.2 2.2
3
2.2.2
xi
xii
OBSAH
2.2.2.1
astronomy.com . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2.2.2
ostatní . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
3 Analýza technologií pro implementaci 3.1
Diskuse relačních a bezschémových databází . . . . . . . . . . . . . . . . . . .
9
3.1.1
9
3.1.2
3.2
9
Úvod do bezschémových databází – MongoDB
. . . . . . . . . . . . .
3.1.1.1
Vlastnosti MongoDB
. . . . . . . . . . . . . . . . . . . . . . 11
3.1.1.2
Denormalizovaná databáze . . . . . . . . . . . . . . . . . . . 12
3.1.1.3
Rychlost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.1.4
Škálovatelnost . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.1.5
Základní příkazy . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1.1.6
Vkládání dat . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1.1.7
Čtení dat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.1.1.8
Upravování dat . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1.1.9
Mazání dat . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Srovnání relačních a bezschémových databází . . . . . . . . . . . . . . 18 3.1.2.1
Množství dat . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.2.2
Rychlost a horizontální škálování . . . . . . . . . . . . . . . . 19
3.1.2.3
Křivka učení, rozšířenost a dospělost . . . . . . . . . . . . . . 19
3.1.2.4
Dostupnost a cena . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2.5
Flexibilní schéma a interakce s daty . . . . . . . . . . . . . . 20
3.1.2.6
Transakce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2.7
Normalizace dat a konzistence . . . . . . . . . . . . . . . . . 20
Výběr technologií pro implementaci . . . . . . . . . . . . . . . . . . . . . . . . 20
OBSAH
xiii
3.2.1
Výběr hlavní databáze . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.2
Výběr ostatních technologií . . . . . . . . . . . . . . . . . . . . . . . . 21
4 Realizace 4.1
Model-View-Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4.1.1
4.2
Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4.1.1.1
Zaměnitelnost datové vrstvy . . . . . . . . . . . . . . . . . . 23
4.1.1.2
Připojení k MySQL . . . . . . . . . . . . . . . . . . . . . . . 24
4.1.1.3
Připojení k MongoDB . . . . . . . . . . . . . . . . . . . . . . 24
4.1.1.4
Business objekty . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.1.2
View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.1.3
Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Implementace Data Access Objektů . . . . . . . . . . . . . . . . . . . . . . . . 26 4.2.1
4.2.2
4.3
23
Implementace DAO pro MySQL . . . . . . . . . . . . . . . . . . . . . 27 4.2.1.1
Metoda getSpotsCreatedBy . . . . . . . . . . . . . . . . . . . 27
4.2.1.2
Metoda createNewUser . . . . . . . . . . . . . . . . . . . . . 27
4.2.1.3
Metoda addAttendingUserToEvent . . . . . . . . . . . . . . . 27
Implementace DAO pro MongoDB . . . . . . . . . . . . . . . . . . . . 27 4.2.2.1
Metoda getSpotsCreatedBy . . . . . . . . . . . . . . . . . . . 27
4.2.2.2
Metoda createNewUser . . . . . . . . . . . . . . . . . . . . . 27
4.2.2.3
Metoda addAttendingUserToEvent . . . . . . . . . . . . . . . 28
Některé další prvky implementace . . . . . . . . . . . . . . . . . . . . . . . . . 28 4.3.1
Formuláře . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 4.3.1.1
Životní cyklus formulářů
. . . . . . . . . . . . . . . . . . . . 28
xiv
OBSAH
4.3.2
Dynamicky generovaný JavaScript . . . . . . . . . . . . . . . . . . . . 29
4.3.3
Dynamicky generované XML . . . . . . . . . . . . . . . . . . . . . . . 29
4.3.4
Práce s Google Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.3.4.1
zobrazení značek na mapě . . . . . . . . . . . . . . . . . . . . 30
4.3.4.2
Vložení značky na mapu . . . . . . . . . . . . . . . . . . . . . 30
4.3.5
Práce s GPS souřadnicemi . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.3.6
Načítání nejbližších pozorovacích míst – AJAX . . . . . . . . . . . . . 31
4.3.7
Komponenty jQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.3.8
Tvorba multimediálních záznamů z pozorování . . . . . . . . . . . . . 31
4.3.9
4.3.8.1
Obrázky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.3.8.2
YouTube videa . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Profilové fotografie – popup okna a cache . . . . . . . . . . . . . . . . 32
4.3.10 Ukládání hesel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.4
Model nasazení . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5 Testování
35
5.1
Akceptační test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2
Test validity HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.3
Test kognitivním průchodem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 5.3.1
Založení nového místa . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.3.2
Založení nové události na určitém místě . . . . . . . . . . . . . . . . . 36
5.3.3
Přidání místa mezi oblíbené . . . . . . . . . . . . . . . . . . . . . . . . 36
5.3.4
Přidání komentáře k pozorovacímu místu . . . . . . . . . . . . . . . . 36
5.3.5
Přidání záznamu z pozorování k události . . . . . . . . . . . . . . . . . 37
OBSAH
xv
5.3.6
Přihlášení se k účasti u události . . . . . . . . . . . . . . . . . . . . . . 37
5.3.7
Uložení výchozí pozice mapy . . . . . . . . . . . . . . . . . . . . . . . 37
5.3.8
Výsledky kognitivních průchodů . . . . . . . . . . . . . . . . . . . . . 37
6 Závěr 6.1
39
Shrnutí výsledků a zhodnocení splnění cílů . . . . . . . . . . . . . . . . . . . . 39 6.1.1
Srovnání relačních a bezschémových databází . . . . . . . . . . . . . . 39
6.1.2
Implementace informačního systému pro JihoČAS
6.1.3
Rozdíly v implementaci při použití bezschémové databáze . . . . . . . 39
6.1.4
Otestování implementovaného systému . . . . . . . . . . . . . . . . . . 40
. . . . . . . . . . . 39
6.2
Zhodnocení přínosu práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.3
Zamyšlení se nad použitelností bezschémových databází . . . . . . . . . . . . 40
6.4
Další možné pokračování práce . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A Seznam použitých zkratek
45
B UML diagramy
47
C Ukázky zdrojových kódů
49
D Výsledky akceptačního testu
57
E Instalační a uživatelská příručka
61
E.1 Instalační příručka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 E.1.1 PHP + MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 E.1.2 MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 E.1.3 Nahrání souborů na server . . . . . . . . . . . . . . . . . . . . . . . . . 61
xvi
OBSAH
E.1.4 Konfigurace aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 E.2 Uživatelská příručka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 E.2.1 Administrace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
F Obsah přiloženého CD
65
Seznam obrázků
2.1
Ukázka obsahu a UI webu astro-forum.cz – kategorie Astronomická setkání . .
6
3.1
Přibližné zobrazení závislosti výkonu na funkcionalitě čtyř systémů - zdroj: [21]. 11
3.2
Znázornění, jak jednotlivé SQL funkce odpovídají nástroji MapReduce – zdroj: [19]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.1
UML diagram pro DaoFactory a jím vracené DAO objekty (z úsporných důvodů je zobrazeno pouze několik DAO tříd a pouze některé metody) . . . . . 24
4.2
UML diagram systému controllerů (z úsporných důvodů jsou zobrazeny pouze některé) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.3
UML diagram modelu nasazení . . . . . . . . . . . . . . . . . . . . . . . . . . 33
B.1 Grafické znázornění adresářové struktury aplikace . . . . . . . . . . . . . . . . 47
E.1 Ukázka úvodní stránky aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . 63 E.2 Ukázka profilové stránky uživatele . . . . . . . . . . . . . . . . . . . . . . . . . 63 E.3 Ukázka stránky pozorovacího místa . . . . . . . . . . . . . . . . . . . . . . . . 64 E.4 Ukázka stránky události . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
xvii
xviii
SEZNAM OBRÁZKŮ
Seznam tabulek
3.1
Různé typy bezschémových databází. Tabulka čerpá především z článku [23].
10
3.2
Výsledky testu rychlosti vložení milionu záznamů (každý záznam měl tři hodnoty včetně generovaného ID) na stolním počítači. [3] . . . . . . . . . . . . . . 13
3.3
Základní komponenty databází MySQL a MongoDB, které sobě přibližně odpovídají. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
D.1 Akceptační test požadavků týkajících se uživatele . . . . . . . . . . . . . . . . 58 D.2 Akceptační test požadavků týkajících se pozorovacích míst a událostí . . . . . 59 D.3 Akceptační test ostatních požadavků . . . . . . . . . . . . . . . . . . . . . . . 59
xix
xx
SEZNAM TABULEK
Kapitola 1
Úvod Lidé, zabývající se astronomií (ať už amatérsky či profesionálně), jsou poměrně decentralizovaní. Často se tak stává, že ten samý objekt pozorují jednotliví astronomové odděleně, připravujíce se tak o sociální prvky takových událostí a možnost sdílet vybavení či znalosti. V horším případě právě z důvodu absence vybavení nepozorují vůbec. Především výše zmíněné bylo motivací k vytvoření informačního systému (sociální sítě), který bude astronomům pomáhat organizovat pozorování. Současně se práce zabývá srovnáním bezschémových databází s relačními, a to především z pohledu implementace aplikace. V současnosti zaznamenává velký rozvoj tzv. cloud computing1 a distribuované služby. Pokud chceme cloud využít, obvykle se nevyhneme také bezschémovým databázím. Mnoho programátorů má však z opuštění ověřených relačních databází obavy. Jedním z cílů této práce je zjistit, zda jsou tyto obavy oprávněné. Práce popisuje všechny fáze tvorby systému od specifikace cíle, přes technologickou analýzu a samotnou implementaci, až po otestování a zhodnocení výsledků.
1
Cloud computing je definovaný především poskytováním zdrojů (jako je výpočetní výkon či datový prostor) na požádání. Jednou z výhod tohoto přístupu je, že provozovatel aplikace platí pouze za výkon, jaký jeho aplikace opravdu využívá a navíc růst počtu uživatelů a s ním požadavek na více výkonu nepředstavuje problém.
1
2
1.1
KAPITOLA 1. ÚVOD
Struktura bakalářské práce
V kapitole Popis problému, specifikace cíle (2) je popsán řešený problém a především jsou zde specifikovány funkční i nefunkční požadavky na výsledný systém. Dále se zde nachází analýza současných řešení stejného problému. V následující kapitole Analýza technologií pro implementaci (3) je čtenář nejdříve uveden do základů relačních a bezschémových databází. Základní informace jsou následovány srovnáním obou databází a výběrem hlavní databáze pro implementaci. Kromě databáze je proveden i výběr dalších technologií. Navazuje kapitola Realizace (4), která tvoří spolu s analýzou nejdůležitější část práce. Kromě ostatních důležitých částí zdrojového kódu, ukazuje rozdílnost implementace systému pro relační a pro bezschémovou databázi. Testování aplikace je zdokumentováno v kapitole Testování (5). Především je zde akceptačním testem ověřeno splnění všech požadavků. Navazuje ověření validnosti výstupu systému a několik testů provedených kognitivním průchodem. Zhodnocení práce spolu s možnostmi dalšího rozšíření systému je možno nalézt v poslední kapitole – Závěr (6).
Kapitola 2
Popis problému, specifikace cíle Cílem projektu je vytvořit webovou aplikaci pro Jihočeskou pobočku České astronomické společnosti s využitím Google Maps (http://code.google.com/apis/maps/index.html). Aplikace bude sloužit jako mezičlánek pro amatérské a profesionální astronomy. Lidé se budou moci scházet na vytvořených pozorovacích místech a mimo jiné tak sdílet své vybavení. V aplikaci pak bude možné monitorovat, kdo se pozorovací události bude účastnit (účastní se) a na závěr podat z pozorování hlášení, které může být obohacené multimedii. Podrobněji viz Funkční požadavky (2.1.1). Současně je cílem zhodnotit výhody a nevýhody relačních a bezschémových databází pro implementaci tohoto systému a zjistit, jak složité je přizpůsobení systému pro jeden či druhý databázový stroj.
2.1
Požadavky
Dále jsou uvedeny funkční a nefunkční požadavky na systém.
2.1.1 2.1.1.1
Funkční požadavky Požadavky týkající se uživatele
1. Systém bude umožňovat registraci nového uživatele. O úspěšné registraci bude systém uživatele informovat e-mailem. 2. Systém bude umožňovat přihlášení a odhlášení uživatele. 3. Neregistrovaný uživatel bude mít omezená práva. Bude si moci pouze pasivně prohlížet veřejný obsah. 4. Profil uživatele bude obsahovat fotografii, historii navštívených událostí, seznam oblíbených pozorovacích míst, seznam založených pozorovacích míst, seznam privátních pozorovacích míst a nastavení odebíraných informací o místech. 5. Registrovaný uživatel si bude moci přidat pozorovací místo mezi svá oblíbená místa.
3
4
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
6. Registrovaný uživatel si bude moci nastavit preferovanou úroveň přiblížení a výchozí pozici mapy (domácí souřadnice). 7. Registrovaný uživatel bude moci vytvářet pozorovací místa. 8. Registrovaný uživatel bude moci vytvářet události (i na místech, které sám nezaložil, pokud je toto místo veřejné nebo pokud je místo privátní, ale uživatel je v seznamu privátních pozorovatelů tohoto místa). 9. Registrovaný uživatel se bude moci přihlásit k odběru informací o událostech na pozorovacích místech (např. založení nové události). 10. Registrovaný uživatel dostane za každých 10 návštěv pozorovacích míst (jiných, než těch, které sám vytvořil) jeden volný bod hodnocení. Tento bod hodnocení může registrovaný uživatel použít ke zlepšení hodnocení pozorovacího místa. 11. Každá navštívená událost registrovaného uživatele bude zaznamenávána. Součet těchto návštěv bude odpovídat uživatelovo osobnímu hodnocení (karma). 12. Registrovaný uživatel se bude moci přihlásit k události se stavy: „Možná se zúčastním“, „zúčastním se“, „ jsem na místě, ale nepozoruji“, „ jsem na místě a pozoruji“. 2.1.1.2
Požadavky týkající se pozorovacích míst a událostí
1. Pozorovací místo bude obsahovat popis, zeměpisné souřadnice, datum založení, zakladatele, komentáře registrovaných uživatelů a seznam událostí na tomto místě. 2. Událost bude obsahovat popis, pozorovací místo, datum založení, zakladatele, seznam účastníků a hlášení z pozorování. 3. Pozorovací místa budou privátní a veřejná. Privátní pozorovací místa budou viditelná pouze pro vyjmenované pozorovatele. Veřejná místa budou viditelná pro všechny. 4. Vyjmenovat pozorovatele privátního místa bude moci pouze jeho zakladatel. 5. K pozorovacímu místu bude moci registrovaný uživatel přidat komentář. 6. Všichni účastníci události budou moci k této události přidat multimediální hlášení, do kterého bude možné přidávat videa z YouTube (http://youtube.com/) a obrázky. 2.1.1.3
Ostatní funkční požadavky
1. V systému budou „pozorovací místa“ a „události“. Události lze vytvořit pouze na pozorovacích místech. 2. Google Mapa bude zobrazovat pozorovací místa. 3. Na Google Mapě budou odlišena (zvýrazněna) ta pozorovací místa, kde právě někdo pozoruje.
2.2. SROVNÁNÍ EXISTUJÍCÍCH ŘEŠENÍ
5
4. Otevřený detail (bublina v Google maps) pozorovacího místa na mapě bude obsahovat aktuální pozorování. 5. Úvodní stránka bude obsahovat seznam pozorovacích míst, setříděných podle vzdálenosti od aktuálního středu zobrazené mapy. 6. Vedle mapy bude tlačítko pro přechod na domácí souřadnice. 7. Systém bude nabízet sérii ikon pro různé druhy objektů na mapě. 8. Systém bude obsahovat tři role: „neregistrovaný uživatel“, „registrovaný uživatel“ a „administrátor“. 9. Administrátor bude moci archivovat pozorovací místa. 10. Administrátor bude mít práva pro přístup do všech pozorovacích míst, včetně těch privátních.
2.1.2
Nefunkční požadavky
1. K systému se bude přistupovat přes webové rozhraní. 2. Systém bude implementovaný v jazyce PHP. 3. Systém bude pro klienty nezávislý na platformě. 4. Systém bude možné co nejjednodušeji rozšiřovat. 5. Systém bude jednoduchý na používání.
2.2
Srovnání existujících řešení
Pokusil jsem se na internetu nalézt co nejvíce podobných řešení, nicméně aplikace, která by pomáhala lidem jednoduše organizovat menší i větší pozorovací události, zřejmě neexistuje (nenalezl jsem takovou).
2.2.1 2.2.1.1
Řešení v českém jazyce astro.cz
Na webu ČAS (http://www.astro.cz/) (pro jejíž Jihočeskou pobočku systém vyvíjím) se objevují aktuální informace nejen o tom, co je možné na obloze pozorovat. Není zde však pro uživatele žádná možnost, jak se navzájem kontaktovat a už vůbec ne nástroj pro organizaci takovýchto akcí. V sekci „akce“ jsou některé události vypisovány, takže setkání možné je, nicméně jedná se pouze o události významné, kterých bývá jen několik do roka. Navíc zde není pro uživatele žádný prvek interakce, jde pouze o pasivní příjem informace od správců webu.
6
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
2.2.1.2
astro-forum.cz
Astronomické fórum (http://www.astro-forum.cz/) nabízí uživatelům interakci mezi sebou formou odpovědí na své příspěvky (a zakládáním nových témat). Navíc má pro pozorování a podobné akce vyhrazenou kategorii „Astronomická setkání“. Fórum je hostováno na serveru ČAS, ale není jeho přímou součástí. Diskusní fórum nabízí určitou možnost zorganizovat společné pozorování, není však pro tento typ úkolu dostatečně přehledné a názorné. Nový potenciální pozorovatel např. nemůže snadno zjistit (bez přečtení celého vlákna), kdo se bude události účastnit, kde konkrétně bude apod.
Obrázek 2.1: Ukázka obsahu a UI webu astro-forum.cz – kategorie Astronomická setkání
2.2.1.3
astronomie.cz
Virtuální trpaslík (http://www.astronomie.cz/) s podtitulem „Amatérská prohlídka oblohy“ stejně jako astro.cz poskytuje aktuální informace z prostředí Astronomie (některé zprávy přebírá z RSS kanálu ČAS, ale i dalších webů). U lokálních článků se dá komunikovat formou komentářů, nicméně toto není vhodné místo pro organizaci pozorovacích událostí. Virtuální trpaslík svým uživatelům nabízí kromě informací i několik komunikačních kanálů – Facebook stránku (http://www.facebook.com/AstronomieCZ), uživatelské blogy a Twitter (http://twitter.com/AstronomieCZ). K organizaci událostí by se dalo využít diskusní fórum Facebook stránky, ale se stejnými nevýhodami (o něco zesílenými z důvodu ne příliš vhodné integrace na Facebooku), jako v případě Astronomického fóra.
2.2. SROVNÁNÍ EXISTUJÍCÍCH ŘEŠENÍ
2.2.1.4
7
vesmir.info
Poslední aktualita webu vesmir.info (http://www.vesmir.info/) je téměř dva roky stará, web již tedy pravděpodobně přerušil svou činnost. Nicméně v době, kdy aktivní byl, se v sekci „Obloha – pozorování“ objevovaly tipy na pozorování a pod těmito tipy bylo možné diskutovat.
2.2.2 2.2.2.1
Řešení v anglickém jazyce astronomy.com
Web astronomy.com (http://www.astronomy.com/) stojí za oblíbeným magazínem Astronomy a nabízí organizátorům akcí na svém webu (a zřejmě i v magazínu samotném) vypisovat události, které pořádají. Jedná se většinou o větší akce, jako jsou např. konference, exhibice, kempování či přednášky. Web nabízí i diskusní fórum, ale žádný nástroj určený k organizování setkání pozorovatelů oblohy zde není. 2.2.2.2
ostatní
Existuje mnoho zdrojů, které nabízí informace o aktuálním dění ve viditelném vesmíru kolem nás. Mezi takovými je např.: • NASA Space Calendar (http://www2.jpl.nasa.gov/calendar/) • The Calendar-Sky (http://www.calsky.com/cs.cgi/Calendar) • AAS Calendar (http://aas.org/calendar) • Sea and Sky Astronomy Calendar (http://www.seasky.org/astronomy/astronomy-calendar-current.html) Žádný z nich však nenabízí možnost pro uživatele, jak se mezi sebou dohodnout na společném pozorování ze stejného místa. Kromě pasivních poskytovatelů informací pak existují diskusní fóra. Mimo výše uvedeného astronomy.com, je dobrým příkladem např. http://www.astronomyforum.net/. Jak již však bylo řečeno, diskusní fóra nejsou ideálním nástrojem pro organizaci pozorovacích událostí.
8
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
Kapitola 3
Analýza technologií pro implementaci V této kapitole jsou diskutovány výhody a nevýhody dvou významných zástupců z řady bezschémových a relačních databází. V první řadě je uveden princip fungování NoSQL databáze. Následuje srovnání obou databází a je proveden výběr jedné z nich pro finální implementaci aplikace.
3.1
Diskuse relačních a bezschémových databází
Jako zástupce bezschémové databáze jsem vybral MongoDB, jejíž autorem je firma 10gen (http://www.10gen.com/). Zástupcem relačních databází v této práci bude MySQL.
3.1.1
Úvod do bezschémových databází – MongoDB
Tato část bakalářské práce obsahuje vlastnosti konkrétní databáze – MongoDB, ale mnoho zmiňovaného platí obecně pro většinu NoSQL databází. Tuto podkapitolu píši především proto, aby si čtenář mohl udělat základní obrázek o bezschémových databázích. Vycházím z faktu, že bezschémové databáze jsou pro mnoho lidí novou věcí, kterou neznají. Naopak základy relačních SQL databází jsou pro případné čtenáře této poměrně specificky zaměřené bakalářské práce známé. Z toho důvodu sekci uvádějící základy relačních databází záměrně vynechávám. MongoDB je škálovatelná databáze s vysokým výkonem a je považována za spojnici mezi klíč/hodnota databázemi a klasickými RDBMS systémy. Je tomu tak především proto, že MongoDB je robustní jako jednoduchá klíč/hodnota databáze, ale rychlá jako Memcached1 , při zachování funkcí srovnatelných s RDBMS systémy, což je symbolicky zobrazeno na obrázku 3.1. [21] Existuje několik druhů bezschémových databází, z nichž nejvíce zastoupené jsou zmíněny v tabulce 3.1. 1
Memcached je obecný systém pro cachování dat do paměti. Často používaný právě v oblasti databází jako mezivrstva za účelem zvýšení rychlosti. [16]
9
10
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
Typ databáze úložiště typu klíč/hodnota
tabulkové úložiště
úložiště dokumentů
úložiště objektů
Poznámka Příkladem takového úložiště je např. Azure Table Storage od společnosti Microsoft (http://www.microsoft.com/) nebo SimpleDB od společnosti Amazon (http://www.amazon.com/). Tyto úložiště mají pevně definované struktury tabulek, ne však relace mezi nimi. Příkladem je Cassandra (http://cassandra.apache.org/) (úložiště bylo vyvinuto a uvolněno pod licencí Open Source ve společnosti Facebook) nebo Hypertable (http://www.hypertable.org/). Příkladem je MongoDB http://www.mongodb.org/, CouchDB (http://couchdb.apache.org/) nebo Riak (http://wiki.basho.com/). Velmi podobné úložišti dokumentů. Rozdíl je především v tom, že schéma je zde pevně určeno, je definována hierarchie dědičností a místo vkládání dokumentů do sebe se zde používají pointery mezi objekty. Příkladem je databáze db4objects (http://www.db4o.com/).
Tabulka 3.1: Různé typy bezschémových databází. Tabulka čerpá především z článku [23].
3.1. DISKUSE RELAČNÍCH A BEZSCHÉMOVÝCH DATABÁZÍ
11
Obrázek 3.1: Přibližné zobrazení závislosti výkonu na funkcionalitě čtyř systémů - zdroj: [21].
Bezschémové databáze (často také nazývané jako strukturovaná úložiště) nemají pevně dané schéma dat, jako je tomu u relačních SQL databází. Díky tomu je možné bez nutnosti složitých změn struktury dat u jednotlivých záznamů přidávat či ubírat klíče a změny ošetřit na úrovni aplikace.
3.1.1.1
Vlastnosti MongoDB
MongoDB a ani žádné jiné databáze nelze považovat za univerzální řešení všech problémů. Má však vlastnosti a funkce potřebné u většiny projektů. • Ke komunikaci s MongoDB je používán bohatý a široce známý jazyk JavaScript, formát pro ukládání dokumentů je obecný JSON. • MongoDB nabízí širokou škálu základních datových typů, blíže je možné se s nimi seznámit v knize [12] na stranách 15-22. • Databáze je velmi rychlá – detailněji viz 3.1.1.3.
12
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
• Díky podpory shardingu2 umožňuje horizontální škálování. • Protože se jedná o dokumentově orientovanou bezschémovou databázi, má flexibilní datový model. • Databázi je možné snadno replikovat a díky tomu mít záložní databáze např. pro případy výpadku hlavní databáze (failover). • Data je možné indexovat. • MongoDB je ve srovnání s MySQL velmi lightweight (jednoduchý systém). Klíč/hodnota páry databáze MongoDB jsou citlivé na datové typy, velikost písmen a jsou také seřazené. Použijeme-li tedy v názvu či hodnotě jinou velikost písma, jiný datový typ hodnoty či změníme pořadí klíčů, bude se jednat o jiné dokumenty. Dokument také nesmí obsahovat duplicitní klíče. 3.1.1.2
Denormalizovaná databáze
Častým argumentem proti bezschémovým databázím, je denormalizace dat3 , ke které zde (nikoliv však nezbytně) obvykle dochází. Karel Minařík ve své přednášce na WebExpo 2010 [11] (http://webexpo.cz/) upozorňuje, že mnoho aspektů reálného světa neodpovídá normalizovanému obrazu. Myšlenku opírá o příklad fakturačního systému, kde při změně adresy dojde vlivem normalizace dat ke změně adres na všech fakturách a tím dojde ke znehodnocení starých faktur (adresa musí zůstat stejná, jaká byla v době vystavení). Také v článku [23] jsou uvedeny protiargumenty na téma normalizace dat: 1. Argument: Ušetření datového prostoru – Protiargument: Žijeme v době, kdy datový prostor je velmi levný a představuje až ten poslední problém. 2. Argument: Normalizovaná data je možné upravovat na jednom místě – Protiargument: Pravdou je, že většinu dat nepotřebujeme měnit, anebo jen velmi zřídka. Na druhou stranu pokud použijeme normalizovaný model, operaci spojování dat musíme provádět pokaždé, kdy o ně někdo požádá. 3. Argument: Potřebujeme many-to-many relace – Protiargument: Je uveden příklad knihovny. Máme knihu, kterou si může půjčit více lidí a osobu, která si může půjčit několik knih. Problém se dá vyřešit snadno, za cenu denormalizace dat – k osobě si uložíme všechny knihy, které si půjčila a ke knize všechny osoby. Za předpokladu, že ke změně informací jako je název knihy či jméno osoby dochází zřídka, denormalizace nepředstavuje problém a přináší nezanedbatelné výhody v podobě ušetření místa na vztahových tabulkách a především ušetření výkonu, díky nepoužití operací spojení (JOIN). 2
Sharding je metoda horizontálního dělení databáze, která umožňuje rozdělení dat mezi jednotlivé stroje po řádcích (dokumentech, záznamech,. . . ). 3 Opakem je normalizace dat, která se snaží odstranit nadbytečné informace, sémanticky oddělit data a vytvořit mezi těmito daty dobře definované relace.
3.1. DISKUSE RELAČNÍCH A BEZSCHÉMOVÝCH DATABÁZÍ
Databáze MongoDB unsafe MyISAM MongoDB safe InnoDB
13
Čas 76,911s 231,695s 232,042s 533,430s
Tabulka 3.2: Výsledky testu rychlosti vložení milionu záznamů (každý záznam měl tři hodnoty včetně generovaného ID) na stolním počítači. [3] Nabízí se otázka, proč vůbec dělit data do více kolekcí, máme-li databázi bez pevného schématu. Důvodů je několik, ale především bychom neměli zneužívat flexibility, jaká je nám bezschémovými databázemi nabízena, k vytvoření chaosu. Hlavní důvod je tedy udržení určitého pořádku a čitelnosti pro programátory. Ze stejného důvodu je vhodné používat pro pojmenování kolekcí tečkovou konvenci (např. blog.posts či blog.posts.comments), ačkoliv tím fyzicky není vyjádřena žádná spojitost. Dalším důvodem je rychlost. Pokud bychom si typy různých dat (řekněme např. komentáře a články) oddělovali hodnotou určitého atributu, rychlost výběru dat z takové jedné univerzální kolekce by byla menší, než při rozdělení do více kolekcí. V neposlední řadě pak oddělením do kolekcí získáváme lepší indexovatelnost dat. 3.1.1.3
Rychlost
Je všeobecně známo, že bezschémové databáze jsou výrazně rychlejší, než ty relační. Tato skutečnost je však způsobená z velké části tím, že bezschémové databáze často nezajišťují „durability“ 4 . Jinak řečeno data zapisují pouze do paměti a bezpečně uchovávají na disk až po určitém čase (např. jednou za minutu). [24] Test rychlosti (ačkoliv neprofesionální) vkládání dat provedl např. Artur Ejsmont. Své výsledky, jejichž část je možné vidět v tabulce 3.2, prezentoval ve svém článku [3]. 3.1.1.4
Škálovatelnost
Škálovatelnost je vlastnost umožňující zvyšování (ale i snižování) výkonu stroje, především za účelem poskytnutí služeb více klientům a možnost pracovat s větším množstvím dat (v případě databází). Existují dva základní způsoby, jakými lze databáze škálovat - horizontální a vertikální. Vertikální škálování probíhá v rámci jednoho fyzického stroje. V praxi může vypadat např. tak, že se současný server rozšíří o další paměťový modul. Problém tohoto přístupu je především cena (velmi výkonný stroj je mnohem dražší, než více méně výkonných), ale také fakt, že tento způsob má určitý limit (jeden stroj nelze donekonečna rozšiřovat). Horizontální škálování neboli rozšiřování do šířky naopak uvažuje rozšíření systému o více strojů a rozdělení práce mezi ně. 4
Durability je jedna z vlastností ACID systémů, která garantuje, že jednou odeslaná transakce bude zachována, i kdyby následovala závažná chyba typu výpadek proudu.
14
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
MongoDB nativně nabízí podporu pro horizontální škálování. Pokud je potřeba větší výkon, lze do stávajícího systému zapojit další MongoDB server. 3.1.1.5 • • • • •
Základní příkazy
show dbs – vypíše seznam všech databází use foobar – přepne do databáze s názvem „foobar“ db – vypíše název aktuální databáze show collections – vypíše seznam všech kolekcí v aktuální databázi db.runCommand({getLastError:1}) – vypíše chybu (spíše status) posledního příkazu
3.1.1.6
Vkládání dat
Dokument bezschémové databáze, na rozdíl od záznamu v relační databázi, může reprezentovat složitější datové struktury, což je bližší reprezentaci dat na úrovni aplikace implementované v objektově orientovaném jazyku. Ukázku vložení dokumentu do databáze MongoDB je možné vidět ve zdrojovém kódu 3.1. Pokud dokumentu ručně nedefinujeme jeho _id, dojde k jeho automatickému vygenerování, jak je možné vidět v kódu 3.3. Tento vygenerovaný ObjectId garantuje unikátnost napříč všemi servery. Podrobnější informace o ObjectId lze nalézt např. v knize [12] na stranách 20-22.
Listing 3.1: Příklad vložení nového dokumentu do MongoDB
1 post = { 2 " title " : " Article headline " , 3 " articleContent " : " Here is the content 4 of the article with headline 5 Article headline . " , 6 " date " : new Date () , 7 " author " : { 8 " name " : " Tonda " , 9 " email " : " danek@antonindanek . cz " 10 } 11 } 12 13 db . test . insert ( post )
Pro vkládání velkého množství záznamů najednou (stovky, tisíce, . . . ) je vhodné použít funkci batch_insert(), které se předává pole dokumentů a je možné je takto vložit najednou. Dojde tak k ušetření času při otevírání TCP spojení a dekódování hlaviček. Nejde však o funkci určenou např. pro migraci záznamů z jiné databáze. K tomu účelu existují nástroje, jako je např. mongoimport.
3.1. DISKUSE RELAČNÍCH A BEZSCHÉMOVÝCH DATABÁZÍ
15
Omezení velikosti jednoho dokumentu je nastavena na 4MB a velikost jednoho dávkového vložení dokumentů na 16MB. Jde především o ochranu před špatnými návrhy. Vkládání záznamů je nativně odolné proti SQL injection5 . 3.1.1.7
Čtení dat
Pro čtení dat z databáze je možné použít jednu ze dvou základních funkcí: find() nebo findOne(). Do obou vyhledávacích funkcí je možné jako parametr předat dotazovací dokument. Výsledky hledání pak obsahují pouze ty dokumenty, které odpovídají dotazu. Funkce se volají nad kolekcemi, konkrétní použití je možné vidět ve zdrojovém kódu 3.2. Výsledek každého volání v tomto příkladu je stejný a je vidět v ukázce 3.3.
1 2 3 4 5 6 7 8
Listing 3.2: Příklad jednoduchého načtení dokumentu z databáze (3x)
db . test . find ( { " _id " : ObjectId ( " 4 d72450e4 e2f00000000 6b38 " ) } ) db . test . find ( { " title " : " Article headline " } ) db . test . find ( { " _id " : ObjectId ( " 4 d72450e4e 2f000000006 b38 " ) , " title " : " Article headline " } )
1 { 2 3 4 5 6 7 8 9 10 11 12 13 }
Listing 3.3: Příklad dokumentu s automaticky generovaným ObjectId
" _id " : ObjectId ( " 4 d7 2450e4e2f00 0000006b38 " ) , " title " : " Article headline " , " articleContent " : " Here is the content of the article with headline Article headline . " , " date " : " Sat Mar 05 2011 15:13:07 GMT +0100 ( Central Europe Standard Time ) " , " author " : { " name " : " Tonda " , " email " : " danek@antonindanek . cz " }
Pokud je potřeba agregace (seskupující operace, ke kterým se ve světě SQL používají funkce GROUP BY, HAVING, MAX apod.), je zde funkce mapReduce(). Problematika a možnosti mapReduce jsou poměrně široké a existuje na toto téma mnoho názorných příkladů. 5
SQL injection je technika napadení databázové vrstvy programu vsunutím (odtud „injection“) kódu přes neošetřený vstup a vykonáním vlastního SQL dotazu. [17]
16
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
Některými z nich jsou např. [18], [10] či na oficiálních stránkách MongoDB [7]. Pomocí mapReduce se dá vyjádřit vše, co pomocí agregačních funkcí v SQL a existují dokonce úspěšné pokusy o automatické převody. [20] Rick Osborne na toto téma vytvořil názornou infografiku 3.2.
mySQL
1
Grouped dimension columns are pulled out as keys in the map function, reducing the size of the working set.
2
Measures must be manually aggregated.
3 Aggregates depending on record counts must wait until finalization. 4 Measures can use procedural logic. 5 Filters have an ORM/ActiveRecordlooking style. 6 Aggregate filtering must be applied to the result set, not in the map/reduce. 7 Ascending: 1; Descending: -1
MongoDB
1 2 3
4
5 1
6 7
db.runCommand({ mapreduce: "DenormAggCollection", query: { filter1: { '$in': [ 'A', 'B' ] }, filter2: 'C', filter3: { '$gt': 123 } }, map: function() { emit( { d1: this.Dim1, d2: this.Dim2 }, { msum: this.measure1, recs: 1, mmin: this.measure1, mmax: this.measure2 < 100 ? this.measure2 : 0 } );}, reduce: function(key, vals) { var ret = { msum: 0, recs: 0, mmin: 0, mmax: 0 }; for(var i = 0; i < vals.length; i++) { ret.msum += vals[i].msum; ret.recs += vals[i].recs; if(vals[i].mmin < ret.mmin) ret.mmin = vals[i].mmin; if((vals[i].mmax < 100) && (vals[i].mmax > ret.mmax)) ret.mmax = vals[i].mmax; } return ret; }, finalize: function(key, val) { val.mavg = val.msum / val.recs; return val; }, out: 'result1', verbose: true }); db.result1. find({ mmin: { '$gt': 0 } }). sort({ recs: -1 }). skip(4). limit(8);
Revision 4, Created 2010-03-06 Rick Osborne, rickosborne.org
SELECT Dim1, Dim2, SUM(Measure1) AS MSum, COUNT(*) AS RecordCount, AVG(Measure2) AS MAvg, MIN(Measure1) AS MMin MAX(CASE WHEN Measure2 < 100 THEN Measure2 END) AS MMax FROM DenormAggTable WHERE (Filter1 IN (’A’,’B’)) AND (Filter2 = ‘C’) AND (Filter3 > 123) GROUP BY Dim1, Dim2 HAVING (MMin > 0) ORDER BY RecordCount DESC LIMIT 4, 8
Obrázek 3.2: Znázornění, jak jednotlivé SQL funkce odpovídají nástroji MapReduce – zdroj: [19].
3.1.1.8
Upravování dat
„Updaty“ jsou atomické6 a provádí se postupně tak, jak přicházejí na server. Provádí se pomocí funkce update( vyhledavaci_dokument, novy_dokument ), která funguje tak, že nahradí dokument nalezený podle prvního parametru dokumentem v druhém parametru. V příkladu 3.4 je vidět ukázka úpravy dat (je upravován dokument 3.3). 6
Atomicita nebo-li nedělitelnost je důležitou vlastností v programování. Vyjadřuje, že daná činnost (operace) se provede najednou, nemůže být přerušena něčím jiným a dokončena později. [15]
3.1. DISKUSE RELAČNÍCH A BEZSCHÉMOVÝCH DATABÁZÍ
Listing 3.4: Příklad nahrazení dokumentu jiným dokumentem
1 db . test . update ( 2 { " title " : " Article headline " } , 3 { " foo " : " novy dokument " }) 4 5 db . test . find ( 6 { " _id " : ObjectId ( " 4 d72450e4e2 f000000006b 38 " )}) 7 8 // nalezeny dokument 9 { " _id " : ObjectId ( " 4 d72450e 4e2f0000000 06b38 " ) , 10 " foo " : " novy dokument " }
17
Pokud bychom chtěli odstranit z dokumentu nějaký klíč, mohli bychom to udělat tak, jak je ukázáno v ukázce 3.5.
Listing 3.5: Příklad odstranění klíče z dokumentu
1 var article = db . test . findOne ( 2 { " title " : " Article headline " } ); 3 delete article . date 4 db . test . update ( 5 { " title " : " Article headline " } , article )
Mnohdy však potřebujeme se záznamy provádět pouze částečné změny a v takovém případě je zbytečné nahrazovat celý dokument. Pro změnu pouze některých klíčů se používají modifikátory. Jelikož si tato bakalářská práce neklade za cíl být referenční příručkou ani k MongoDB, ani k jiné bezschémové databázi, uvedu pouze stručný příklad a krátký výčet dalších možných modifikátorů. V příkladu 3.6 je použit modifikátor $inc, který slouží k přičtení číselné hodnoty. Klíč, ke kterému je hodnota přičítána, nemusí předem existovat – v takovém případě bude vytvořen.
Listing 3.6: Příklad použití modifikátorů
1 db . test . update ( 2 { " title " : " Article headline " } , 3 { " $inc " : { " pageviews " : 1}})
Některé další modifikátory • $set – Slouží pro přidání nového klíče nebo upravení obsahu již existujícího. Je možné takto změnit i datový typ. • $unset – Odstranění klíče.
18
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
MySQL databáze tabulka řádka sloupec
MongoDB databáze kolekce dokument klíč
Tabulka 3.3: Základní komponenty databází MySQL a MongoDB, které sobě přibližně odpovídají. • $push – Vloží další element na konec pole, případně vytvoří pole, pokud neexistovalo. • $addToSet – Vloží další element na konec pole, ale pouze v případě, že element v poli ještě neexistuje. • $pop – Odebere prvek ze začátku či konce pole. • $pull – Odebere prvek z pole dle kritérií. Konkrétní příklady použití modifikátorů a další možnosti upravování dat, včetně jejich výhod a nevýhod, je možné dohledat v knize [12] na stranách 27–41. 3.1.1.9
Mazání dat
Pro mazání lze použít funkci remove(), která bez parametrů smaže všechny dokumenty v kolekci, nad kterou byla zavolána. Stejně jako u předchozích příkladů je možné funkci předat v parametru dokument, podle něhož budou vymazány pouze specifické dokumenty. Je třeba si uvědomit, že zde neexistuje žádná funkce „zpět“. Funkce remove nesmaže samotnou kolekci ani indexy. Pokud bychom chtěli smazat celou kolekci, je vhodnější použít funkci pro zrušení kolekce db.drop_collection("test"), která je o mnoho rychlejší.
3.1.2
Srovnání relačních a bezschémových databází
V této sekci provedu srovnání bezschémových a relačních databází tak, abych na jeho základě mohl rozhodnout, která z databází bude vhodnější pro finální implementaci aplikace. Jak již bylo výše zmíněno, žádné řešení se nedá považovat za univerzálně nejlepší a vždy je třeba vlastnosti jednotlivých systémů porovnat s požadavky na konkrétní systém. Mnohé systémy dokonce používají obě databáze. Relační databáze je pak použita v části, kde je klíčová konzistence či komplexní transakce a na vše ostatní databáze bezschémová. [23] V následujících podsekcích provádím diskuzi důležitých aspektů obou databází. 3.1.2.1
Množství dat
Pokud potřebujeme ukládat velké množství dat, bezschémová databáze je lepší volba. [22] Velkým množstvím dat je však míněno opravdu velmi velké množství dat. Pro představu, bezschémovou databázi začal používat server digg.com (http://digg.com/), který umožňuje
3.1. DISKUSE RELAČNÍCH A BEZSCHÉMOVÝCH DATABÁZÍ
19
návštěvníkům přidávat odkazy na zajímavé webové stránky a následně pro ně hlasovat. Tento oblíbený server čítá desetitisíce nově přidaných odkazů denně, přibližně stejné množství komentářů a statisíce hlasů pro tyto odkazy. [13] Dalším příkladem je server Twitter (http://twitter.com/), který přijímá na 7TB dat denně – je tedy třeba rychlost více než 80MB/s, aby se takové množství dat vůbec zapsalo. V těchto případech není myslitelné použití SQL databáze. [22] Bezschémové databáze však mohou pojmout velké množství dat především díky škálování – datovým prostorem nijak nešetří. Pokud vyvíjíme např. pro mobilní zařízení, kde stále ještě máme poměrně omezený datový prostor, je vhodnější použít relační databázi. 3.1.2.2
Rychlost a horizontální škálování
Z hlediska rychlosti vyhrávají bezschémové databáze, ale mnoho logiky, která je u relačních databází zahrnuta, si musí programátor dopsat sám nebo ji musí obsahovat ovladač databáze. [22] [4] Opět nabízím příklad serveru digg.com, který obsluhuje 40 milionů uživatelů a 500 milionů zobrazení stránek měsíčně. [13] S bezschémovými databázemi se díky horizontálnímu škálování také zprošťujeme možného problému nárazu na nepřekonatelnou bariéru, kdy bychom mohli zjistit, že náš rostoucí projekt už nejsme schopni technicky zvládnout. [23] Horizontální škálování lze u bezschémových databazí snadno provádět především proto, že API pro přístup k datům je dostatečně jednoduché a přesně definované. [4] Relační databáze také nabízejí určité možnosti rozložení zátěže na více strojů, ale nevyhneme se dotazům, které se budou muset odeslat na všechny databáze a výsledek zkombinovat z těchto dílčích výsledků. Takové dotazy se pak stanou velmi drahými a úzkým hrdlem celé aplikace. [8] Relační databáze horizontálně škálujeme pomocí vytvoření struktury master-slave, kde master slouží pro zapisovací operace a slaves pro čtecí. U bezschémové databáze jsou všechny stroje ekvivalentní a škáluje se jednoduše přidáním dalšího stroje. [8] 3.1.2.3
Křivka učení, rozšířenost a dospělost
Křivka učení představuje závislost času stráveného programátorem učením se určité technologie na jeho schopnostech s touto technologií pracovat. Ta v případě NoSQL bude mít u většiny lidí pomalejší růst, než u SQL databází. [9] [13] Na druhou stranu to jiní lidé [21] vyvracejí, jako mýtus. Relační databáze tu jsou už velmi dlouho a těžko bychom hledali programátora, který nezná alespoň základy dotazovacího jazyka SQL. Díky tomu je pro firmu snazší najmout SQL programátora a navíc existuje více lidí, s kterými je možné případné problémy konzultovat. NoSQL naopak zatím není tak rozšířené. [6] Relační databáze se nesčetněkrát ověřily v praxi a lidé v ně mají důvěru. Také vědí, co se s nimi dá dělat a co ne. Navíc existuje o mnoho více SQL nástrojů, které při vývoji pomohou. [22]
20
3.1.2.4
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
Dostupnost a cena
Vzhledem k hromadnému rozšíření MySQL i dalších SQL databází je mnohem snazší nalézt hostera, který poskytuje relační databázi. Pokud však vyvíjíme pro cloud, je třeba porovnat ceny datového prostoru pro jednotlivé databáze. Cena prostoru pro bezschémové databáze bývá nižší, může však dojít k jejímu navýšení např. v podobě zpoplatnění transakcí. [23] 3.1.2.5
Flexibilní schéma a interakce s daty
Už z podstaty bezschémových databází je jasné, že pokud očekáváme časté změny datového modelu, měli bychom se vydat cestou NoSQL. Na druhou stranu s flexibilitou ztrácíme jistý pevný základ aplikace. U aplikací používajících relační databáze se dá datový model považovat za jakýsi souhrn pevných informací, které přetrvávají přes všechny změny, které se v aplikaci dějí. [22] Díky standardizaci komunikace s relačními databázemi v podobě jazyka SQL získáváme jednotný přístup k datům – ačkoliv implementace SQL se u jednotlivých databází často liší. U bezschémových databází se zatím přístup k datům standardizovat nepodařilo a změna jedné NoSQL databáze za jinou tak může představovat velké změny. [5] 3.1.2.6
Transakce
Komplexní víceřádkové transakce bezschémové databáze nemají (jednoduché transakce ano) a je třeba je řešit na úrovni aplikace. Je tomu tak z toho důvodu, že tyto operace je složité poskytnout na distribuovaném systému. Relační databáze transakce většinou mají sami o sobě. [22] [8] Existují i bezschémové databáze, jako je např. GT.M, které komplexní transakce podporují (http://fisglobal.com/Products/TechnologyPlatforms/GTM/index.htm). 3.1.2.7
Normalizace dat a konzistence
Díky denormalizaci dat je možné dosahovat vysokých výkonů, ale programátor pak musí být velmi obezřetný (především při upravování či mazání dat), aby došlo ke změnám na všech potřebných místech. [9] Denormalizaci dat lze provést jak u bezschémových, tak u relačních databází. Systém je tím vystaven možné nekonzistenci, ale SQL databáze s podporou ACID nabízí lepší prostředí pro udržování konzistence. [23] Relační databáze nabízejí okamžitou (blokující) konzistenci, zatímco bezschémové pouze částečnou (čtecí operace nečekají na zapisovací a poslední zápis vyhrává). [8]
3.2 3.2.1
Výběr technologií pro implementaci Výběr hlavní databáze
Výběr proběhl mezi bezschémovou databází MongoDB a relační databází MySQL.
3.2. VÝBĚR TECHNOLOGIÍ PRO IMPLEMENTACI
21
• Množství dat – Informační systém (dále jen IS) nebude obsahovat gigantické množství dat. Velká multimediální data a mapové podklady budou uloženy v jiných databázích a v aplikaci na ně budou umístěny pouze odkazy. Z tohoto pohledu je možné použít obě databáze. • Rychlost a horizontální škálování – IS by vzhledem k cílení na omezenou skupinu lidí v ČR neměl přesáhnout kapacit jednoho serveru. Z tohoto pohledu je možné použít obě databáze. • Křivka učení, rozšířenost a dospělost – Vzhledem k možnosti, že systém budou spravovat a případně i rozšiřovat další lidé, bude lepší použít technologii, která je všeobecně známá. Z tohoto pohledu je lepší použít MySQL. • Dostupnost a cena – Zadavatel má již k dispozici server s MySQL databází. Z tohoto pohledu je lepší použít MySQL. • Flexibilní schéma a interakce s daty – Je pravděpodobné, že při vývoji a dalším rozšiřování systému (které je v plánu) se objeví požadavek na změny datového modelu. Z tohoto pohledu je lepší použít MongoDB. • Transakce – Ačkoliv je jistě lepší transakce mít, než-li ne, systém nebude nakládat z finančními či jinak choulostivými daty, a proto vyloženě nutné nejsou. Z tohoto pohledu je možné použít obě databáze. • Normalizace dat a konzistence – Systém by mělo být možné úspěšně denormalizovat při zachování konzistence (např. z důvodu zvýšení výkonu). Z tohoto pohledu je možné použít obě databáze. Výsledek: Ačkoliv bude pravděpodobně v budoucnu nutné upravovat datový model databáze, všeobecné rozšíření a znalost SQL databází posouvá MySQL na místo lepší volby. Navíc je nepravděpodobné, že by bylo nutné systém v budoucnu horizontálně škálovat.
3.2.2
Výběr ostatních technologií
Výběr jazyka byl dán nefunkčními požadavky 2.1.2, kde je specifikován jazyk PHP. Další otázkou bylo, zda použít pro PHP některý z frameworků. Z důvodu jednoduchosti a pochopitelnosti jsem se rozhodl systém vyvíjet bez frameworku. Také z důvodu, že budu systém vyvíjet jak pro MySQL, tak částečně pro MongoDB, rozhodl jsem se nepoužívat ORM. Pro oddělení aplikační logiky od uživatelského rozhraní jsem se rozhodl použít šablonovací systém Smarty (http://www.smarty.net/). Pro komunikaci s Google Maps je možné v PHP použít neoficiální knihovnu php-google-mapapi (http://code.google.com/p/php-google-map-api/), ale rozhodl jsem se použít oficiální Google Maps JavaScript API V3 (http://code.google.com/apis/maps/documentation/javascript/).
22
KAPITOLA 3. ANALÝZA TECHNOLOGIÍ PRO IMPLEMENTACI
Kapitola 4
Realizace V projektu je použit architektonický vzor Model-View-Controller, konkrétně jeho pasivní verze, kde modul View není okamžitě informován Modelem o změnách, nýbrž aktuální data jsou načtena až při dalším HTTP požadavku vyvolaném uživatelem. [2] Pro základní obsluhu požadavků je použit návrhový vzor Front Controller, který předává řízení příslušnému MVC Controlleru. Jak je možné vidět na obrázku B.1, který znázorňuje hlavní adresáře (a jejich podadresáře) aplikace, soubory realizující jednotlivé moduly MVC se nacházejí ve složkách s odpovídajícími názvy (model, view a controller). Zajímavým obsahem těchto i ostatních adresářů se budu blíže zabývat v následujících podkapitolách.
4.1 4.1.1 4.1.1.1
Model-View-Controller Model Zaměnitelnost datové vrstvy
Poněkud nestandardní částí projektu je jeho Model, což je způsobené tím, že je možné v konfiguraci aplikace zaměnit relační databázi za bezschémovou. Aby toto bylo možné (bez nutnosti provádět další změny ve zbytku aplikace), bylo nutné v první řadě odstínit datovou vrstvu od aplikační logiky a view, což zajistila implementace MVC. Kromě toho však bylo nutné vytvořit ještě rozhraní mezi Controllerem a Modelem, aby bylo možné ovlivňovat, jaký model bude použit. Tato funkčnost byla realizována implementací jednoduché továrny (nejde však o návrhový vzor Factory method). Jak je vidět na diagramu 4.1, třída DaoFactory vrací příslušný Data Access Object implementující požadované rozhraní. V aplikaci je pak pouze třeba dodržovat pravidlo, že s databází se komunikuje pouze skrze DAO, které získáváme od DaoFactory. Tímto způsobem by bylo možné systém rozšířit o další datovou vrstvu. Museli bychom pouze rozšířit DaoFactory a samozřejmě naimplementovat příslušné DAO.
23
24
KAPITOLA 4. REALIZACE
Obrázek 4.1: UML diagram pro DaoFactory a jím vracené DAO objekty (z úsporných důvodů je zobrazeno pouze několik DAO tříd a pouze některé metody)
4.1.1.2
Připojení k MySQL
Připojení k MySQL databázi probíhá ve třídě MyDb, která se nachází v adresáři model/dataLayer/SQL/database. Tato třída implementuje návrhový vzor Singleton, který napomáhá ušetření vytváření připojení k databázi, jež je časové náročné. V rámci jednoho zpracování HTTP požadavku tak díky tomuto vzoru dochází k vytvoření pouze jediného připojení k databázi. K připojení samotnému je použito PDO (http://php.net/manual/en/book.pdo.php). Třída MyDb poskytuje statickou metodu getInstance(), častěji je však používána spíše druhá statická metoda query, které je možné přímo předat SQL dotaz, který bude nad databází proveden. Na této úrovni již nejsou prováděny žádné kontroly a je očekáváno, že přijatý SQL dotaz je korektní.
4.1.1.3
Připojení k MongoDB
Připojení k MongoDB databázi probíhá též ve třídě MyDb, která se nachází v adresáři model/dataLayer/NoSQL/database. Na rozdíl od připojení k MySQL, zde není na úrovni aplikace
4.1. MODEL-VIEW-CONTROLLER
25
implementována logika pro zajištění pouze jediného připojení k databázi. Místo toho je použita nativní podpora pro vytvoření tzv. persistentního připojení, která tuto problematiku řeší. K připojení samotnému je použita třída Mongo (http://cz.php.net/manual/en/book.mongo.php). 4.1.1.4
Business objekty
Business objekty jsou součástí rozhraní se zbytkem systému, protože jsou používány jak v controllerech, tak v samotných view – tyto komponenty tedy mají znalost jejich struktury. Business objekty jsou poměrně primitivní a tvoří pouze obálku pro různé typy dat, reprezentujíce tak určitý složitější typ. Typický business objekt pak obsahuje pouze privátní atributy, které je možné namapovat na „atributy“ záznamů v databázi, a veřejné metody pro přístup k nim. K atributům nepřistupujeme přímo z důvodu zlepšení zapouzdření a možnosti provádět s daty určité korekce, jako je např. transformace znaků nových řádků na příslušné HTML tagy, což je možné vidět např. ve třídě Event, konkrétně v metodě getDescription(). Tyto třídy však mohou obsahovat i metody vracející určitou informaci, kterou bychom za jistých okolností (např. pokud je výpočet příliš náročný) mohli také ukládat do databáze, ale z důvodu možnosti dopočítání z jiných informací a omezení redundance, to neděláme. Příkladem takové metody je metoda getState(), kterou je možné vidět opět ve třídě Event. Tato metoda porovnává data události s datem aktuálním a vrací informaci o tom, zda událost např. ještě probíhá, či zda se teprve bude konat.
4.1.2
View
View aplikace je realizováno pomocí šablonovacího systému Smarty (http://www.smarty.net/). Opakující se části, jako je např. hlavička stránky, drobečková navigace, patička či formulář pro přechod na domovské souřadnice, se nacházejí v oddělených souborech (v adresářích view/includes a view/templates). Tyto části jsou pak do ostatních šablon vkládány příkazem include.
4.1.3
Controller
Základem každého controlleru aplikace je abstrakční předek BaseController, který provádí určité přípravné operace prvků, které jsou později třeba ve všech controllerech. Těmito operacemi jsou např. inicializace Smarty, nastavení výchozích hodnot pro titulek stránky či zvolení defaultní šablony. Dále definuje abstraktní metody setup() a render(). Jak je vidět na diagramu 4.2, většina controllerů nedědí přímo z této třídy, ale z konkrétnější (avšak stále abstraktní) třídy BaseSessionController, která navíc připravuje session pro uložení přihlášeného uživatele. Každý finální controller pak implementuje již zmíněné metody setup() a render(), které jsou nad příslušnými controllery volány instancí FrontController v souboru index.php5 (či admin.php5 ). Obsah obou metod by mohl být přesunut do konstruktoru a být tak proveden automaticky při vytváření jednotlivých instancí, ale takto zůstává otevřena možnost pro případné operace např. ještě před vykreslením uživatelského rozhraní. V metodě setup() dochází k vyhodnocení aplikační logiky v závislosti na požadavku, získání potřebných dat a jejich předání do příslušných Smarty proměnných voláním metody assign.
26
KAPITOLA 4. REALIZACE
Obrázek 4.2: UML diagram systému controllerů (z úsporných důvodů jsou zobrazeny pouze některé)
Zajímavou Smarty proměnnou je invokeJavaScript, ve které je možné definovat, které JavaScript funkce z přiložených souborů budou explicitně zavolány po načtení stránky. Podobně lze do proměnné customJavaScript dynamicky generovat funkce nové, čehož je využíváno např. u jednotlivých pozorovacích míst a událostí, kde je třeba zacílit a přiblížit mapu na příslušné místo, dle definované polohy při zakládání těchto objektů. V setup() metodě může také dojít k předání řízení controlleru ErrorController, který je určen k obsluhování chyb (to může nastat, pokud se snažíme přistupovat k privátnímu nebo neexistujícímu obsahu), či případně k přesměrování na jinou adresu. Metoda render() pak už pouze pošle Smarty zprávu s informací, jaká šablona má být zobrazena.
4.2
Implementace Data Access Objektů
V této sekci se nachází příklady tří metod (další je možné nalézt přímo ve zdrojovém kódu aplikace) pro práci s databází. Na těchto je demonstrován odlišný přístup k operacím čtení, upravování a vkládání.
4.2. IMPLEMENTACE DATA ACCESS OBJEKTŮ
4.2.1 4.2.1.1
27
Implementace DAO pro MySQL Metoda getSpotsCreatedBy
Na ukázce C.1 je vidět, jakým způsobem dochází k získávání dat z databáze při použití MySQL. Důležitou částí je místo plnění proměnné $sql, kde se nachází konkrétní SQL dotaz. Je zde také možné vidět ochranu proti SQL injection, jež je realizována metodou gpcAddslashes, která v závislosti na nastavení PHP přidá před speciální znaky escape sekvence (pokud to PHP nedělá automaticky). Další důležitou částí je volání mapovací metody mapSpot, která přijme řádek získaný z databáze jako pole hodnot a z těchto hodnot vytvoří business objekt (4.1.1.4), který je vrácen zpět.
4.2.1.2
Metoda createNewUser
Na další ukázce (C.2) je možné vidět metodu createNewUser, která je volána při registraci nového uživatele. Opět je možné si povšimnout ochrany proti SQL injection. Metoda po vložení záznamu do databáze tohoto právě vytvořeného uživatele vrátí, aby mohl být automaticky po registraci přihlášen.
4.2.1.3
Metoda addAttendingUserToEvent
V poslední ukázce (C.3) této podsekce je metoda vkládající záznam do joinovací (spojovací) tabulky. Ukázka je zde pro účely porovnání této operace s bezschémovou databází (viz 4.2.2.3), kde joinovací tabulky nejsou.
4.2.2 4.2.2.1
Implementace DAO pro MongoDB Metoda getSpotsCreatedBy
Jak je vidět na ukázce C.4, nejsou zde žádné SQL dotazy, místo nich je vytvářen dotazovací dokument, a proto není třeba už z principu řešit SQL injection. Za povšimnutí stojí nutnost volby kolekce (ekvivalent tabulky) před odesláním samotného dotazu, nad kterou bude dotaz proveden. U relační databáze je tato volba součástí dotazu. Je třeba si také uvědomit, že není používán stejný Mapper, jako byl použit u relační databáze. Ve většině případů je třeba mapování lehce upravit, protože data nejsou z databáze přijata ve stejném formátu, jako u databáze relační.
4.2.2.2
Metoda createNewUser
Ukázka postupu uložení nového uživatele do MongoDB je vidět ve zdrojovém kódu C.5. Zdrojový kód je sám o sobě snadno pochopitelný.
28
KAPITOLA 4. REALIZACE
4.2.2.3
Metoda addAttendingUserToEvent
V ukázce C.6 lze pozorovat (při srovnání s ukázkou C.3) odlišný přístup k ukládání dat mezi jednotlivými databázemi. V tomto případě není využíváno spojovacích tabulek, ale navštívené události příslušným uživatelem jsou uloženy přímo u uživatele. Na to je třeba myslet, pokud bychom implementovali možnost události editovat, což by mohlo způsobit vznik aktualizační anomálie1 (aplikace to však momentálně neumožňuje a tak tento problém neexistuje). Editace se provádí voláním metody update, které se kromě vyhledávacího dokumentu předává také dokument upravovací. V tomto dokumentu je použit modifikátor $addToSet, který zajišťuje přidání dokumentu do pole attendedEvents pouze v případě, že se v poli již nenachází.
4.3 4.3.1
Některé další prvky implementace Formuláře
Každý formulář je na straně serveru reprezentován příslušnou třídou (k nalezení v adresáři model/forms) s abstraktním předkem Form, který vyžaduje implementaci metod isValid() a getErrorMessages(). Navíc obsahuje některé již implementované metody, jako je např. check_email($email) (jejímž autorem je Jakub Vrána – http://www.vrana.cz/), které jsou potřeba u více formulářů. Konkrétní potomci tohoto předka jsou inicializováni předáním příslušných $_POST dat jejich konstruktoru, který do atributů třídy uloží jednotlivé položky formuláře zadané uživatelem. Stejně jako u business objektů (viz 4.1.1.4), i zde jsou atributy privátní a je k nim přistupováno pouze skrze veřejné metody. Díky tomu bylo možné do setterů zakomponovat zabezpečení proti XSS2 .
4.3.1.1
Životní cyklus formulářů
1. Při první návštěvě stránky s formulářem controller detekuje nepřítomnost formulářových dat a je pouze zobrazena šablona obsahující formulář. 2. Uživatel vyplní (správně či špatně) formulář a data odešle stisknutím tlačítka na server. 3. Controller detekuje přítomnost formulářových dat a vytvoří objekt formuláře. Voláním metody isValid() (tato metoda zároveň plní pole chyb, pokud nějaké nastaly) nad formulářem ověří jeho korektnost. 1
Aktualizační anomálie je problém, který se může vyskytnout v případě, kdy data v databázi nejsou v normalizované podobě. Tedy aktualizace určité hodnoty nelze provést na jediném místě, ale je třeba ji obnovit na všech místech, kam byla hodnota zkopírována. 2 Cross-site scripting je druh bezpečnostní díry, který umožňuje útočníkům vložit do stránky svůj clientside skript.
4.3. NĚKTERÉ DALŠÍ PRVKY IMPLEMENTACE
29
4. Jestliže byl formulář nesprávně vyplněn (vynechání povinné položky, nesprávný formát položky, . . . ) nebo došlo k jiné chybě (datum konce události je před začátkem, uživatelské jméno již bylo registrováno, . . . ), controller předá view chybové hlášky, které jím jsou zobrazeny u příslušných polí. Spolu s chybovými hláškami controller předává i samotný objekt formuláře, odkud view uživateli předvyplní jeho původní (i když špatná) data, aby nedošlo ke ztrátě informací a uživatel nebyl nucen vyplňovat celý formulář od začátku. 5. Jestliže byla data korektní, provede se cílová operace (uložení dat, přihlášení uživatele, . . . ) a obvykle je také uživatel přesměrován na cílovou stránku operace (stránka nově vytvořené události, profilová stránka uživatele, . . . ).
4.3.2
Dynamicky generovaný JavaScript
Protože aplikace pracuje s Google Maps prostřednictvím jeho klientského (JavaScript) API a pro některé operace nad mapou je potřeba dat uložených na straně serveru (např. uživatelem uložené preference či umístění událostí), je nutné generovat mapu ovládající funkce dynamicky. V aplikaci lze přistupovat ke generování JavaScriptu dvěma možnými způsoby. V první řadě v souboru scripts/dynamic/customMapOptions.js.php5 probíhá generování JS funkce setUsersMapAttributes(). PHP skript pouze načte přihlášeného uživatele ze session (pokud je přihlášen a pokud má nastavené preference) a vygeneruje příslušné volání GMaps API pro nastavení mapy. V této části implementace jsem se setkal se zajímavou chybu – PHP_Incomplete_Class. Ta byla způsobena použitím objektu User ze session, aniž by předtím byla tato třída načtena. Tuto chybu jsem vyřešil inicializací prázdného uživatele před použitím uživatele načteného ze session. Druhá možnost, jak v aplikaci generovat JavaScript, již byla zmíněna v části Controller (4.1.3), kdy je možné prostřednictvím proměnné customJavaScript generovat JS kód přímo v controlleru.
4.3.3
Dynamicky generované XML
Protože data aplikace jsou ukládána do databáze na straně serveru, ale současně je potřeba s nimi pracovat i na straně klienta pomocí JavaScriptu, bylo nutné vytvořit určitou formu databáze i právě na straně klienta. Nejlepší možností se jevilo XML, pro které existuje mnoho ověřených nástrojů a knihoven. Generování XML probíhá v souboru helpers/SpotsMarkers.xml.php5 a to pokaždé, kdy je o tento soubor požádáno. Tímto způsobem bude pravděpodobně docházet k redundantním dotazům na databázi, kdy se bude znovu generovat to samé XML, ačkoliv v databázi nejsou od generování předchozího žádná nová místa či události. Z důvodu zamezení předčasné optimalizace toto zatím není řešeno, avšak zapojení určité cache je předmětem dalšího rozvoje aplikace.
30
KAPITOLA 4. REALIZACE
K vytvoření XML dokumentu byly použity třídy DOMDocument a DOMElement, které pokrývají celou problematiku generování XML. Navíc bylo třeba pouze zajistit odeslání hlavičky Content-type: text/xml, pro informování prohlížeče, o jaký typ souboru se jedná. Ke každému místu jsou do informační bubliny na mapě přidány tři události a to tak, že pokud možno ty probíhající, jinak ty nadcházející a až nakonec uplynulé. Pro ušetření dotazů na databázi jsou načteny všechny události na příslušném pozorovacím místě a následně jsou filtrovány ve třídě EventService.
4.3.4 4.3.4.1
Práce s Google Maps zobrazení značek na mapě
Značky jsou na mapě zobrazovány pomocí funkce loadMarkersFromXml(), která se nachází v souboru scripts/gmapsskript.js. Část obsahu této funkce je možné vidět v ukázce C.7. Na začátku je jQuery metodou get asynchronně načten obsah XML souboru do proměnné data a následně je její obsah prohledán taktéž jQuery metodou find. Pro všechna nalezená pozorovací místa jsou vytvořeny jednak značky samotné, ale také informační bubliny, které jsou naplněny kromě základních informací o místě i již zmíněnými událostmi, které se zde konají, budou konat či konaly (tato část v ukázce C.7 z důvodu přehlednosti popisu funkcí kódu chybí, zpracování značek event je však velmi podobné zpracování značek spot). V závěru je nově vytvořené značce přiřazen listener pro zachytávání kliků na značku. Jako reakce na tyto kliky pak dochází k zobrazování (či skrývání) informační bubliny.
4.3.4.2
Vložení značky na mapu
Vkládání značky na mapu je použito při zakládání nového místa, což uživatelům poskytuje možnost definovat pozici místa na mapě bez nutnosti znalosti jeho GPS souřadnic. Tato funkce je realizována voláním placeMarker (také v souboru scripts/gmapsskript.js), kterému je předána pozice kliknutí na mapu z listeneru. Při prvním volání metody dojde k vytvoření značky a jejímu uložení do globální proměnné marker. Při dalších voláních je pak už pouze měněna pozice této značky metodou setPosition. Zároveň jsou do příslušných polí formuláře vloženy GPS souřadnice právě umístěné značky, které tu jsou pro pokročilé uživatele.
4.3.5
Práce s GPS souřadnicemi
Pro výpočet vzdálenosti mezi dvěma souřadnicemi byla použita třída GeoCalc, která byla původně napsána Andy McGovernem v C++ [1] a následně přepsána Stevenem Brendtroem (http://trac.guifi.net/trac/browser/guifi/drupal6x/modules/guifi/GeoCalc.class.php?rev=234) do PHP. Pro převod GPS souřadnic reprezentovaných jako desetinné číslo na stupně, minuty a vteřiny, což je pro člověka mnohem čitelnější podoba, je použita funkce Jakuba Vrány float2gps.
4.3. NĚKTERÉ DALŠÍ PRVKY IMPLEMENTACE
4.3.6
31
Načítání nejbližších pozorovacích míst – AJAX
Na úvodní stránce projektu se nachází seznam nejbližších pozorovacích míst (vzhledem ke středu mapy), který se při posunu mapy aktualizuje. JavaScript realizující asynchronní volání PHP skriptu byl napsán opět pomocí jQuery (funkce se nachází v souboru scripts/ajax.js), kde pouze stačilo zavolat funkci get s příslušnými parametry. Nesporná výhoda řešení touto knihovnou je kompatibilita s různými prohlížeči. Serverovou část reprezentuje PHP skript, který se nachází v souboru helpers/ajax/getSpotsByDistance.php5. Ten vrací HTML kód, který je klientskou stranou vložen do příslušného elementu DIV. Tento soubor by mohl být považován za potenciální bezpečností díru, protože je volán přímo z klientské části prostřednictvím své URL a nemůže tak být chráněn pomocí .htaccess, jako je tomu u většiny serverových souborů v tomto systému. Skript se však proveden pouze tehdy, jsou-li správně definovány vstupní parametry, a navíc provádí nad databází pouze čtecí operace. Jediné bezpečnostní riziko tak hrozí v podobě DoS3 útoku. Ten však hrozí i u ostatních skriptů a prevence takového útoku je nad rámec aplikační logiky tohoto systému.
4.3.7
Komponenty jQuery
Jak již bylo zmíněno, v aplikaci je upotřeben JavaScriptový framework jQuery (http://jquery.com/) a to včetně jQuery UI (http://jqueryui.com/). Ten je použit např. pro odesílání asynchronních požadavků, zpracování XML, ale i jednoduché animace na uživatelském rozhraní (např. při zobrazování informačních zpráv nebo při obnovení dat na titulní stránce). Z UI komponent byl použit kalendář pro volbu data (při zakládání nové události). Pro volbu času s posuvníky bylo nutné použít jQuery addon od Trenta Richardsona (http://trentrichardson.com/examples/timepicker/).
4.3.8
Tvorba multimediálních záznamů z pozorování
U událostí je pozorovatelům umožněno vytvářen záznamy, do kterých lze přidávat fotografie a videa z YouTube. Před uložením záznamu je navíc možné si nejdříve prohlédnout výsledek, jak bude po uložení záznam vypadat. Obrázky ani videa nejsou do databáze ukládány ve formě HTML, ale pouze jako interní značky (v případě obrázku) či pouhého odkazu (v případě YouTube videa), což ponechává do budoucna otevřenu možnost s těmito daty dále strojově pracovat. 4.3.8.1
Obrázky
Vložení obrázku se provádí skrze stejný formulář, jaký slouží pro přidání hlášení samotného. Při požadavku na odeslání formuláře s obrázkem dojde ještě před odesláním dat na server 3
Útok typu Denial-of-service obvykle spočívá v umělém vytvoření dotazů na systém v takovém množství, že dojde k jeho zahlcení a neschopnosti poskytovat služby svým skutečným uživatelům. Takový útok je však v efektivní podobě poměrně nákladný a lze ho předpokládat spíše u honosnějších aplikací, jako jsou např. internetová bankovnictví. [14]
32
KAPITOLA 4. REALIZACE
k vložení značky do textového pole s hlášením a to konkrétně na místo, kde se aktuálně nachází kurzor. Toto vložení značky na správně místo zajišťuje JavaScriptová funkce insertAtCursor. Na serveru je pak nahraný obrázek zpracován, a pokud se skutečně jedná o obrázek (a je v podporovaném formátu), dojde k jeho uložení do adresáře graphics/upload/reports (unikátnost názvu obrázku je zajištěna jeho složením z jedinečného identifikátoru události a aktuálního času). Značky, které byly do formuláře vloženy JS funkcí, jsou poté obohaceny o název nově nahraného obrázku. Tento přístup není ideální, a to proto, že nad jednou nahranými obrázky ztrácíme kontrolu. Pokud se tedy uživatel rozhodne vložený obrázek nepoužít, přesto již zůstane uložený na serveru. Toto by bylo možné vyřešit např. ukládáním názvů přiložených obrázků do databáze, přičemž nepoužité obrázky by byly při ukládání záznamu smazány. Jiným řešením by mohl být Cron4 job, který by jednou za určitý čas kontroloval, zda se všechny obrázky v příslušném adresáři nacházejí alespoň v jednom záznamu z pozorování. 4.3.8.2
YouTube videa
Při vložení YouTube videa do záznamu neprobíhají při ukládání žádné operace navíc, protože převod YouTube odkazu na přehrávač probíhá až při čtení záznamu. Pro detekci videí je použit regulární výraz, jemuž odpovídající odkazy jsou převedeny pomocí PHP funkce preg_replace na HTML, které prohlížeč interpretuje jako YouTube přehrávač.
4.3.9
Profilové fotografie – popup okna a cache
Nahrání nové profilové fotografie se provádí v popup okně, které je po úspěšném nahrání fotografie automaticky zavřeno funkcí window.close(), ještě předtím je však obnoven obsah otevírající stránky popup okna, aby došlo k načtení nového obrázku. To je provedeno nastavením adresy do proměnné window.opener.location.href a zavoláním funkce window.opener.focus(). Při nahrávání nových obrázků a jejich ukládání pod stejným názvem však nastává problém s cache pamětí prohlížeče, který pro ušetření zbytečných přenosů po síti a urychlení zobrazení stránky jednou načtené obrázky již znovu nenačítá. Uživatel by z tohoto důvodu nově nahraný obrázek bez tzv. tvrdého obnovení stránky neviděl. Tento problém jsem vyřešil přidáním prefixu iterator před název obrázku, přičemž při vytváření prvního obrázku je hodnota proměnné iterator nastavena na číslo 1. Při nahrávání nové profilové fotografie pak dochází před smazáním fotografie staré k zjištění současné hodnoty iterátoru, která je pro název nového obrázku navýšena o číslo 1. Tímto je zajištěno, že nově nahraná fotografie bude mít nové jméno a prohlížeč je nucen její obsah stáhnout ze serveru. Na druhou stranu funkčnost cache pro fotografie, které už není třeba stahovat, zůstává zachována (problém by se dal vyřešit dynamickým načítáním obrázků a odesíláním hlavičky s informací, že je obrázek starý, ale pak by došlo k úplnému zamezení cachování obrázků v prohlížeči). 4
Unixový program umožňující automatické spouštění jiných programů či skriptů v určitý čas a s danou periodicitou.
4.4. MODEL NASAZENÍ
4.3.10
33
Ukládání hesel
Při registraci nového uživatele je vyžadováno heslo, pomocí kterého se uživatel později může do aplikace přihlašovat. Tato hesla nejsou v databázi uložena v čiré (plain text) podobě, nýbrž jsou „osolena“ a následně zahashována. Díky tomu jsou uživatelská hesla v bezpečí i v případě, že by došlo např. k úniku surových dat z databáze. Implementační detaily zde z bezpečnostních důvodů nebudou zmíněny.
4.4
Model nasazení
Aplikace momentálně zkušebně běží na adrese http://jihocas.4td.cz/ a provoz odpovídá modelu nasazení na obrázku 4.3. V ostrém provozu se předpokládá model podobný či dokonce stejný.
Obrázek 4.3: UML diagram modelu nasazení
34
KAPITOLA 4. REALIZACE
Kapitola 5
Testování 5.1
Akceptační test
Akceptační test lze vykonat v rámci standardního prostředí a s výchozím nastavením souboru config.php (kromě nastavení přístupu k databázi, které je třeba upravit dle lokální konfigurace). V databázi musí být vytvořena struktura tabulek skriptem DDL.sql (který se nachází v adresáři model/dataLayer/SQL/database) a vložena výchozí data skriptem demo_data.sql. Akceptační test proběhnul s úspěšností 100%, přičemž jednotlivé testované položky je možné vidět v tabulkách D.1, D.2 a D.3.
5.2
Test validity HTML5
Validita stránek dle zvoleného doctype je důležitá z důvodu správného zobrazení obsahu v různých prohlížečích. Je však třeba myslet na to, že se jedná o podmínku nutnou, nikoliv však postačující a neméně důležitou roli hraje korektnost kaskákodých stylů CSS. V případě, kdy nejsou stránky napsané dle standardu, dochází k interpretaci (X)HTML v tzv. quirk módu, ve kterém se každý prohlížeč chová jinak, v závislosti na tom, jak se programátoři jednotlivých prohlížečů rozhodli k chybným stránkám zachovat. DTD jednotlivých typů dokumentů lze nalézt na webových stránkách konsorcia W3C (http://www.w3.org/), kde je možné validitu stránek také otestovat. Vzhledem k tomu, že se v systému nachází poměrně nízký počet stránek, provedl jsem jejich validaci ručně. Při testování jsem objevil některé menší chyby, které jsem ihned opravil a systém je proto nyní plně validní.
5.3
Test kognitivním průchodem
Při provádění kognitivního průchodu se snažíme simulovat, jak by asi postupoval uživatel aplikace. Zjišťujeme, zda aplikace uživatele vede ke splnění požadovaného úkolu. Pro všechny úkoly pak odpovídáme na následující otázky:
35
36
KAPITOLA 5. TESTOVÁNÍ
1. Bude uživateli zřejmé, jakou akci použít? 2. Spojí si uživatel popisek u požadované akce s tím, co chce udělat? 3. Dostane uživatel dostatečnou zpětnou vazbu o provedení akce?
5.3.1
Založení nového místa
1. Ano 2. Ano 3. Ano Problém může nastat v případě, kdy se uživatel nenachází na své profilové stránce a není si vědom toho, že právě ze své profilové stránky může místa zakládat. Uživatel je však na svou profilovou stránku přesměrován ihned po registraci a pravděpodobně si zapamatuje, že na jeho profilové stránce „nějaké“ akce jsou.
5.3.2
Založení nové události na určitém místě
1. Ano 2. Ano 3. Ano Problém může nastat, pokud uživatel neví, že nové události lze zakládat ze stránky pozorovacího místa.
5.3.3
Přidání místa mezi oblíbené
1. Ano 2. Ano 3. Ano
5.3.4
Přidání komentáře k pozorovacímu místu
1. Ano 2. Ano 3. Ano
5.3. TEST KOGNITIVNÍM PRŮCHODEM
5.3.5
37
Přidání záznamu z pozorování k události
1. Ano 2. Ano 3. Ano
5.3.6
Přihlášení se k účasti u události
1. Ano 2. Ano 3. Ano
5.3.7
Uložení výchozí pozice mapy
1. Ano 2. Ano 3. Ano Problém může nastat, pokud uživatel neví, že změnit výchozí pozici mapy lze z jeho profilové stránky.
5.3.8
Výsledky kognitivních průchodů
Kognitivní průchody zvolených úkolů proběhly dobře. Problém může nastat pouze u operací, které různí lidé (s různými mentálními modely) mohou očekávat na různých místech. Pokud se při dalších testech s uživateli zjistí, že toto skutečně je problém, řešením by mohlo být vytvoření menu v hlavičce s problematickými operacemi či vytvoření FAQ stránky.
38
KAPITOLA 5. TESTOVÁNÍ
Kapitola 6
Závěr 6.1 6.1.1
Shrnutí výsledků a zhodnocení splnění cílů Srovnání relačních a bezschémových databází
V sekci 3.1.1 byl nastíněn úvod do bezschémových databází a především bylo provedeno srovnání s databázemi relačními (v sekci 3.1.2). Při srovnání bylo zjištěno, že bezschémové databáze jsou ideální pro projekty, kde je klíčová rychlost, prostor pro enormní množství dat, škálovatelnost a flexibilita datového modelu. Pokud však vyžadujeme komplexní transakce, je pro nás důležité, abychom používali ověřené a široce rozšířené řešení se strmou křivkou učení a nejsme ochotni přistoupit k denormalizaci dat (při zachování dobré rychlosti a prostoru pro přiměřené množství dat), měli bychom zvolit spíše databázi relační.
6.1.2
Implementace informačního systému pro JihoČAS
Informační systém byl plně implementován s použitím relační databáze a částečně i s použitím databáze bezschémové (pro účely demonstrace odlišnosti). Výsledná aplikace splňuje všechny definované požadavky (viz sekce 2.1). Subjektivně ji považuji za zdařilou a reakce na beta verzi byly též velmi pozitivní. Objektivně budeme moci úspěšnost aplikace posoudit až po jejím dokončení a oficiálním spuštění.
6.1.3
Rozdíly v implementaci při použití bezschémové databáze
Z teoretického hlediska je důležitým výsledkem této práce zjištění, že implementace systému pro bezschémovou databázi nepředstavuje velký problém. Jak je demonstrováno v sekcích 4.1.1.1 a 4.2, pokud je zajištěno dobré oddělení datové vrstvy od zbytku systému, implementace pro bezschémovou databázi se kromě komunikace s databází nijak neliší od implementace pro databázi relační.
39
40
KAPITOLA 6. ZÁVĚR
6.1.4
Otestování implementovaného systému
Implementovaný systém byl otestován (viz kapitola 5). Dále proběhl beta-test s šesti uživateli, z nichž dva jsou členové ČAS. Nebyl proveden pouze test zátěže.
6.2
Zhodnocení přínosu práce
Jelikož je tato práce z části teoretická, a z části praktická, je vhodné ji posuzovat ze dvou pohledů. Přínos práce z teoretického hlediska vidím především v podání konkrétního příkladu o jednoduchosti implementace aplikace nad bezschémovou databází. Mnoho programátorů se NoSQL databázím vyhýbá pouze z neochoty učit se novou technologii, proto podávám touto formou důkaz, že křivka učení je u obou databází přinejmenším srovnatelně strmá. Nezanedbatelným přínosem je také poskytnuté srovnání obou databází, na základě kterého je možno učinit informované rozhodnutí, zda použít pro různé projekty databázi bezschémovou či relační. Přínos praktického výsledku této práce – implementovaný systém pro organizaci pozorování – bude možné posoudit až po nasazení aplikace do produkce a bude jistě záležet také na jejím patřičném uvedení mezi současné členy JihoČASu. Subjektivně má systém reálnou šanci stát se mezi astronomy oblíbeným. Ohlasy z testování velmi omezenou skupinou uživatelů jsou velmi pozitivní.
6.3
Zamyšlení se nad použitelností bezschémových databází
Bezschémové databáze mají své místo v budoucnosti zajištěné díky tzv. cloud computingu, se kterým jsou neoddělitelně spjaty. Věřím však (a spolu se mnou mnozí další), že bezschémové databáze mohou být uplatněny i u menších systémů, které nevyužijí jejich možnosti takřka neomezeného škálování. Data jsou na straně databáze uložena v podobě velmi blízké jejich reprezentaci na straně aplikace a převod mezi jednotlivými podobami je tak podstatně jednodušší. Překážku rozšíření bezschémových databází v řadách odborné veřejnosti představuje především velká popularita SQL databází, kdy znalost jedné technologie představuje bariéru v podobě neochoty učit se podstatu technologie jiné. Tato překážka bude pravděpodobně (s ohledem na oblíbenost ORM1 frameworků) o něco snížena po vydání dobrého ODM2 frameworku, což bude v případě PHP nejspíš MongoDB Object Document Mapper (http://www.doctrine-project.org/projects/mongodb_odm) z dílny týmu Doctrine (pro většinu ostatních programovacích jazyků probíhá vývoj ODM též). 1
Objektově relační mapování slouží k transformaci záznamů databáze na objekty aplikace a též k interpretaci prvků objektově orientovaného jazyka do relačního světa. 2 Objektově dokumentové mapování slouží k transformaci dokumentů bezschémové databáze na objekty aplikace a též k interpretaci prvků objektově orientovaného jazyka do světa dokumentů.
6.4. DALŠÍ MOŽNÉ POKRAČOVÁNÍ PRÁCE
6.4
41
Další možné pokračování práce
Implementovaný systém není v aktuální podobě zcela dokončený a před jeho spuštěním je v plánu vytvoření několika prvků, které vyplynuly při implementaci funkcí naplánovaných pro tuto práci. Uvádím zde pouze některé: • Pozorovací místa (jejich názvy nebo i další atributy) bude možné editovat jejich zakladateli. • Pozorovací místo bude obsahovat seznam lidí, kteří se na něm právě nachází. • Pro přidávání pozorovatelů k privátnímu místu bude vytvořen našeptávač. • Na stránkách pozorovacích míst bude chat (týkající se pouze tohoto místa). Na titulní stránce se budou zobrazovat zprávy ze všech míst. • Registrace bude chráněna proti spamu (CAPTCHA). • Generované XML s pozorovacími místy bude obsahovat vyrovnávací paměť (cache). • Při archivaci místa v administraci bude administrátor upozorněn, pokud archivuje místo, na kterém jsou probíhající nebo naplánované události. • Uživatel bude moci právě pozorovat pouze na jednom místě. • Pozorovací místa, která se nacházejí blízko sebe, budou při oddálení mapy sdružována pomocí utility MarkerClusterer (http://code.google.com/p/gmaps-utility-librarydev/). Pokud bude systém úspěšný na úrovni Jihočeského kraje, je v plánu jeho prosazení u poboček ČAS po celé České republice.
42
KAPITOLA 6. ZÁVĚR
Literatura [1] Andy McGovern. Geographic Distance and Azimuth Calculations [online]. 2011. [cit. 11. 5. 2011]. Dostupné z:
. [2] Antonín Daněk, Jakub Stejskal. Model-View-Controller vs. Presentation-AbstractionControl [online]. 2011. [cit. 21. 5. 2011]. Dostupné z:
. [3] Artur Ejsmont. Insert performance comparison of NoSQL vs SQL servers [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: . [4] Avi Kapuya. NoSQL - the SQL [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [5] Bill Nigh. NoSQL DB vs SQL Performance Monitoring [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [6] claus. NoSQL vs. SQL [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [7] Eliot Horowitz. MapReduce [online]. 2011. [cit. 28. 3. 2011]. Dostupné z: . [8] Ian Rogers. Compare sql vs. nosql [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [9] Ilya Grigorik. Schema-Free MySQL vs NoSQL [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [10] ishaan. Yet another MongoDB Map Reduce tutorial [online]. 2011. [cit. 28. 3. 2011]. Dostupné z: . [11] Karel Minařík. CouchDB — Databáze pro web [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: . [12] KRISTINA CHODOROW, M. D. MongoDB: The Definitive Guide. : O’Reilly Media Inc, California, 1st edition, 2010. In English.
43
44
LITERATURA
[13] Loraine Lawson. The Business Pros and Cons of NoSQL [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [14] Přispěvatelé Wikipedie. Denial-of-service attack [online]. 2011. [cit. 11. 5. 2011]. Dostupné z: . [15] Přispěvatelé Wikipedie. Linearizability [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: . [16] Přispěvatelé Wikipedie. Memcached [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: . [17] Přispěvatelé Wikipedie. SQL injection [online]. 2011. [cit. 22. 5. 2011]. Dostupné z: . [18] Rick Osborne. Playing around with MongoDB and MapReduce functions [online]. 2011. [cit. 28. 3. 2011]. Dostupné z: . [19] Rick Osborne. InfoGraphic: Migrating from SQL to MapReduce with MongoDB [online]. 2011. [cit. 28. 3. 2011]. Dostupné z: . [20] Rick Osborne. Yes, Virginia, that’s automated SQL to MongoDB MapReduce [online]. 2011. [cit. 28. 3. 2011]. Dostupné z: . [21] [email protected]. NoSQL Technology [online]. 2011. [cit. 26. 3. 2011]. .
Dostupné z:
[22] Todd Hoff. What the heck are you actually using NoSQL for? [online]. 2011. [cit. 27. 3. 2011]. Dostupné z: . [23] unknown. RDBMS vs NoSQL [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: . [24] unknown. Why MongoDB Writes are Faster than MySQL? [online]. 2011. [cit. 26. 3. 2011]. Dostupné z: .
Příloha A
Seznam použitých zkratek AAS American Astronomical Society ACID Atomicity, Consistency, Isolation, Durability AJAX Asynchronous JavaScript and XML API Application programming interface ČAS Česká astronomická společnost ČVUT České vysoké učení technické DAO Data Access Object DoS Denial-of-service DTD Document Type Definition FAQ Frequently Asked Questions GPS Global Positioning System HTML HyperText Markup Language HTTP Hypertext Transfer Protocol IS Informační systém JSON JavaScript Object Notation MVC Model-View-Controller NASA National Aeronautics and Space Administration NoSQL Not Only SQL ODM Object-Document Mapping ORM Object-Relational Mapping
45
46
PŘÍLOHA A. SEZNAM POUŽITÝCH ZKRATEK
PDO PHP Data Objects PHP PHP: Hypertext Preprocessor (rekurzivní akronym) RDBMS Relational database management system SQL Structured Query Language CSS Cascading Style Sheets UML Unified Modeling Language W3C World Wide Web Consortium XML Extensible Markup Language XAMPP X(cross-platform) Apache MySQL PHP Perl XSS Cross-site scripting
Příloha B
UML diagramy
Obrázek B.1: Grafické znázornění adresářové struktury aplikace
47
48
PŘÍLOHA B. UML DIAGRAMY
Příloha C
Ukázky zdrojových kódů
Listing C.1: Ukázka čtecí operace nad relační databází
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public function getSpotsCreatedBy ( $userId ) { if ( ! isset ( $userId ) ) return null ; $spots = array (); $sql = " SELECT spots .* FROM spots WHERE spots . creator = ’ " . Utils :: gpcAddslashes ( ( int ) $userId ). " ’" ; $query = MyDb :: query ( $sql ); if ( $query - > rowCount () == 0) return null ; $rows = $query - > fetchAll (); foreach ( $rows as $row ) { $spot = Mapper :: mapSpot ( $row ); $spots [] = $spot ; } return $spots ;
}
49
50
PŘÍLOHA C. UKÁZKY ZDROJOVÝCH KÓDŮ
Listing C.2: Ukázka vkládací operace nad relační databází
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public function createNewUser ( RegistrationForm $data ){ $sql = " INSERT INTO users ( ‘ id ‘ , ‘ name ‘ , ‘ surname ‘ , ‘ login ‘ , ‘ password ‘) VALUES (0 , ’" . Utils :: gpcAddslashes ( $data -> getName ()). " ’, ’" . Utils :: gpcAddslashes ( $data - > getSurname ()). " ’ , ’" . Utils :: gpcAddslashes ( $data - > getEmail ()). " ’, ’" . Utils :: gpcAddslashes ( /* hashovani hesla */ ) . " ’); " ; MyDb :: query ( $sql ); return $this - > getUserByEmail ( $data - > getEmail ());
}
51
Listing C.3: Ukázka vkládací operace do joinovací tabulky nad relační databází
1 public function add AttendingUs erToEvent ( $userId , 2 $eventId , $attendTypeId , 3 $addPoints , $addKarma ){ 4 5 if (! isset ( $userId ) || 6 ! isset ( $eventId )) return null ; 7 8 if ( $addPoints ) { 9 DaoFactory :: getUserDao () 10 -> i n c r e a s e U s e r s C l a s s i f i c a t i o n P o i n t s ( $userId ); 11 } 12 if ( $addKarma ){ 13 DaoFactory :: getUserDao () 14 -> increaseUsersKarma ( $userId ); 15 } 16 17 $sql = " INSERT INTO eventsAttendees ( ‘ event ‘ , 18 ‘ user ‘ , ‘ attendType ‘) 19 VALUES ( ’ " . Utils :: gpcAddslashes ( ( int ) $eventId ). 20 " ’, ’" . Utils :: gpcAddslashes ( ( int ) $userId ). 21 " ’, ’" . Utils :: gpcAddslashes ( 22 ( int ) $attendTypeId ). " ’); " ; 23 MyDb :: query ( $sql ); 24 25 }
52
PŘÍLOHA C. UKÁZKY ZDROJOVÝCH KÓDŮ
Listing C.4: Ukázka čtecí operace nad bezschémovou databází
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
public function getSpotsCreatedBy ( $userId ) { if ( ! isset ( $userId ) ) return null ; $spots = array (); $searchDocument = array ( ’ creator . _id ’ = > new MongoId ( $userId ) ); $db = new MyDb (); $db - > setCollection ( " spots " ); $rows = $db - > get ( $searchDocument , null );
if ( count ( $rows ) == 0) return null ; foreach ( $rows as $row ) { $spot = Mapper :: mapSpot ( $row ); $spots [] = $spot ; } return $spots ;
}
53
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Listing C.5: Ukázka vkládací operace nad bezschémovou databází
public function createNewUser ( RegistrationForm $data ) { $newUser = array ( " name " = > $data - > getName () , " surname " = > $data - > getSurname () , " login " = > $data - > getEmail () , " password " = > /* hashovani hesla */ , " longitude " = > null , " latitude " = > null , " zoom " = > null , " karma " = > 0 , " profilePicture " = > null , " classificationPoints " = > 0 ); $db = new MyDb (); $db - > setCollection ( " users " ); $db - > insert ( $newUser ); return $this - > getUserByEmail ( $data - > getEmail ());
}
54
PŘÍLOHA C. UKÁZKY ZDROJOVÝCH KÓDŮ
Listing C.6: Ukázka upravovací operace nad bezschémovou databází
1 public function add AttendingUs erToEvent ( $userId , 2 $eventId , $attendTypeId , $addPoints , 3 $addKarma ) { 4 5 if (! isset ( $userId ) || 6 ! isset ( $eventId )) return null ; 7 8 if ( $addPoints ) { 9 DaoFactory :: getUserDao () 10 -> i n c r e a s e U s e r s C l a s s i f i c a t i o n P o i n t s ( $userId ); 11 } 12 if ( $addKarma ){ 13 DaoFactory :: getUserDao () 14 -> increaseUsersKarma ( $userId ); 15 } 16 17 $eventToAdd = DaoFactory :: getEventDao () 18 -> getEventById ( $eventId ); 19 20 $searchDocument = array ( 21 ’ _id ’ = > new MongoId ( $userId ) 22 ); 23 24 $updateDocument = array ( ’ $addToSet ’ = > array ( 25 ’ attendedEvents ’ = > array ( 26 " _id " = > $eventToAdd - > getId () , 27 " eventName " = > $eventToAdd - > getEventName () , 28 " eventUrl " = > $eventToAdd - > getEventUrl () , 29 " attendType " = > $attendTypeId , 30 " fromDate " = > $eventToAdd - > getFromDate () , 31 " toDate " = > $eventToAdd - > getToDate () 32 ) 33 )); 34 35 $db = new MyDb (); 36 $db - > setCollection ( " users " ); 37 $rows = $db - > update ( $searchDocument , 38 $updateDocument ); 39 40 }
55
Listing C.7: Ukázka načtení značek mapy z XML
1 jQuery . get ( " helpers / SpotsMarkers . xml . php5 " , {} , 2 function ( data ) { 3 4 jQuery ( data ). find ( " spot " ). each ( function () { 5 6 var marker = jQuery ( this ); 7 var latlng = new google . maps . LatLng ( 8 parseFloat ( marker . attr ( " lat " )) , 9 parseFloat ( marker . attr ( " lng " )) 10 ); 11 12 ... 13 ... 14 15 var newMarker = new google . maps . Marker ({ 16 position : latlng , 17 map : map , 18 icon : image , 19 shadow : shadow , 20 title : marker . attr ( " name " ) 21 }); 22 23 var markersBubble = new google . maps . InfoWindow ( 24 ... 25 ); 26 27 google . maps . event . addListener ( newMarker , ’ click ’ , 28 function () { 29 30 markersBubble . open ( map , newMarker ); 31 }); 32 33 }); 34 35 });
56
PŘÍLOHA C. UKÁZKY ZDROJOVÝCH KÓDŮ
Příloha D
Výsledky akceptačního testu
57
58
PŘÍLOHA D. VÝSLEDKY AKCEPTAČNÍHO TESTU
Požadavek Systém bude umožňovat registraci nového uživatele. O úspěšné registraci bude systém uživatele informovat e-mailem. Systém bude umožňovat přihlášení a odhlášení uživatele. Neregistrovaný uživatel bude mít omezená práva. Bude si moci pouze pasivně prohlížet veřejný obsah. Profil uživatele bude obsahovat fotografii, historii navštívených událostí, seznam oblíbených pozorovacích míst, seznam založených pozorovacích míst, seznam privátních pozorovacích míst a nastavení odebíraných informací o místech. Registrovaný uživatel si bude moci přidat pozorovací místo mezi svá oblíbená místa. Registrovaný uživatel si bude moci nastavit preferovanou úroveň přiblížení a výchozí pozici mapy (domácí souřadnice). Registrovaný uživatel bude moci vytvářet pozorovací místa. Registrovaný uživatel bude moci vytvářet události (i na místech, které sám nezaložil, pokud je toto místo veřejné nebo pokud je místo privátní, ale uživatel je v seznamu privátních pozorovatelů tohoto místa). Registrovaný uživatel se bude moci přihlásit k odběru informací o událostech na pozorovacích místech (např. založení nové události). Registrovaný uživatel dostane za každých 10 návštěv pozorovacích míst (jiných, než těch, které sám vytvořil) jeden volný bod hodnocení. Tento bod hodnocení může registrovaný uživatel použít k zlepšení hodnocení pozorovacího místa. Každá navštívená událost registrovaného uživatele bude zaznamenávána. Součet těchto návštěv bude odpovídat uživatelovo osobnímu hodnocení (karma). Registrovaný uživatel se bude moci přihlásit k události se stavy: „Možná se zúčastním“, „zúčastním se“, „ jsem na místě, ale nepozoruji“, „ jsem na místě a pozoruji“. Tabulka D.1: Akceptační test požadavků týkajících se uživatele
Splněno ano ano ano ano
ano ano ano ano
ano ano
ano
ano
59
Požadavek Pozorovací místo bude obsahovat popis, zeměpisné souřadnice, datum založení, zakladatele, komentáře registrovaných uživatelů a seznam událostí na tomto místě. Událost bude obsahovat popis, pozorovací místo, datum založení, zakladatele, seznam účastníků a hlášení z pozorování. Pozorovací místa budou privátní a veřejná. Privátní pozorovací místa budou viditelná pouze pro vyjmenované pozorovatele. Veřejná místa budou viditelná pro všechny. Vyjmenovat pozorovatele privátního místa bude moci pouze jeho zakladatel. K pozorovacímu místu bude moci registrovaný uživatel přidat komentář. Všichni účastníci události budou moci k této události přidat multimediální hlášení, do kterého bude možné přidávat videa z YouTube a obrázky.
Splněno ano
ano ano
ano ano ano
Tabulka D.2: Akceptační test požadavků týkajících se pozorovacích míst a událostí
Požadavek V systému budou „pozorovací místa“ a „události“. Události lze vytvořit pouze na pozorovacích místech. Google Mapa bude zobrazovat pozorovací místa. Na Google Mapě budou odlišena (zvýrazněna) ta pozorovací místa, kde právě někdo pozoruje. Otevřený detail (bublina v Google maps) pozorovacího místa na mapě bude obsahovat aktuální pozorování. Úvodní stránka bude obsahovat seznam pozorovacích míst, setříděných podle vzdálenosti od aktuálního středu zobrazené mapy. Vedle mapy bude tlačítko pro přechod na domácí souřadnice. Systém bude nabízet sérii ikon pro různé druhy objektů na mapě. Systém bude obsahovat tři role: „neregistrovaný uživatel“, „registrovaný uživatel“ a „administrátor“. Administrátor bude moci archivovat pozorovací místa. Administrátor bude mít práva pro přístup do všech pozorovacích míst, včetně těch privátních. Tabulka D.3: Akceptační test ostatních požadavků
Splněno ano ano ano ano ano ano ano ano ano ano
60
PŘÍLOHA D. VÝSLEDKY AKCEPTAČNÍHO TESTU
Příloha E
Instalační a uživatelská příručka E.1 E.1.1
Instalační příručka PHP + MySQL
Aplikace byla vyvíjena na PHP verze 5.3.1, serveru Apache verze 2.2.14 a MySQL verze 5.3.1. Vše zmíněné lze jednoduše nainstalovat pomocí balíčku XAMPP (verze 1.7.3) (http://www.apachefriends.org/en/xampp.html). Již v době psaní této dokumentace však byla vydána novější verze (s novější verzí PHP apod.). Použití novější verze by nemělo představovat problém, dokud všechny systémy zajišťují zpětnou kompatibilitu, což však nemusí vždy platit (zejména u PHP). V takovém případě je možné stáhnout starší verzi XAMPPu (http://sourceforge.net/projects/xampp/files/). XAMPP (pro Windows) lze nalézt také na přiloženém CD v adresáři execution-environments. Samozřejmě je také možné provést instalaci každé komponenty zvlášť. Výhodou balíčku XAMPP je kromě kompaktnosti všech tří důležitých systémů pro vývoj v PHP i instalace nejčastěji používaných ovladačů. Pro připojení se z PHP k MySQL (ale i MongoDB) už tedy není třeba instalovat další komponenty.
E.1.2
MongoDB
Pro testování běhu aplikace nad bezschémovou databází je nutné nainstalovat MongoDB server (http://www.mongodb.org/). Při implementaci byl použit server verze 1.6.3.
E.1.3
Nahrání souborů na server
Po instalaci serverů je nutné do veřejně dostupného adresáře aplikačního serveru nahrát soubory aplikace (viz přiložené CD). Kromě toho je také nutné nastavit práva pro zápis adresářům graphics/upload/profiles a graphics/upload/reports.
61
62
PŘÍLOHA E. INSTALAČNÍ A UŽIVATELSKÁ PŘÍRUČKA
E.1.4
Konfigurace aplikace
Konfigurace aplikace probíhá pouze v souboru config.php5. Celý soubor je komentovaný, nicméně pro spuštění aplikace postačuje upravit hodnoty těchto konstant: • ADR – URL adresa aplikace, bez konečného lomítka. • DB_NAME – Název databáze. • HOST – URL adresa databázového serveru. • USER – Uživatelské jméno pro přístup do databáze. • PASSWORD – Heslo pro přístup do databáze. Přidání administrátorského účtu lze provést ve třídě Administrators, která se též nachází v souboru config.php5 (tento uživatel však musí být v aplikaci registrován klasickým způsobem, nedojde k jeho automatickému vytvoření – na pořadí těchto operací nezáleží).
E.2
Uživatelská příručka
Systém neobsahuje složité uživatelské rozhraní a lze se v něm orientovat i bez uživatelské příručky. Uvádím pouze popis některých stránek systému. Po spuštění aplikace (pokud není v Apache nastaven soubor index.php5 jako možný automatický vstupní soubor, je třeba za adresu serveru vložit index.php5 ) se zobrazí úvodní obrazovka E.1. Zde je možné se přihlásit nebo registrovat (vpravo nahoře). Na profilové stránce uživatele, kterou je možné vidět na obrázku E.2, lze uložit výchozí souřadnice mapy, založit nové pozorovací místo či nahrát profilovou fotografii. Na stránce pozorovacího místa (E.3) je možné vedle názvu místa vidět až tři druhy ikon (pokud máme místo přidané mezi oblíbenými, odebíráme z něj novinky nebo se jedná o místo soukromé). Nachází se zde také ovládací prvky pro přidání právě prohlíženého místa mezi oblíbené, přihlášení se k odběru novinek či založení nové události. Také zde lze k místu přidat komentář. Pokud je zobrazené místo privátní a právě přihlášený uživatel je jeho zakladatel, lze zde také přidávat privátní pozorovatele. Na stránce události (E.4) lze nastavit účást na této události a v případě, že je aktuální uživatel k události již přihlášen, je zde také tlačítko pro přidání nového záznamu z pozorování.
E.2.1
Administrace
Administrace aplikace se nachází na adrese aplikace v souboru admin.php5 a je přístupná pouze administrátorům. Přihlášený administrátor má k dispozici odkaz mířící do administrace přímo v aplikaci a to vpravo nahoře (za svým jménem).
E.2. UŽIVATELSKÁ PŘÍRUČKA
Obrázek E.1: Ukázka úvodní stránky aplikace
Obrázek E.2: Ukázka profilové stránky uživatele
63
64
PŘÍLOHA E. INSTALAČNÍ A UŽIVATELSKÁ PŘÍRUČKA
Obrázek E.3: Ukázka stránky pozorovacího místa
Obrázek E.4: Ukázka stránky události
Příloha F
Obsah přiloženého CD |--project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . soubory aplikace |--controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . controllery aplikace |--graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . obrázky aplikace |--helpers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . pomocné PHP skripty aplikace |--libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Smarty |--model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . modely aplikace |--nbproject . . . . . . . . . . . . pracovní soubory vývojového prostředí NetBeans 6.9.1 |--scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . statický a dynamický JavaScript, jQuery |--styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CSS styly a jQuery UI |--view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . views aplikace |--text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . text této práce ve formátu PDF |--src . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . zdrojové soubory (LATEX) této práce |--figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PDF soubory, použité v práci |--pictures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . obrázky, použité v práci |--execution-environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XAMPP
65