Tvorba databázových formulářů v OpenOffice.org

Úvod

V práci dělám výrobní informační systém na základě PostgreSQL a PHP. I když je internetový prohlížeč velmi univerzální nástroj a textový Lynx se dá použít na velké množství pořizováků - i rychlost vývoje a následně i rychlost aplikace Lynx+PostgreSQL+PHP je obdivuhodná - má takový přístup některá zásadní omezení. Nikdy jsem například nedokázal vyrobit pořizovák jako klasickou tabulku (typu Calc, Excel a podobně). Proto mě vždycky lákala třída JTable v Javě (s tím je ale neuvěřitelně mnoho práce) a když jsem získal představu o možnostech formulářů v OpenOffice.org, měl jsem na pár dnů o zábavu postaráno.

Vytvoření databázových tabulek

Předpokládám, že jste si přečetli můj minulý článek o připojení OpenOffice.org na databázi a podařilo se vám rozchodit vše, o čem jsem psal.

V minulém článku o propojení databáze s OpenOffice.org jsem vyrobil jednoduchou tabulku s telefonním seznamem. Pro účely tohoto článku se telefonního seznamu přidržím. Původní tabulku ovšem zlikviduji a aby to nebylo tak jednoduché, vyrobím tabulky tři. Bude to trochu umělý příklad. Vyrábět nic složitějšího se mi nechce - sám vím, jaké mám problémy sledovat něčí myšlenkové pochody v různých návodech, článcích a dokumentacích. Bohužel jednodušší příklad jsem vymyslet nedokázal. Každé další zjednodušení by znamenalo vzdát se některé významné části databázových formulářů a popis by tak byl neúplný.

V první tabulce mějme uskladněny lidi. Každý člověk bude mít své číslo, jméno a příjmení. Více nebudeme v telefonním seznamu potřebovat. Pro jednoduchost budeme číslo přidělovat my a nenecháme to na databázi. Tady si to zjednodušuju sám: ve velkém množství svých tabulek používám pro vytváření čísel záznamů datový typ serial a zatím jsem nepřišel na rozumný způsob práce s tímto datovým typem ve formulářích OpenOffice.org.

V další tabulce budou telefonní čísla. Každý záznam bude obsahovat číslo člověka, telefonní číslo a nakonec operátora. Poslední položku jsem si vymyslel zcela záměrně, abych mohl ukázat jednu z vlastností formulářů. Protože OpenOffice.org vyžaduje od databázových tabulek primární klíče, musel jsem v tabulce definovat klíč nad více položkami.

A nakonec ve třetí tabulce bude jen operátor a jeho textový popis.

Datový zdroj mám nastavený tak, že k databázi přistupuji jako uživatel office. Po vytvoření tabulek proto musím myslet i na příslušná oprávnění.

Kontrola dat

Jakmile zpřístupníte obyčejným uživatelům databázové tabulky pro zápis, můžete se dočkat mnoha nepříjemných překvapení. I když se vám podaří vyrobit neprůstřelný formulář a pomocí maker zkontrolovat před zápisem všechna data, uživatel může kdykoliv narazit na svém počítači na klávesu F4 a začít se prohrabovat v tabulkách přímo, bez zastřešující aplikace. Proto rozumná databáze musí uložená data před nezbednými uživateli chránit. Málokdy něco v textech zvýrazňuji, ale v tomto případě se mi zdá zdůraznění základní myšlenky na místě. Z principu je zhola nemožné ochránit data sebelepší kontrolou v aplikaci.

Základní kontroly poskytují už cizí klíče (slovo references při tvorbě tabulek). Nelze například databázi vnutit telefonní číslo na neexistujícího člověka. Další kontroly lze zajistit pomocí příkazu (klauzule, slova?) check u databázové položky při vytváření tabulky. Takto jsou kontrolované položky lidi.oc a operatori.operator. Kontrolu lze nakonec zajistit i pomocí speciálně vytvořených databázových funkcí. Takto je kontrolovaný tvar telefonního čísla (trochu divoká kontrola, připouštím). Funkce je napsaná v jazyce Pl/PgSQL a aby vám příklad fungoval, musí být jazyk Pl/PgSQL v databázi definován.

V případě složitějších datových modelů lze skutečné tabulky od uživatele odstínit úplně. V databázi PostgreSQL je možné nastavit uživatelská práva i pro funkce. Pro zápis do databáze se vytvoří virtuální tabulka a funkce volaná triggerem před zápisem rozhodí zkontrolovaná data do všech skutečně existujících tabulek. Virtuální tabulku lze pomocí pravidel přetvořit na view (create rule "_RETURN" as on select to tabulka do instead select * from jina_tabulka). Běžný uživatel pak nemá nejmenší šanci vnutit databázi nezkontrolovaná data. (V PostgreSQL se s termínem virtuální tabulka nesetkáte. Já jsem takto označil tabulku, která sice existuje, ale neobsahuje žádné věty a při zápisu a při čtení se pracuje ve skutečnosti s úplně jinými tabulkami. Postup jsem naznačil v jednom ze svých starších článků na Rootu).

Bez kontrol je snadné vyrobit v datech chaos i bez uživatele s přílišným objevitelským nadšením. Stačí, když nad tabulkami pracuje více lidí najednou a jeden uživatel smaže druhému pod rukama rozpracovaný záznam. Bez zajištění referenční integrity cizími klíči pak uživatel může vesele zapisovat telefonní čísla neexistujících lidí a za pár chvil se divit, kam se jeho záznamy poděly. Nikam se nepoděly - stále leží osiřelé v databázové tabulce a v aplikaci neexistuje prostředek, kterým by bylo možné takové záznamy objevit a uvést do pořádku.

Omlouvám se za trochu obšírnější úvod do zabezpečení a kontroly dat, ale připadá mi zbytečné se zabývat databázovými formuláři, neexistuje-li záruka, že údaje v databázi jsou pravdivé a úplné a že tak zůstanou i poté, co uživatelé dostanou ke své práci několik formulářů.

Celý skript pro vytvoření tří jednoduchých databázových tabulek je díky kontrolám trochu rozsáhlejší, takže jsem jím nezatěžoval tento text a umístil jej do samostatného souboru.

Nejjednodušší cesta k formuláři

Nejjednodušším způsobem, jak něco v OpenOffice.org vyrobit, je "Průvodce". Pomocí "Průvodce" lze vyrobit pochopitelně i jednoduchý formulář. Aby i v naší ukázce obsahoval jednoduchý formulář nějaká užitečná data, je v přiloženém SQL skriptu pamatováno i na view, složené ze všech tří datových tabulek. Protože do view normálně nelze zapisovat, bude náš formulář pouze pro čtení, nebude možné data vkládat.

Momentálně ale nevadí, že je formulář jen pro čtení, protože mířím s popisem formulářů trochu dál. Nakonec si ukážeme, jak propojit v jediném formuláři všechny tři datové tabulky. Můžete si samozřejmě vyzkoušet vytvořit formulář z tabulky lidi, který vám umožní data v tabulce upravovat. Ve formuláři ovšem nebudou všechna potřebná data.

"Průvodce" najdete v menu Soubor->Průvodce->Formulář. Samotná tvorba je jednoduchá a když vyberete některou z voleb, okamžitě vidíte na obrazovce vzhled formuláře. Dvě z různých podob formulářů můžete vidět na obrázcích.

Obrázek: Jednoduchý formulář (tabulka) vytvořený Průvodcem

Obrázek: Jednoduchý formulář vytvořený Průvodcem

Formulář vytvořený s pomocí "Průvodce" můžeme samozřejmě upravit podle svých představ. Nástroj pro úpravu formulářů najdete na "Hlavním panelu nástrojů" (v menu Zobrazit->Panely Nástrojů->Hlavní panel nástrojů). Nástroj se jmenuje "Ovládací prvky formuláře" a nachází se pod touto ikonkou:

Obrázek: Ovládací prvky formuláře

Krátkým kliknutím přepínáme formulář z provozního do editačního režimu a zpět. Samotný nástroj s ovládacími prvky zapneme delším podržením tlačítka myši. Pomocí tohoto nástroje můžete vkládat do formuláře další prvky, zapínat/vypínat další nástroje a upravovat různé vlastnosti formuláře.

Zapněte režim návrhu formuláře, označte náš formulář a někde v ploše klikněte pravým tlačítkem myši. V kontextovém menu nás bude zajímat volba "Formulář...". Trochu jiné kontextové menu je skryto pod hlavičkou formulářové tabulky - zde se dají přidávat sloupce, editovat nadpisy a podobně.

Pomocí nástroje s ovládacími prvky formuláře lze vyrobit celý formulář ručně, bez pomoci "Průvodce". Na plochu se rozmístí prvky formuláře a ve volbě "Formulář..." v kontextovém menu formuláře na kartě data lze zadat celý databázový dotaz i s případnými parametry.

Pojmenované parametry

Pro další práci musíme vytvořit makro, pomocí kterého můžeme používat v databázových dotazech pojmenované parametry. Makro jsem získal z článku Parameter Name Substitution na webu OpenOffice.org. Neptejte se mě, jak to funguje - programování tohoto typu je mi zcela cizí. V makru je pouze nutné upravit jméno datového zdroje - jméno "Pokusy" (v původní verzi makra "Bibliography") upravte na vlastní název podle skutečně existujícího datového zdroje.

Soubor s makrem

V hlavním menu vyvolejte Nástroje->Makra->Makro. Ve stromu vyberte modul soffice->Standard->Module1 a klikněte na tlačítko "Upravit". Tím se otevře Basic IDE, do kterého přepíšete text makra. Nakonec makro spusťte:

Obrázek: Editace a spuštění makra.

Vraťme se od maker zpátky k formuláři. Ve vlastnostech změňte zdroj, ze kterého se získávají data. Místo "Typ obsahu tabulka" zvolte "SQL příkaz" a do "Obsahu" místo seznam_vw napište SQL příkaz:

select * from seznam_vw where oc = :oc

Formulář se vás nyní po spuštení zeptá na konkrétní hodnotu oc. Stejného výsledku bychom mohli dosáhnout i bez maker nahrazením řetězce :oc otazníkem, ale parametr by byl bezejmenný a nedokázali bychom ho využít pro propojení několika formulářů.

Obrázek: Pojmenované parametry v databázovém dotazu formuláře.

S tímto jednoduchým formulářem toho už více nedokážeme, pojďme se podívat na užitečnější systém.

Složitější příklad - podformuláře

Vytvořte si, například pomocí průvodce, tabulkový formulář s tabulkou lidi. Tabulku vytvořte trochu menší, aby se mám na obrazovku vešel ještě jeden formulář s tabulkou telefony.

Zapněte si "Navigátor formulářem". Na obrázku jsem pomocí navigátora přejmenoval formulář na "lidi". V menu po kliknutí pravým tlačítkem myši vytvořte nový formulář v hierarchii pod původním formulářem. Nechte nový formulář označený a ručně vytvořte novou tabulku. Jako zdroj dat pro tento formulář zadejte SQL dotaz:

select * from telefony

Poté můžete přes kontextové menu v hlavičce formulářové tabulky přidávat další sloupce. Každý sloupec má vlastní menu, ve kterém lze nastavit jeho vlasnosti. V každém sloupci zvolte jako zdroj dat příslušnou položku z databázové tabulky. Zatím si to příliš nekomplikujte a zadejte všechny položky jako textové.

Obrázek: Pojmenované parametry v databázovém dotazu formuláře.

Když nyní vyskočíte z editačního režimu a formulář aktivujete, vyberou se v první tabulce všechny záznamy z tabulky lidi a ve druhé všechny záznamy z tabulky telefony. Pomocí pojmenovaných parametrů nyní zajistíme, aby se ve druhé tabulce zobrazovala pouze telefonní čísla patřící člověku vybranému v první tabulce.

Ve vlastnostech druhého formuláře dopište do SQL příkazu klauzuli where:

select * from telefony where oc = :hoc

Pokud byste nyní formulář aktivovali, při každé změně v tabulce lidí byste museli zadat parametr pro spodní tabulku s telefonními čísli. Pro automatické propojení vyplňte položku "Propojit hlavní pole" - sem zadejte datovou položku v nadřízeném formuláři (tabulka lidí, položka oc) a položku "Propojit závisla pole" - sem zadejte jméno parametru v SQL dotazu.

Obrázek: Vlastnosti databázového dotazu formuláře telefonních čísel.

Když po těchto úpravách formulář aktivujete, můžete opravovat existující záznamy o lidech, zavádět a rušit jim telefony a nemusíte se starat o vzájemné vazby mezi tabulkami. Formulář je sice pěkný, ale chybí mu ještě lepší provázání s tabulkou operátorů.

Sloupec s číslem operátora změňte na typ "Pole seznamu". Ve vlastnostech sloupce na kartě data zadejte jako "Druh obsahu seznamu" SQL a do "Obsahu seznamu" napište SQL příkaz pro získání seznamu operátorů z databáze:

select popis, operator from operatori

V SQL příkazu záleží na pořadí vybraných sloupců. Nikde jsem nenašel bližší popis, ale vysledoval jsem, že první sloupec se používá pro zobrazování textu ve formuláři a pro vazbu na nadřízený formulář se používají další vybrané sloupce. Druhý sloupec má v položce "Svázané pole" číslo jedna, třetí sloupec má číslo dva a tak dál. V praxi budou vždy stačit pouze dva sloupce.

Obrázek: Vlastnosti databázového dotazu sloupce Operátor.

Hotový formulář je z hlediska přístupu k datům téměř dokonalý. Umožňuje komfortní správu navrženého datového modelu a nezatěžuje uživatele zbytečnými informacemi (číslo operátora pro vazbu do tabulky operátorů). Kontroly zajišťuje samotná databáze - uživateli by se nemělo podařit zadat do databáze například záznam s nevyplněným jménem člověka ani telefonní číslo v nepřípustném tvaru. Mírné vylepšení by si formulář zasloužil především v oblasti srozumitelnějších chybových hlášení. Ale to už by nejspíš vyžadovalo programování v OO Basicu.

Obrázek: Hotový formulář.