WebToDate/Příručka vývojáře/WebToDate moduly: Porovnání verzí

Z WebToDate
Skočit na navigaciSkočit na vyhledávání
Bajkvl (diskuse | příspěvky)
Bajkvl (diskuse | příspěvky)
Řádek 1 063: Řádek 1 063:


Hlášení typu pokynů k ošetření chyb apod. se vkládají do předlohy ve formátu
Hlášení typu pokynů k ošetření chyb apod. se vkládají do předlohy ve formátu


:<tt><nowiki><!--WTD_IF(příznak,hláška)--></nowiki></tt>
:<tt><nowiki><!--WTD_IF(příznak,hláška)--></nowiki></tt>


tedy například
tedy například

Verze z 23. 9. 2009, 13:30

Co jsou moduly

Modul je sada PHP skriptů, dalších souborů a databázových objektů (hlavně tabulek), která rozšiřuje funkčnost aplikace WebToDate a jejíž administrační část se integruje do administračního rozhraní WebToDate. Modul může využívat WebToDate prvků jako šablony a styly, může a nemusí mít vlastní data a využívá předpřipravených tříd a funkcí, které jsou navrženy pro rychlejší vývoj funkčnosti, která se opakuje u všech modulů.

Modul se může skládat z následujících částí:

Databáze

  • Databázové tabulky a další databázové prvky vytvořené pro daný modul
  • Záznamy v databázových strukturách společných pro všechny moduly

Administrační část

  • Požadované PHP skripty
  • Skripty specifické pro daný modul
  • XML definice nabídky modulu
  • Extenze
  • Další pomocné soubory typu předpřipravených šablon apod.

Veřejná část

  • Skripty veřejné části
  • Extenze

Na následujícím diagramu vidíme, z čeho se skládá modul Diskuse, který je vybrán jako modelový modul využívající všech dostupných funkcí.

Obrázek znázorňuje následující funkčnost:

  • Modul má vlastní databázové tabulky s daty
  • Modul využívá databázové struktury aplikace WebToDate, a to jednak společné struktury pro moduly, jednak volitelně relace mezi diskusními příspěvky a zprávami
  • Modul spolupracuje s jiným modulem, v tomto případě s modulem Registrace a personalizace
  • Modul má administrační část, pomocí které se nastavuje funkčnost (grafická nastavení, přístupová práva, předvolby pro nastavení funkčnosti apod.) a pomocí které lze editovat data (v tomto případě moderovat diskusní příspěvky)
  • Modul má skripty pro veřejnou část, které v různých formách prezentují data modulu a případně umožňují tato data vkládat (v tomto případě vkládat diskusní příspěvky)
  • K modulu se mohou vázat úlohy pro Plánovač úloh, v tomto případě např. úloha, která může rozesílat e-mailem nové diskusní příspěvky návštěvníkům webu, kteří si takovou službu nastavili.

Většina z těchto funkcí není povinná, modul nemusí mít svoje vlastní data (např. modul Nejčtenější články pracuje pouze s daty vlastní aplikace WebToDate), nemusí mít veřejnou část (modul Neveřejná část slouží pouze k nastavení pravidel pro přístup ke zprávám pro návštěvníky webu, nemá žádnou vizuální reprezentaci na veřejné části webu) apod.

Pro všechny moduly platí následující zásady:

  • Moduly negenerují vlastní HTML kód, stejně jako v aplikaci WebToDate jsou veškeré kódy sestavovány spojením šablon, stylů a vlastních dat.
  • Moduly využívají společné databázové struktury (pro registraci modulů, předvolby modulů, přístupová práva apod.)
  • Moduly využívají společné funkce pro veřejnou i administrační část, funkce jsou umístěny v knihovnách funkcí
  • Všechny moduly pracují stejným způsobem s objekty jako jsou styly, šablony, jazyky apod.

Každý modul definuje typicky svoje klíčová slova používaná v šablonách či stylech, např. klíčové slovo pro diskusní příspěvek je jedinečné a není použitelné v jiném kontextu. Data modulu jsou většinou zobrazována vlastními veřejnými skripty modulu, k tomu existuje několik metod jak data daného modulu prezentovat v jiných typech stránek (extenze, SQL seznamy).

Nabídka modulu Diskuse

Nabídka modulu Poradny

Všechny moduly se ovládají stejným způsobem. Na předchozím obrázku jsou otisky obrazovek – menu modulů Diskuse a Poradny a rozhovory. Obě menu jsou velmi podobná, jsou dělená do stejných sekcí a obsahují podobné položky, které se ovládají stejně.

Příklady využití

Praktické využití modulů je např. v oblastech jako vytváření interaktivních funkcí veřejné části webu, publikace obsahu složitějších relačních databází, importy a exporty dat, propojení s externími aplikacemi a systémy apod.

Standardně dodávané moduly zahrnují např.:

  • Diskuse – modul pro provozování diskusí ke článkům i volných diskusních fór
  • Ankety – modul pro hlasování na anketní otázky
  • Poradny a rozhovory – modul pro provozování internetových poraden a chatů s osobnostmi
  • Katalog – modul pro publikování obsahu jednotabulkových databází s možností výpisů podle různých kritérií, prohledávání apod.
  • Rozcestník – modul pro správu hierarchického adresáře www adres

Zákaznické moduly, které byly nasazeny v řešení pro určité konkrétní zákazníky zahrnují např.:

  • Modul pro komunikaci a výměnu dat se systémem pro správu dokumentů
  • Modul pro správu předplatitelů
  • Modul pro publikaci adresáře institucí vydávajících periodické publikace a seznamů těchto publikací
  • Modul pro propojení s externím reklamním systémem
  • Modul pro zveřejňování řádkové inzerce
  • Modul pro import statistických dat typu čtenost časopisů, sledovanost televize apod. a zobrazování těchto dat v různých pohledech (základní přehledy, časové řady apod.)

Jak pracuje typický modul

Základní principy činnosti modulů lze vysvětlit na příkladu relativně jednoduchého standardně dodávaného modulu – Kalendáře akcí.

Tento modul má za cíl spravovat jednoduché kalendárium a jeho položky zobrazovat a prohledávat na veřejné části serveru. Položky kalendária jsou záznamy zhruba typu název – popis – datumy od a do, kategorie. Veřejná část umožňuje:

  • Zobrazit stránkovaný seznam položek kalendária, kde se ve výchozím pohledu zobrazuje výběr akcí od aktuálního data dál a kde je možné prohledávání pomocí formuláře nebo klepnutím na kategorii.
  • Zobrazovat seznam kategorií pro výběr filtru omezujícího zobrazení položek na danou kategorii
  • Zobrazovat stránku s detailním zobrazením jedné položky.

Veřejná část modulu v podstatě sestává z dvou pohledů na data – seznam položek a detail jedné položky. Každý pohled na data je reprezentován samostatným PHP skriptem, který podle parametrů (z URL či formuláře) zobrazí tu správnou selekci dat. Přitom tyto skripty samy žádné HTML kódy negenerují – požadavkem na moduly je, aby se tyto kódy generovaly podle definic, které vytvoří designér v samotném WebToDate a v příslušném modulu.

Rozdělení funkcí mezi veřejnou a administrační částí modulu je proto následující.

Veřejná část Administrační část
  • Skript, který zobrazuje seznam položek; umí zobrazit v dané šabloně seznam akcí, seznam kategorií, vyhledávací formulář a stránkovací lištu pro seznam akcí. Seznam akcí zobrazuje filtrovaný podle parametrů z URL nebo z formuláře.
  • Skript, který zobrazuje detailní pohled na jednu akci; umí v dané šabloně zobrazit všechny položky dané akce a k tomu navíc seznam kategorií akcí.
Nástroj pro správu dat kalendária akcí.
  • Nástroj umožňující nastavit, kteří uživatelé mají oprávnění tato data spravovat.
  • Nástroje umožňující definovat grafické zobrazení obou pohledů na data na veřejné části.
  • Nástroje ulehčující práci designéra - v tomto případě funkce, která umí např. vygenerovat jako HTML fragment generický funkční vyhledávací formulář s příslušnými ovládacími prvky a klíčovými slovy, který stačí jen graficky upravit a vložit na stránku, která bude šablonou pro seznam akcí.

Zobrazení stránky se seznamem akcí je definováno

  • HTML šablonou stránky
  • Nastavením jak formátovat zobrazovaný seznam akcí
  • Nastavením jak formátovat seznam kategorií
  • Nastavením jak zobrazovat a formátovat stránkovací lištu

Různé seznamy položek lze ve WebToDate formátovat WebToDate styly, proto se i zde používá nastavení pomocí stylů. Formulář pro nastavení je zobrazen na následujícím otisku obrazovky (poslední položka – stránkovací lišta – se nastavuje v jiném formuláři globálně pro celý modul).

Jsou-li definovány tyto čtyři položky, pro veřejný skript je to postačující pro to, aby byl schopen sestavit kompletní HTML stránku se seznamem položek kalendáře a to je přesně to, co tento skript dělá. Načte zvolenou šablonu, načte zvolené WebToDate styly, provede SQL dotazy, kterými získá potřebná data a podle nastavení, které provedl designér celou stránku sestavuje. Knihovny pro vytváření modulů při tom zajišťují funkce pro připojení k databázi, načítání objektů jako šablony či styly a některé další pomocné funkce, ale zbytek, tj. sestavení vhodných SQL dotazů a formátování výsledků těchto dotazů příslušnými styly už musí být funkce přímo tohoto skriptu, který programuje autor modulu.

Analogicky toto platí i pro druhý skript – zobrazení detailu jedné akce. Nastavení jsou zde ještě jednodušší, postačuje šablona stránky a styl pro zobrazení seznamu kategorií. Klíčová slova pro položky jedné akce jsou již součástí šablony stejně jako tomu je např. u zobrazování zpráv v samotném WebToDate. Rovněž SQL dotazy, kterými skript získává vlastní data jsou zde jednoduché – jeden dotaz pro získání všech položek daného záznamu kalendária (podle přiděleného ID položky) a druhý pro získání seznamu názvů a ID všech kategorií kalendária.

Terminologie

Modulem se rozumí aplikace rozšiřující funkčnost produktu WebToDate, která má administrátorský interface integrovaný do tohoto produktu a která může mít veřejnou část (tj. PHP skripty) pracující s daty daného modulu na veřejné části serveru. Příkladem modulu je Kalendář akcí, Diskusní skupiny apod.

Součástí modulu může a nemusí být nějaká extenze, extenze lze vyvíjet i samostatně a nemusí být součástí žádného modulu.

Druh zobrazení – nastavování modulů je orientováno na druhy zobrazení. Např. u diskusí je jeden druh zobrazení seznam příspěvků, druhý detail jednoho příspěvku, třetí stránka pro zadání příspěvku atd.

Předpis – předpis je množina parametrů, která dohromady dává popis grafického zobrazení aplikovatelný na jednu z tohoto hlediska dále nedělitelnou část dat modulu (tj. jednu diskusní skupinu, jednu poradnu atd.)

Globální nastavení – předpis platný pro celý modul, resp. pro daný jazyk; například seznam diskusních skupin či prohledávání všech skupin není závislé na konkrétní diskusní skupině.

Administrační rozhraní modulů

Jednotné rozhraní pro administraci modulů

Uživatelské rozhraní administrátorské části se zobrazuje ve stejném okně prohlížeče jako vlastní WebToDate až na dobře zdůvodněné výjimky. V navigačním stromu WebToDate v sekci Moduly se nachází seznam instalovaných modulů, kliknutím na název modulu se levý navigační rámec přepne na zobrazení stromu modulu, zpět se lze dostat klepnutím na záložku WebToDate v tomto levém rámci.

V pravé části se pak zobrazují formuláře či seznamy objektů stejným způsobem jako ve vlastní aplikaci WebToDate.

Všechny moduly musí vypadat a fungovat z hlediska uživatele jednotně. To v zásadě znamená:

  • Stejná struktura nabídky u všech modulů
  • Stejné funkce musí fungovat stejně (pokud např. uživatel vybírá nějakou šablonu stránky, musí to dělat ve všech modulech stejně)
  • Stejné funkce musí být podporovány stejným způsobem – např. podpora vícejazyčných webů je ve všech standardně dodávaných modulech realizována stejným způsobem a měla by být takto realizována i u všech zákaznických modulů.

Dodržování těchto pravidel je podporováno možností využívat knihovní funkce a třídy, které zajišťují jednotné zpracování stejných činností (práci s nabídkou modulu, práci s prvky formulářů apod.).

Navigační strom modulu

Strom v administračním rozhraní obsahuje v nejvyšší úrovni vždy tyto elementy (některé mohou být vynechány pakliže to u daného modulu nemá smysl):

  • Nástroje – interaktivní nástroje typu vygenerování vyhledávacího formuláře do těla HTML fragmentu
  • Nastavení – zde se nastavuje grafické zobrazení dat, tedy předlohy, styly a další nastavení pro veřejné stránky
  • Administrace – v této části se pracuje s vlastními daty modulu z hlediska administrátora, tj. např. zakládání diskusních skupin či poraden a předvolby modulu
  • Data – v této části se pracuje s vlastními daty modulu – zde se zakládají ankety, zodpovídají se dotazy poraden, moderují se diskuse apod.
  • Nápověda – zobrazuje nápovědu obdobným způsobem a graficky stejně jako samotný WebToDate

Další úrovní pod Nastavení by měl být seznam jazyků, protože nastavení jsou typicky jazykově závislá, pokud je v systému (tedy v tabulce NEWSLANGUAGE) definován jen jeden jazyk, měla by být tato úroveň vynechána.

Dále by se pod Nastavení / jazyk měla nacházet úroveň GlobálníPředpisy. Pod globálními nastaveními se ukrývají nastavení společná pro celý modul (samozřejmě v rámci jednoho jazyka), tedy například jaké předlohy užívá stránka seznamu diskusních skupin či vyhledávání ve všech diskusních příspěvcích). Pod Předpisy by se měly rozbalit jednotlivé předpisy. Předpis je množina nastavení aplikovatelná na část dat modulu, tedy např. na jednu diskusní skupinu. Pokud chceme provozovat 10 diskusních skupin, 5 v jedné grafice a 5 v druhé, definujeme dva předpisy, prvních 5 skupin bude mít přiřazeno jeden předpis a druhých 5 druhý. Předpisy se pak skládají z nastavení pro jednotlivé druhy zobrazení – druhem zobrazení se rozumí např. seznam příspěvků v dané diskusi, stránka pro vložení nového příspěvku apod.

Nástroje

V této části se typicky nacházejí funkce, které nenastavují předvolby modulu ani nemodifikují vlastní data modulu. Typickým použitím je funkce pro vygenerování formuláře pro daný modul jako fragmentu ve WebToDate, tato funkce je podporovaná v knihovně společných funkcí.

Nastavení

Tato sekce obsahuje popisy jednotlivých druhů zobrazení, tedy volbu jejich šablon, stylů seznamů apod. Nastavování je orientováno na druhy zobrazení, každý druh zobrazení by tedy měl být reprezentován jednou položkou v této části navigačního stromu. Výjimkou je stránkovací lišta, která by měla být definována globálně v rámci modulu společně pro všechny druhy zobrazení.

Rozeznáváme globální nastavení a předpisy. Globální nastavení je nastavení, které může být pouze jedno pro daný modul a jazyk (např. nastavení pro vyhledávací stránku ve všech diskusích), předpis je pak nastavení pro sadu stránek, u kterých je přípustné víc variant nastavení (např. nastavení pro stránky, ze kterých se skládá jedna diskusní skupina).

V této sekci je důležité rozlišování podle jazyků, každé nastavení se váže právě k jednomu jazyku. Pokud je v databázi zaveden pouze jeden jazyk, je naopak třeba tuto volbu programově zneviditelnit, aby se navigační strom pro daný modul nekomplikoval.

Administrace

V této části se nacházejí funkce pracující s daty daného modulu, které mají být ovšem přístupné pouze administrátorům. Jedná se o editaci seznamu diskusních skupin, kategorií dat apod. Typicky zde administrátor nastavuje i grafiku pro daný okruh dat, neboli např. pro diskusní skupinu definuje kromě názvu, popisu apod. i předpis pro danou diskusi, který byl předem vytvořen v sekci Nastavení.

Data

Tato část je odlišná pro každý modul, jsou zde umístěny funkce pro správu dat (zodpovídání dotazů poradny, moderování diskusí, editace seznamu zaregistrovaných uživatelů v registračním modulu apod.). Tuto část lze typicky pomocí nastavení přístupových práv zpřístupnit i jiným uživatelům než administrátorům.

Formuláře

Klepnutím na položku v navigačním stromu modulu se zpravidla v pravém části okna otevírají editační formuláře a to buď v celém pravém rámci (např. pokud jde o formuláře nastavující grafické zobrazení v sekci Nastavení) nebo děleně na dva rámce (pokud se např. jedná o editaci dat analogicky jako se editují položky v samotném WebToDate).

Každému formuláři odpovídá zpravidla alespoň jeden PHP skript, který vytváří programátor daného modulu. V těchto skriptech se využívají knihovny popisované v následujících kapitolách.

Zatímco skripty, pomocí kterých se nastavuje grafické zobrazení, generují pomocné fragmenty či nastavují přístupová práva jsou ve všech modulech velmi podobné, skripty editující data či pracující s předvolbami modulu jsou zpravidla jedinečné pro daný modul a znuvupoužitelnost existujících kódů je zde podstatně nižší.

Veřejně přístupná část modulů

Co je veřejná část

Pod pojmem veřejná část modulu rozumíme skripty tvořící zpravidla prezentační vrstvu pro data modulu. Skripty samy o sobě negenerují HTML kód, ale je v nich implementována logika načítání a vkládání dat a formátování stránek, stránky formátují na základě šablon, stylů a dat modulu analogicky jako to provádí samotná aplikace WebToDate.

Veřejná část se skládá z jednoho nebo více PHP skriptů, typicky každý druh zobrazení je implementován jako jeden skript. Tyto skripty se ukládají do veřejného adresáře modulu, tedy scripts/modules/název_modulu.

Sestavení stránky

Stránky prezentované na veřejné části se skládají zpravidla z některých z následujících elementů:

  • Šablony stránky, která tvoří základní HTML kód dané stránky
  • Jednoho či více seznamů (seznam akcí v Kalendáři akcí, seznam diskusních příspěvků atd.)
  • Stránkovací lišty příslušné k danému seznamu
  • Obsahu polí nějaké databáze (obsah polí jedné akce z databáze akcí apod.)
  • Jednoho či více formulářů
  • Hlášení typu "Nenalezen žádný záznam." či hlášení o chybách vstupu ("Pole pro datum obsahuje nesprávně zadanou hodnotu." apod.)

Při sestavování stránky se používají následující principy:

Každá stránka je zobrazována v určité šabloně. Touto šablonou je příslušná předloha vygenerovaná pomocí WebToDate a typicky zařazená do kategorie předloh patřící příslušnému modulu.

Pokud se na stránce nachází určitý výběr databázových záznamů, je formátován podle zvoleného WebToDate stylu. Definice stylu pak obsahuje klíčová slova příslušná k danému modulu, konkrétní způsob práce se stylem pak závisí na daném modulu, pole Hlavička, Tělo, Patička a Separátor by se však měly aplikovat vždy stejným způsobem. Při volbě způsobu formátování daného elementu je třeba dobře zvolit, o jaký objekt se jedná, seznamem je například i hlasovací formulář, kde začátek formuláře je hlavičkou, jednotlivé otázky jsou formátovány tělem stylu a separátorem a konec je patičkou stylu.

Dalším elementem souvisejícím se seznamy je stránkování. Knihovna společných funkcí obsahuje funkce pro sestavování stránkovací lišty příslušné k danému seznamu.

Pokud daný druh zobrazení má zobrazovat jeden záznam z databáze, pracuje se na principu předloh pro zprávy, tedy klíčová slova pro jednotlivá pole databáze se mohou nacházet kdekoliv v předloze a jsou nahrazena příslušným obsahem polí většinou bez dodatečného formátování.

Formuláře se nacházejí v předloze, pokud je to potřeba, jsou v rámci modulu definována klíčová slova pro "aktivní" prvky formuláře. Příkladem je klíčové slovo pro obsah pole "Hledaný text" pro vyhledávací formulář, které se nahradí hledaným textem vždy, když je tento text znám, což zajišťuje přenos tohoto parametru ze stránky volající hledání na výslednou stránku. Doporučený postup je ten, že kód formuláře se vloží do samostatné zprávy, tato zpráva se přiřadí na předlohu stránky a předloha se vygeneruje. Tento postup je podporován v modulech tím, že v takovém případě existuje v administraci modulu v sekci Nástroje funkce, která vytvoří generický formulář jako novou zprávu. Formulář je pro jednoduchost pouze v té jazykové verzi, jako administrační rozhraní modulu. Administrátor si takový formulář graficky a jazykově upraví podle potřeby (tj. změní jeho HTML kód, nesmí měnit klíčová slova, názvy prvků formulářů apod.), po přiřazení na danou předlohu a vygenerování dostane funkční "aktivní" formulář. Součástí instalace může být i jedna nebo více výchozích předloh.

Společné databázové struktury

Úvod

Společné databázové struktury řeší funkce, které využívají všechny moduly a které souvisí s integrací modulů do administračního rozhraní obecně. Jedná se o tyto funkce:

  • Registrace modulů do systému a jejich základní vlastnosti (verze apod.)
  • Ukládání skalárních předvoleb všech modulů
  • Vytváření předpisů v modulech
  • Nastavení přístupových práv v redakční části.

S daty těchto tabulek se zpravidla nepracuje přímo, ale pomocí knihovních funkcí pro zápisy a čtení z těchto tabulek.

Databázové tabulky společné pro všechny moduly mají názvy začínající na písmena MOD. Jedná se o tyto tabulky:

  • MODULES – základní tabulka obsahující seznam instalovaných modulů
  • MODSETTINGS – tabulka pro ukládání nastavení, každý řádek obsahuje jedno nastavení (např. ID předlohy pro daný druh zobrazení)
  • MODRECEIPTS – tabulka předpisů; každý řádek reprezentuje jeden předpis pro daný modul.
  • MODRIGHTS – tabulka pro nastavování přístupových práv
  • MODXUSAGE – tabulka pro registraci datových tabulek modulů, které využívají funkcí modulu Registrace a personalizace (více popsaná v kapitole pojednávající o funkcích tohoto modulu).

MODULES

Struktura této tabulky je následující

  • MODULEID – číslo modulu
  • NAME – název modulu (WebToDate je zde registrován jako jeden z modulů)
  • VER1, VER2, VER3, VER4 – sloupce pro číslování verzí
Poznámka: Verze modulů se číslují stejně jako verze WebToDate, tedy např. 3.7.0.2; první číslo je hlavní číslo verze, druhé číslo je vedlejší číslo verze, tyto čísla by se měla 
inkrementovat pokud dojde k zásadnějšímu rozšíření funkcí. Třetí číslo se inkrementuje v případě implementace drobných změn, čtvrté číslo se inkrementuje pokud se pouze opraví chyby.
  • DEFPATH – výchozí cesta k modulu vzhledem k adresáři neveřejných skriptů systému WebToDate (např. "modules/diary/", tedy bez prvního lomítka a včetně posledního lomítka)
  • OPTIONS – možno použít na základní volby modulu
  • ADVUSERSYSTEM – příznak možnosti pokročilého nastavování uživatelských práv u modulu (např. u Diskusí nebo Hlasování)
  • ADVOBJECTNAME – název objektu modulu (při ADVUSERSYSTEM = 1)
  • ADVOBJECTDESC - popis objektu modulu (při ADVUSERSYSTEM = 1)
  • ADVOBJECTIDFIELD – pole s ID objektu v DB, např.: "DISKGROUPS.ID" (při ADVUSERSYSTEM = 1)
  • ADVOBJECTNAMEFIELD – pole se jménem objektu v DB, např.: "DISKGROUPS.NAME" (při ADVUSERSYSTEM = 1)
  • ACTIVE – příznak zobrazení modulu v nabídkovém panelu (tj. v sekci Moduly navigačního stromu WebToDate)
  • INSTALLED – datum a čas instalace modulu (doplňuje se automaticky)

Při zakládání nového modulu je nutné vyplnit minimálně následující pole: MODULEID, NAME, VER1 až VER4, DEFPATH, ACTIVE.

Každý modul má přiděleno jedinečné číslo MODULEID, které se pak používá v příslušných databázových tabulkách. Čísla 1 – 9999 jsou rezervované pro moduly vytvořené v Macron Software, vyšší čísla může použít nezávislý autor modulu.

MODSETTINGS

Tabulka slouží pro ukládání všech nastavení všech modulů, pokud se tato nastavení dají rozložit na množinu "skalárních" nastavení. Tabulka má tuto strukturu:

  • MODULEID – číslo modulu
  • LANGUAGEID – číslo jazyka
  • RECEIPTID – číslo předpisu (z tabulky MODRECEIPTS; obsahuje NULL pokud se jedná o globální nastavení)
  • SPECIFGROUP – skupina voleb, typicky označuje druh zobrazení (jednotná identifikace nastavení však leží pouze na SETID)
  • SETID – číslo nastavení jednoznačné v rámci modulu a jazyka
  • DTYPE – zda se jedná o celočíselnou (1) či řetězcovou (2) hodnotu
  • IVALUE – celočíselná hodnota nastavení
  • SVALUE – řetězcová hodnota nastavení

Nastavení se stejným SPECIFGROUP se nacházejí pod jednou položkou v navigačním stromu. Čísla pro SETID se definují v každém modulu separátně a to v souboru _constants_inc.php. Pro modul Kalendář akcí jsou např. definovány následující konstanty:

define( 'intListSET_TemplID' , 1); // ID předlohy pro seznam akcí

define( 'intListSET_WTDStyle' , 2); // ID stylu seznamu akcí pro druh zobrazení Seznam akcí

define( 'intListSET_StyleCount' , 3); // maximální počet záznamů zobrazených v seznamu akcí

define( 'intListSET_OrderBy' , 4); // třídění seznamu akcí; nepoužívá se, třídí se vždy podle datumů

define( 'intListSET_KategStyle' , 5); // ID stylu seznamu kategorií zobrazených v stránce pro seznam akcí

define( 'intListSET_KategStyleCount' , 6); // maximální počet záznamů v seznamu kategorií

define( 'intDetSET_TemplID' , 7); // ID předlohy pro detail akce

define( 'intDetSET_KategStyle' , 8); // ID stylu seznamu kategorií zobrazených v stránce pro detail akce

define( 'intDetSET_KategStyleCount' , 9); // maximální počet záznamů v seznamu kategorií

define( 'intDetSET_OrderBy' , 10); // třídění seznamu kategorií; nepoužívá se, třídí se vždy podle názvu

define( 'intListSET_NavigBarOffset' , 11); // číslo, na kterém začínají nastavení pro stránkovací lištu

V následujícím obrázku jsou předvolby vyplněné pro modul Kalendář akcí.

MODRECEIPTS

Tabulka obsahuje seznam předpisů pro daný modul definovaný administrátorem. Její struktura je:

  • MODULEID – číslo modulu
  • RECEIPTID – číslo předpisu
  • NAME – název předpisu.

MODRIGHTS

Tabulka definuje přístupová práva k datům modulu pro případ, že tato práva lze poskytnout i jiným uživatelům než administrátorům. Struktura je

  • ID – číslování záznamů
  • MODULEID – číslo modulu
  • OBJECTID – ID objektu, kterému se přidělují daná práva (např. ze sloupečku DISKGROUPS.ID)
Poznámka: při hodnotě NULL má oprávněný tým přístup k těm částem rozhraní, které nejsou rozděleny na objekty (např. část Nástroje).  
  • GROUPID – číslo týmu
Poznámka: při hodnotě NULL je přístup povolen všem uživatelům WebToDatu.

Tabulka MODRIGHTS počítá pouze s tím, že se nastavují práva specificky pro každou skupinu dat (např. zvlášť pro každou diskusní skupinu. Pokud je třeba nastavovat přístupová práva na editaci dat bez dalšího rozlišení dat (to je např. případ editace databáze akcí v modulu Kalendář akcí, postupuje se následujícím způsobem:

  • Založí se tabulka patřící k modulu ve struktuře ID, NAME a vloží se jeden řádek (např. 1, ‚Akce‘)
  • V tabulce MODULES se doplní hodnoty polí takto: ADVUSERSYSTEM=1 , ADVOBJECTNAME="Přístup k části", ADVOBJECTIDFIELD="SERVOBJECTS.ID" a ADVOBJECTNAMEFIELD="SERVOBJECTS.NAME", kde SERVOBJECTS je třeba nahradit za název tabulky založené v předchozím kroku.

Další datové tabulky

Další důležitou tabulkou je NEWSPATTERNS, která obsahuje kategorie předloh. Instalace každého modulu by měla instalovat svoji kategorii předloh pokud používá veřejné skripty, jejichž zobrazení je založeno na šabloně. Čísla kategorií předloh jsou napevno stanovená pro každý modul.

Vytváření administračního rozhraní modulu

Založení nového modulu

První kroky při vytváření nového modulu jsou následující:

  • Založte nový adresář pro administrační rozhraní modulu v adresáři application/modules
  • Vytvořte záznam v tabulce MODULES pro tento modul. Je vhodné při programování vytvářet instalační SQL skript, který příslušné tabulky naplní dávkově. Po zápisu do tabulky MODULES se název a odkaz na modul zobrazí v administračním rozhraní WebToDate.
  • Založte nový adresář pro soubory typu zdroj v adresáři rdata/resources/modules. V tomto adresáři založte souboru menu.xml pro základní nabídku modulu
  • V adresáři application/modules/název_modulu založte soubory default.php (stránka pro zobrazení menu modulu) a _constants_inc.php (definiční konstanty modulu).

Další postup je takový, že v souboru menu.xml se vytvoří základní nabídka modulu, v souboru default.php se vytvoří kód pro zobrazení menu tohoto modulu. V adresáři application/modules/název_modulu se následně vytvářejí jednotlivé skripty – formuláře administračního rozhraní modulu, při tom se průběžně definují potřebné konstanty v _constants_inc.php. Lokalizační soubor se typicky ukládá do adresáře rdata/resources/modules/název_modulu/application.

XML menu

Soubory menu modulu jsou umisťovány jako soubor /rdata/resources/modules/ nazev_modulu /menu.xml.

Příklad menu a odpovídající definice v souboru (menu modulu Fulltext):

<?xml version="1.0" encoding="iso-8859-2"?>
<Structure>
	<Element id="401" name="Module" version="3.6.0.2" class="pagb" iconclass="cubew" label="strModuleName">
		<Element name="Functions" class="pagb" iconclass="cubew" label="strFunctions">
			<Element name="NewsGenerator" class="pagb" iconclass="cubew" label="strNewsGenerator">
				<script>newscreator.php</script>
				<Attribute>external</Attribute>
			</Element>
		</Element>

		<!-- display full menu in case of two or more languages -->
		<Element name="Fulltext" label="strLanguages" class="pagb" iconclass="cubew">
			<Attribute>external</Attribute>
			<Element name="Language" class="pagb" iconclass="cubew">
				<Attribute name="LangugeName" label="strLangName" type="text" NameOfObject="1">
					<Linkage type="db" checkcount="1">
						<id refid="id_of_language">NEWSLANGUAGE.ID</id>
						<name>NEWSLANGUAGE.NAZEV</name>
					</Linkage>
				</Attribute>
				<Element name="Global" class="pagb" iconclass="cubew" label="strGlobal">
					<Element name="ResultList" class="pagb" iconclass="cubew" label="strListOfFound">
						<script>resultlist.php?id={id_of_language}&type=newsonly</script>
						<Attribute>external</Attribute>
					</Element>
					<Element name="GlobalList" class="pagb" iconclass="cubew" label="strGlobalSearch">
						<script>resultlist.php?id={id_of_language}&type=global</script>
						<Attribute>external</Attribute>
					</Element>
					<Element name="NavigBar" class="pagb" iconclass="cubew" label="strNavigBar">
						<script>navigbar.php?id={id_of_language}</script>
						<Attribute>external</Attribute>
					</Element>
				</Element>
			</Element>
		</Element>

		<!-- /display... -->
		<Element name="Help" class="pagb" iconclass="cubew" label="strHelp">
			<script target="_blank">../../helpviewer.php?module=fulltext</script>
			<Attribute>external</Attribute>
		</Element>
	</Element>
</Structure>

Jednotlivé elementy Element jsou větvemi stromu menu. Tak je například vidět v kořenovém elementu (Structure) element Module, který odpovídá první úrovni menu (položka "Fulltext"), a v něm vnořené elementy Functions (Nástroje), Fulltext (Nastavení) a Help (Nápověda), které jsou v menu zobrazeny jako druhá úroveň (označením jsou zde myšleny hodnoty parametru name elementu Element).

Element představující první úroveň má také odlišné parametry od ostatních úrovní (parametry všech Element tagů jsou shodné, kromě první úrovně). Obsahuje parametry (id): ID modulu, jak je uveden v databázové tabulce MODULES; (version): které verzi modulu menu odpovídá; (class): styl CSS použitý na zpracování; zpravidla "pagb";(iconglass): ikonka zobrazená před volbou, zpravidla čtvereček, "cubew"; (label): popiska, nadpis modulu, konstanta nadpisu, většinou konstanta strmoduleName. Elementy ostatních úrovní neobsahují parametry (id) a (version), obsahují tedy jen parametry name, label (tyto dva se mění pro každou položku), classiconclass (tyto dva parametry mají stejnou hodnotu pro všechny elementy Element.

Zatímco atribut name identifikuje typ položky (viz také níže o podmíněném zobrazování položek), atribut label udává zobrazovaný název položky. Zobrazovaný je určen nepřímo. V XML definici je přítomen název jazykově nezávislé lokalizační konstanty, která podle víše zmíněného lokalizačního souboru rdata/resources/modules/název_modulu/application/_localization_inc.php překládána do příslušného jazyka.

Obsahem nejvnořenějsího Element tagu, "na konci větve" menu, se již nacházejí samotné odkazy (např. v podmenu Nástroje volba Formuláře). Ty jsou v XML definici menu definovány dvěma způsoby závisle na tom, zda je tato část menu pevně daná nebo vytvářená dynamicky podle databáze (např. podle nastavených jazyků se generuje podnabídka Fulltext / Nastavení / [čeština | novy_jazyk] ):

  • statické menu: volbu prezentují dva tagy – scriptAttribute. Obsahem elementu script je odkaz na požadovaný skript (odkaz je relativní k / application / modules / nazev_modulu / ).Element Attributes má vždy hodnotu "external".
  • generované menu (jazyky): definici voleb uvozuje pokyn, CO se má generovat. Zde jsou z elementu Attribute čitelné parametry name a label, známé již z tagů Element. Důležitý je však element Linkage, který určuje, odkud se načítají záznamy; zde máme parametrem type určeno, že z databáze. Vnořené elementy id a name zde znázorňují konkrétní pole, jež se mají z databáze načíst. Obsahem těchto elementů je řetězec (nazev_tabulky.nazev_pole), který se použije přímo v databázovém dotazu. Má-li element parametr refid, je hodnota z tohoto pole použitelná v nastavení, typicky v URL parametru u odkazu na požadovaný skript (tedy např. refid="id_of_language" a níže <script>navigbar.php?id={id_of_language}</script''>.Větve vnořené do generované nabídky se řídí stejným pravidlem, jako statické menu.

Potřebujeme-li některé položky dynamicky vytvářeného menu ve výpisu vynechat (např. ve výpisu modulů ty moduly, které nejsou aktivní), použijeme v elementu Linkage nepovinný subelement Condition. Tím vznikne filtr na vrácené záznamy. Jako hodnotu elementu Condition uvedeme DB sloupec, jehož hodnota bude figurovat coby levá strana podmínky. V elementu equalTo (popř. notEqualTo pro nerovnost) uvedeme pevnou hodnotu pro pravou stranu podmínky. Element Condition můžeme použít i několikrát, což vytvoří několik filtrů ve vztahu logického součinu. Např. XML kód

	<Condition notEqualTo="101">MODULES.MODULEID</Condition>
	<Condition equalTo="1">MODULES.ACTIVE</Condition> 

odpovídá SQL kódu

…where MODULES.MODULEID<>101 and MODULES.ACTIVE=1

Někdy ovšem vyvstává potřeba podmíněně zobrazovat i pevně dané položky menu (např. v případě jediného jazyka skrýt celou úroveň menu, zobrazovat zkrácené menu pro redaktory atp.). Element name identifikující typ položky, obsahuje-li speciální hodnotu, proto někdy rozhoduje o tom, zda položku zobrazit či nikoliv. Např. hodnota "AdminsOnly" udává, že se má položka zobrazit pouze administrátorům. Konkrétní pravidla jsou stanovena uvnitř fce checkMenuAccessRights ve skriptu application/menuengine.php.

V praxi se dynamické vytváření menu podle databáze využívá např. v těchto případech:

  • seznam jazyků s vnořeným podstromem pro konkrétní jazyk (podle tabulky NEWSLANGUAGE)
  • seznam modulů v dolní části menu WebToDate (podle tabulky MODULES)
  • seznam objektů modulu (diskusních skupin v modulu Diskuse apod.)

Další povinné soubory

Úvodní stránka

Jediným úkolem úvodní stránky administrační části (application/modules/název_modulu/default.php) je vytisknout menu modulu pomocí knihovní fce printModuleMenu. Její obsah se tedy zobrazuje v levém rámci po kliknutí na název modulu v menu WebToDate.

Např. úvodní strana modulu Diskuze má následující obsah:

include ('../../../config/global.php');	//include základních knihovan
include ('../../../includes/init.php');

getModLoc ( 'modules/disc/application' );	//načtení lokalizačního souboru modulu Diskuze

include ('../../../classes/DomElementAccess.php');	//include knihoven potřebných pro tisk menyu
include ('../../../classes/Menu.php');
include ('../../menuengine.php');
include ('../common/_utils_inc.php');

printModuleMenu(loc('strModuleName'), 'disc');	//samotný tisk menu


Konstanty

Soubor application/modules/název_modulu/_constants_inc.php je určen k definici konstant modulu. Kromě řady nepovinných konstant (např. konstanty udávající pozici předvoleb v tabulce MODSETTINGS) by měl obsahovat tyto konstanty:

  • intGlobModuleID – identifikátor modulu, např. pro modul Diskuse číslo 601
  • strModuleFolderName - název adresáře s modulem, např. pro modul Diskuze řetězec "disc".
  • intPtnUrldb – číslo kategorie předloh, pokud se na veřejné části modulu s využíváním předloh počítá,


Lokalizační soubor

Lokalizované texty jsou definovány v samostatném souboru zvlášť pro část administrační (jsou využívány v kódech v adresáři / application/) a zvlášť pro veřejnou (jsou využívány v kódech v adresáři /scripts/). Tyto soubory jsou uloženy jako "/rdata/resources/modules/nazev_modulu/ (application | scripts ) /_localization_inc.php". Přístup k těmto konstantám v samotném kódu je řešen pomocí funkce loc('nazev_konstanty), která vrací obsah konstanty. Ta jednak ošetřuje, zda požadovaná konstanta vůbec existuje (pokud ne, nic nezobrazí), jednak převádí vracený text do správné znakové sady podle parametrů nastavených v konfiguračním souboru. Lokalizované řetězce by proto měly být uloženy v jednotném kódování iso-8859-2.


Kontextová nápověda

Kontextová nápověda modulu je definována v samostatném HTML souboru (/rdata/resources/modules/nazev_modulu/help.htm), který obsahuje jednotlivé části kontextové nápovědy. Každá část je uvedena klíčovým slovem <!--WTD_H(NAZEV_CASTI)-->, např.:

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2">
<!--WTD_H(EDIT_C)-->
<h3><u>Editace kategorií</u></h3>
<p>Stránka umoľňuje zaloľit novou nebo editovat jiľ existující kategorii odkazů. </p>
<p><b><u>Funkční tlačítka</u></b></p>
<ul>
  <li><b>Přidat </b>- uloľí novou kategorii do databáze</li>  
  <li><b>Uloľit </b>- uloľí změny do databáze</li>
  ...
</ul>

<p> </p>

<!--WTD_H(EDIT_L)-->
<h3><u>Editace odkazů</u></h3>
<p>Stránka umoľňuje zakládat a editovat odkazy zařazené do stromu kategorií.</p>
<p><b><u>Funkční tlačítka</u></b></p>
<ul>
  <li><b>Nový</b>- zobrazí prázdný formulář pro zaloľení nového odkazu</li>
  <li><b>Přidat </b>- uloľí nový odkaz do databáze</li>  
  ...
</ul>

Volání nápovědy je řešeno prostřednictvím skriptu "/application/help.php" s parametry chapter (název požadované části) a filename (umístění souboru s nápovědou; relativní k /rdata/resources/), např.: http://adresa_serveru/admin/help.php?chapter=NEWSDETAIL&filename=modules%2Fcatalogue%2Fhelp.htm

Tento zdrojový soubor s nápovědou by měl byl být vytvořen v kódování iso-8859-2. O případný převod do jiného vyžádaného kódování se postará taktéž skript help.php.

Třídy pro přístup k databázím

S databázemi se nepracuje přímo příslušnými funkcemi, ale pomocí objektu $db. Jeho použití je popsáno ve kapitole Databázová knihovna.

Knihovny pro vytváření modulů

Následující procedury a funkce jsou umístěny v adresáři /application/modules/common/ v knihovnách:

  • _rights_inc.php
  • _users_inc.php
  • _utils_inc.php
  • _xutils_inc.php

Popis knihovny "_rights_inc":

Knihovna slouží k nastavení práv uživatele v modulu.


Reference knihovny "_ users _inc":
Knihovna obsahuje procedury a funkce na ověření práv uživatele.
  • m_CheckAccess ( strObjectID = '*' )
- ověřuje, zda má uživatel právo na přístup k objektu strObjectID, příp. mu zamezí přístup a přesměruje jej na chybové hlášení. StrObjectID může být buď číselná
hodnota (např. číslo 1 pro diskusní skupinu s tímto číslem) nebo znak "*” , zajímá-li nás přístup k libovolnému objektu.
  • m_isVisible ( strObjectID )
- interní funkce; zjišťuje, zda má uživatel přístup k objektu strObjectID. Fce je analogická k funkci m_CheckAccess, místo přesměrovávání však pouze předává návratovou hodnotu typu boolean.


Reference knihovny "_utils_inc.php":
Knihovna obsahuje procedury a funkce společné všem modulům.
  • printModuleMenu ( strMenuName, strModulePath, strXMLfile='menu.xml' )
- tiskne menu modulu s názvem podle parametru strMenuModule. XML soubor s menu by se měl nacházet na cestě: ( WTD_PATH / resources / modules / strModulePath strXMLFile ).
  • PrintGenerateNewsForm ( strFormTitle, strNewsDefaultTitle, strTemplFileName, additionalInputs = array() )
- pomocí fce. CreateNewsFormBody tiskne formuláře pro přidání nového fragmentu s  formulářem, včetně ošetření druhého průchodu. Předloha se navíc bude lokalizovat pomocí lokálních lokalizačních konstant. Pokud je první znak předlohy "*", použije se kromě toho fce extendedTemplFile.
- parametry udávají: titulek formuláře v jazyce modulu; výchozí nadpis vkládané zprávy; jméno souboru s předlohou formuláře v příslušném adresáři modulu (strTemplFileName); pole s údaji o případných dalších formulářových polích (additionalInputs)
  • Hidden ( strName, strValue )
- vytváří a vrací HTML kód formulářového hidden pole s parametry name=strName, id=strName, value=strValue
  • moduleRedirectToEditNewsButton ( inNewsId )
- vytváří a vrací HTML kód tlačítka odkazujícího na zobrazení editačního formuláře fragmentu s předaným ID (inNewsId)
  • CreateNewsFormBody ( blnDone, additionalInputs=array() )
- tiskne samotné tělo formuláře pro přidání nového fragmentu. Parametr blnDone určuje, zda jde již o druhý průchod (a tedy se má skrýt odesílací tlačítko a zobrazit pole s ID), parametr additionalInputs obsahuje údaje o případných dalších polích.
  • PrintPopUpMenu ( strName, strID, strIDField, strNameField, strTableName, strSelValue, strDefOpt=, strAttribs= )
- vytváří a vrací pop-up menu podle zadaných parametrů
  • SaveNewArticle ( nc_title, nc_categid, nc_publid, nc_langid, strTemplFileName )
- ukládá nový fragment s předanými parametry do databáze a vrací jeho ID.
  • LocalizeFormTemplFile ( strFileName )
- načítá do řetězce soubor (strFileName) s předlohou formuláře a provádí replace všech nalezených klíčových slov podle lokálního lokalizačního souboru
  • getModSettingFromDB ( intLangID, intReceiptID, intSetID, intSpecifGroup = 0 )
- načítá jednu konstantu do MODSETTINGS přímo z DB (pro APPLICATION i SCRIPTS)
- parametry určují ID jazyka (intLangID); ID předlohy (intReceiptID); jedinečné ID konstanty v rámci jazyka a modulu (intSetID); specifickou skupinu (intSpecifGroup)
  • getNameOfLanguage ( intLangID )
- získává název jazyka podle ID, předávaného parametrem intLangID
  • OfferModulePattern ( strName, strLabel, lngPatternID, intDefPatCat )
- tiskne formulář pro nastavení předlohy
- parametry: uvozující jméno formuláře (strName); nadpis (jediného) políčka (strLabel); ID předlohy, pokud bylo již v minulosti nastaveno (lngPatternID); výchozí kategorie předloh (intDefPatCat)
  • OfferStyleOfList ( strName, intSelectedStyle, intRecordsOnPage=null, arrOrderColumns=null, intOrderBy=null, strResultsCountLabel=null, inPatternId=0, inSplitByColumns=null, inSplitByValue=null )
- tiskne formulář pro určení stylu seznamu
- parametry: jméno formuláře (strName); již zvolený, nabízený styl (intSelectedStyle); již zvolený, nabízený počet záznamů/stran (intRecordsOnPage); pole s jednotlivými způsoby třídění (arrOrderColumns); již zvolená, nabízená možnost třídění – číslováno od 1 (intOrderBy); jiný než standardní titulek u políčka s počtem záznamů (strResultsCountLabel); výchozí filtrovaní podle kategorii stylu (inPatternId); pole hodnot pro dělení stylu (inSplitByColumns); vybraná položka dělení stylu (inSplitByValue)
  • ;SetModSetting ( intLangID, intReceiptID, intSpecifGroup, intSetID, intType, Value )
- vkládá / updatuje jednu konstantu v MODSETTINGS
  • OfferModuleNavBar ( strName, strEvent, intLangID, intReceipt, intSpecifGroup, intOffset )
- nabízí formulář pro určení navigační lišty, zároveň se také zpracovává načítání a ukládání hodnot a ošetřování chyb
- parametry: jméno formuláře (strName), strEvent – ovlivňuje průběh podprogramu (může nabývat hodnot cstrEvent_Edit nebo cstrEvent_Save); ID jazyka (intLangID); ID předpisu (intReceipt), NULL pro globální volbu);skupina nastavení (intSpecifGroup); pokud se v jednom modulu využívá několik navigačních lišt, bude intOffset pokaždé zcela jiné
  • getNavBarTextArea ( intOffset, strLabel, strVarName, strValue )
- tiskne formulářové textové pole s použitím předaných parametrů: hodnota VALUE parametru pole (intOffset), popiska před políčkem (strLabel); hodnoty ID a NAME parametru pole (strVarname); hodnota TITLE parametru pole (strValue)
  • getNameOfReceipt ( intReceiptID )
- vrací název Předpisu identifikovaného pomocí ID – parametru intReceiptID
  • getTextField ( headerStr, labelStr, fieldName, fieldValue, fieldSize=50 )
- tiskne formulářové políčko s použitím předaných parametrů: nadpis tabulky s políčkem (headerStr); nadpis před políčkem (labelStr); hodnoty ID a NAME parametru políčka (fieldName); hodnota VALUE parametru políčka (fieldValue); šířka políčka (fieldSize)
  • SetReceipt ( inName, intReceiptID=0 )
- nastavuje Předpis podle předaného názvu (inName) nebo ID (intReceiptID)
  • RemoveReceipt ( intReceiptID )
- odstraňuje nastavení Předpisu podle předaného ID (intReceiptID)
  • getAuthorizationTypes ( )
- vrací pole s definovanými typy a popisem autorizace
  • getGlobals ( prefix='f_' )
- vytváří a vrací spustitelný příkaz pro automatické zpřístupnění globálních proměnných (podle zadaného vzoru prefix) pro funkci; příkaz se používá přes eval()
  • wtdReplaceSimple ( keyword, value, body, metaBegin=strMetaBegin, metaEnd=strMetaEnd )
- nahrazuje v řetězci body všechny WTD metatagy s klíčovým slovem keyword za hodnotu value. Celé klíčové slovo se skládá ze spojení metaBegin, keyword a metaEnd.
  • wtdReplaceIf ( keyword, body, clause=true, ifBegin=wtdifbegin, ifEnd=wtdifend )
- pokud je splněna podmínka clause, nahrazuje v řetězci body všechny WTD metatagy IF s podmínkou keyword jako jejich druhým parametrem. Pokud splněna není (clause = FALSE), klíčové slovo smaže.
  • getScriptForModulesMenuReload ( )
- vrací kompletní JavaScriptový tag pro refresh rámce, který obsahuje výpis položek v menu modulu
  • moveToPageForm ( intObjID, strDynamicField )
- pomocí funkce getMoveButton vrací odkaz na formulář Stránky
  • moveToStyleForm ( intObjID, strDynamicField )
- pomocí funkce getMoveButton vrací odkaz na formulář Stylu
  • getMoveButton ( strObjName, intObjID, strHint, strDynamicField, intIndex )
- interní funkce; používaná ke generování tlačítka (odkazu) funkcemi moveToPageFormmoveToStyleForm.


Reference knihovny "_xutils_inc.php":
Knihovna obsahuje personalizační procedury a funkce.
  • ModuleRegistrationInstalled ( )
- zjišťuje, zda je nainstalovaný (a aktivní) modul 301 (Registrace a Personalizace)
  • getNewGUIDRand ( )
- interní funkce; generuje 40 znaků dlouhý náhodný řetězec
  • getNewGUID ( )
- volá funkci getNewGUIDRand() a vrací její výsledek
  • getRandomChar ( )
- vrací náhodně zvolené písmeno
  • make_seed ( )
- vrací aktuální timestamp v desetinném tvaru (s přesností na jednu desetinu)
  • xGetUserIDInsertNew ( theGUID )
- vrací číslo uživatele, který je buď nalezen podle předaného theGUID nebo je nově založen a předané theGUID je mu přiděleno
  • xNewAnonymousUser ( theGUID )
- vkládá nový záznam do tabulky XUSER a vrací jeho ID – číslo nového uživatele

Objektová knihovna pro uživatelský interface

Účel knihovny

Knihovna má za cíl zpřehlednit, sjednotit a zjednodušit tvorbu grafického rozhraní ve WTD. Výsledný výstup se po stránce HTML prakticky neliší od původního ručně psaného HTML, ale ze strany PHP skriptu přináší následující výhody:

  • Oddělení prezentace od logiky – použití MVC modelu.
  • Skrytí implementace a HTML kódu – vše se provádí obsluhou tříd
  • Vyšší přehlednost kódu
  • Snadnější modifikovatelnost kódu
  • Jednotný způsob práce s třídami, systematické názvosloví API

Rozsah využití

Knihovna pokrývá dvě poněkud odlišné oblasti WTD GUI:

Formuláře – detailní zobrazení/editaci jednoho záznamu z databáze, typicky v pravém dolním rámu.

Výpisy – stránkovatelný výčet záznamů, typicky v horním rámu.

Knihovna v současné verzi řeší vytváření HTML kódu uvnitř formulářů, tj. dialogových a grafických prvků, nikoli samotného formuláře (<FORM>) a html webové stránky (<HEAD>,<BODY>).

Formuláře

Vychází se z koncepce HTML, kde jednotlivé skupiny HTML tagů jsou obaleny jinými skupinami tagů atd. Stejně tak při použití knihovny jsou jednotlivé prvky jsou vloženy do nadřazených prvků, a ty zase do nadřazených, až je vytvořena celá konstrukce. Pořadí vkládání prvků do sebe je prakticky dané ze struktury WTD formulářů, ale lze je také částečně měnit.

Rozdělení formuláře WTD z hlediska HTML komponent

Komponenta HtmlPane

Komponenta nejvyšší úrovně, reprezentuje celou plochu formuláře. Obsahuje tři kontejnery, do nichž lze přidávat další komponenty:

  • leftArea vlevo nahoře, typicky pro tlačítka
  • rightArea vpravo nahoře, např. pro roletku se stavem zprávy
  • tabsArea hlavní kontejner, typicky pro objekty typu HtmlTab

Dále tato komponenta obsahuje nadpis, ikonu a link na nápovědu.

Komponenta HtmlTab

Reprezentuje jednu záložku ve formuláři. Obsahuje volitelně nadpis záložky a kontejner rows pro uchování objektů typu HtmlRow. Použití komponenty HtmlTab se doporučuje, i když vizuálně žádné záložky nechceme; pokud je do HtmlPane vložena pouze jedna komponenta HtmlTab, záhlaví záložky se nezobrazí.

Komponenta HtmlRow

Představuje jeden řádek formuláře, typicky se skládající z nadpisu vlevo, a jednoho či více ovládacího prvku vpravo. Tomu odpovídají dva kontejnery leftArea a rightArea, do nichž se vkládají komponenty skupiny HtmlInputs.

Skupina komponent HtmlInputs

Tato skupina komponent představuje konkrétní druhy vstupních prvků formulářů HTML.

HtmlButton Tlačítko
HtmlCheckBox Zaškrtávací okénko
HtmlHiddenField Skryté pole
HtmlLabel Nadpis
HtmlListBox Výběrový seznam
HtmlListBoxItem Prvek seznamu
HtmlRadio Ovládací přepínač "radio"
HtmlSubmitButton Tlačítko pro odeslání
HtmlTextArea Víceřádkové textové pole
HtmlTextField Textové pole

Seznam komponent typu HtmlInputs

Výpisy

U zobrazení výpisů se vychází z koncepce definování datových "sloupců", agregovaných do výsledné tabulky. Následně je třeba naplnit objekt daty, která jsou pak graficky reprezentována dle nastavení jednotlivých sloupců a celé tabulky.

Rozdělení výpisu ve WTD z hlediska HTML komponent

Komponenta HtmlTable

Komponenta obsahuje nadpis, volitelně odkaz pro přidání záznamu a prohledání. Obsahuje kontejner pro objekty typu HtmlTableColumn a pole datových záznamů, které jsou zobrazovány. Komponenta sama se stará o stránkování výpisu.

Komponenta HtmlTableColumn

Komponenta řídí vzhled jednoho sloupců výpisu. Lze zadat nadpis záhlaví, styl, zarovnání, šířku atd.

Praktický příklad - Formulář pro editaci záznamu

V příkladu si sestavíme formulář pro editaci imaginárního záznamu. Obsahuje 4 ovládací prvky ve dvou záložkách a tři funkční tlačítka.

Komponenta $mainPane s zobrazenou záložkou $tab1

Skript je nedílně spjat s architekturou WebTodate, začíná povinnými knihovnami, jako ostatní skripty:

<?php

include_once ("../config/global.php");
include_once ("../includes/init.php");

Následuje zpracování proměnných,

$f_label = removeNullStr('label', );
$f_body = removeNullStr('body', );
$f_color = removeNullStr('color', 0);
$f_publicate = removeNullStr('publicate', false);

Standardní HTML hlavička WebToDate, ani zde se nic nemění.

print wtdPageHead('htmlComponents demo');
print '</head><body>';

Vlastní tag formuláře je v této verzi také mimo oblast tvořenou knihovnou.

print '<form name="myform">';

Následuje vytvoření objektu mainPane - kořenového objektu celé struktury.

$mainPane =& new HtmlPane('Můj první WTD formulář');

Pro snadné přidání odesílacího tlačítka je navržena metoda addSubmitButton, druhý parametr je hodnota předávaná do proměnné $ev, shodně s koncepcí původního WTD. Přidružený skrytý input je tvořen automaticky.

$mainPane->addSubmitButton('Uložit', cstrEvent_Save );
$mainPane->addSubmitButton('Smazat', cstrEvent_Delete );

Nyní přistoupíme ke tvorbě třetího tlačítka. Jelikož tlačítko se skriptem je více specializované, vytvoříme jeho objekt v pomocné proměnné:

$buttPreview =& new HtmlButton('test', 'Test');

Nyní můžeme snadno toto tlačítko modifikovat. Přidáme tooltip:

$buttPreview->setToolTip("Vypíše název komponenty");

Přidáme tělo JavaScriptové funkce. Může být libovolně dlouhá, odkaz na původní komponentu (this) je v JS proměnné "component”.

$buttPreview->addEvent('alert(component.name)');

Přidáme k ostatním tlačítkům.

$mainPane->addToLeftArea( $buttPreview );

Nyní si připravíme objekt pro první záložku:

$tab1 =& new HtmlTab('Základní');

V pomocné proměnné připravíme vstupní pole.

$inpLabel =& new HtmlTextField('label', $f_label );
$inpLabel->setWidth(TEXT_URL);

Vytvoříme řádek formuláře s připraveným polem a požadovaným popisem.

$row1 =& new HtmlRow('Nadpis', $inpLabel);

Vložíme do záložky.

$tab1->addRow( $row1 );

Podobným způsobem připravíme druhý řádek.

$inpBody =& new HtmlTextArea('body', $f_body );
$inpBody->setWidth(TEXT_URL);
$inpBody->setRowCount(4);
$row1 =& new HtmlRow('Tělo', $inpBody);
$tab1->addRow( $row1 );

Vložíme takto zhotovenou záložku do hlavní komponenty.

$mainPane->addTabObject($tab1);

Nyní již hlavní komponenta mainPane obsahuje strukturu podle obrázku 2.

Budeme nyní pokračovat druhou záložkou.

$tab2 =& new HtmlTab('Rozšířené');

Připravíme si objekt typu HtmlListBox.

$inpColor=& new HtmlListBox('color', $f_color);

Jednoduše v něm vytvoříme 3 prvky typu ListBoxItem, vstupní data jsou ve tvaru pole.

$inpColor->addItemsArray( array('red'=>'červená', 'blue'=>'modrá', 'yellow'=>'žlutá'));

Pokud chceme prvek ListBoxItem více specializovat, použijeme opět pomocnou proměnnou.

$boxitemTrans =& new HtmlListBoxItem(-1, 'transparentní');

Nastavíme požadované atributy.

$boxitemTrans->setAttribute('style', 'color:gray;');

Vložíme do HtmlListBoxu.

$inpColor->addItemObject($boxitemTrans);

HtmlListbox vložíme do nového řádku HtmlRow a ten následně do připravené záložky HtmlTab, kterou máme v proměnné $tab2. Všimněte si zkrácené syntaxe bez pomocné proměnné pro objekt typu HtmlRow.

$tab2->addRow( new HtmlRow('Barva', $inpColor));

Syntaxi vkládání můžeme ještě více zkrátit, pokud všechny použité objekty lze dostatečně nastavit pouze použitím konstruktorů jejich tříd.

$tab2->addRow( new HtmlRow('Publikovat', new HtmlCheckbox('publicate', $f_publicate)));

Naplněný objekt typu HtmlTab vložíme do hlavní komponenty a vytiskneme obsah.

$mainPane->addTabObject($tab2);
print $mainPane->getHtml();

Tím role knihovny komponent v našem příkladu končí. Následuje uzavření formuláře, těla a celého HTML souboru.

print '</form></body></html>';

?>

Druhá záložka $tab2 z příkladu formuláře.

Výpis záznamů

Použití komponenty pro výpis záznamů bude podstatně jednodušší, jak vyplývá z méně komplikované struktury grafického objektu.

Pro příklad použijeme nyní pro změnu kus reálné aplikace WebToDate, a sice výpis kategorií zpráv. Vynecháme hlavičku a přejdeme rovnou k části která používá HtmlComponents.

Vytvoříme objekt tabulky s výpisem

$objTable = new HtmlTable(loc('h_categ_asp_006'));

Nastavíme odkaz na editaci a přidání.

$objTable->setEditLink('edit_c.php?ev=edit&id=%s');
$objTable->setAddLink('edit_c.php?ev=new');

Zažádáme o vytvoření sloupce.

$objTable->addColumnSimple(loc('h_categ_asp_005'));

Načteme seznam záznamů z databáze.

$query = 'select ID, NAZEV from NEWSKATEG order by NAZEV';
$qId = $db->query( $query );

Projdeme výsledek a naplníme datové pole. Tvar pole předávaného metodě addDataRow() musí být takový, že první sloupec je ID záznamu, které se používá pro odkaz do editačního rámce.

while( $rs = $db->fetch_row( $qId ))
{
$objTable->addDataRow( $rs );
}

Nastavíme, na stránku dat chceme zobrazit.

$objTable->setPageSelected( $f_pg);

Nastavíme hlášení, které komponenta zobrazí v případě, že nebyla předána žádná data.

$objTable->setNoResultMsg( loc('h_categ_asp_007') );

Vypíšeme výsledný HTML kód.

print $objTable->getHtml();

Výpis kategorií zpráv WebToDate.

Vytváření veřejné části modulu

Založení veřejné části modulu

První kroky při vytváření veřejné části nového modulu jsou následující:

  • Vytvořte adresář pro modul v adresáři scripts/modules.
  • Do adresáře zkopírujte soubor _constants.php. V souboru jsou definovány zejména konstanty identifikující jednotlivá nastavení modulu, která se v administrační části ukládají a ve veřejné čtou, typicky se tedy používá stejná sada konstant.

Dále se vytvářejí jednotlivé skripty – druhy zobrazení. Lokalizační soubor veřejné části se typicky ukládá do adresáře rdata/resources/modules/název_modulu/scripts a obsahuje pouze chybová hlášení fatálních chyb.

Povinné soubory veřejné části modulu

Obecné konstanty jsou uloženy v souboru /includes/constants.php, veřejné konstanty modulu pak ve /scripts/modules/nazev_modulu/_constants.php. Funkce pro přístup k některým (především novějším) konstantám z config/global.php jsou uloženy v souboru /includes/ConstantsAccess.php. Tyto funkce existují z toho důvodu, že uživatel nemusí mít vždy nainstalovanou nejnovější verzi konfiguračního souboru, funkce tedy ověřují existenci konstanty a případně vracejí ve funkci pevně nastavenou výchozí hodnotu. Např.:

/**
*	@desc 	Returns the absolute path to 'resources' directory
*/
function getResourcesPath() {
return replaceNotDefinedByDefault('RESOURCES', getWTDPath() . 'rdata/resources/');
}

Lokalizované texty jsou definovány v samostatném souboru zvlášť pro část administrační (jsou využívány v kódech v adresáři /application/) a zvlášť pro veřejnou (jsou využívány v kódech v adresáři /scripts/). Tyto soubory jsou uloženy jako "/rdata/resources/modules/nazev_modulu/ (application | scripts ) /_localization_inc.php". Přístup k těmto konstantám v samotném kódu je řešen pomocí funkce loc('nazev_konstanty), která vrací obsah konstanty. Ta jednak ošetřuje, zda požadovaná konstanta vůbec existuje (pokud ne, nic nezobrazí), jednak převádí vracený text do správné znakové sady podle parametrů nastavených v konfiguračním souboru.

Knihovny pro vytváření modulů

Následující procedury a funkce jsou umístěny v adresáři /scripts/modules/common/ v knihovnách:

  • _utils_inc.php
  • _xutils_inc.php
Reference knihovny "_ utils _inc":
Knihovna obsahuje procedury a funkce společné pro všechny moduly.
  • getDefaultLang ( )
- vrací ID výchozího jazyka systému
  • getNameOfLanguage ( intLangID )
- vrací název jazyka podle předaného ID – parametru intLangID
  • getNameOfCateg ( intCategID )
- vrací název kategorie podle předaného ID – parametru intCategID
  • getLangLocale ( intLangID )
- vrací locale řetězec jazyka podle jeho ID – parametru intLangID
  • getLangIDFromLocale ( strLocale )
- vrací ID jazyka podle jeho locale řetězce – parametru strLocale
  • getModSettingFromDB ( intLangID, intReceiptID, intSetID, inSpecificGroup=null, moduleID=intGlobModuleID )
- načítá jednu konstantu do MODSETTINGS přímo z DB (pro APPLICATION i SCRIPTS)
- parametry určují ID jazyka (intLangID); ID předlohy (intReceiptID); jedinečné ID konstanty v rámci jazyka a modulu (intSetID); specifickou skupinu (intSpecifGroup); ID modulu (intGlobModuleID)
  • dispayUserErrorMessage ( strStateName, &strContent, replaceIt=NULL )
- překládá řetězec "xxx" z klíčového slova WTD_IF(strStateName,"xxx").
- parametry: strStateName určuje první parametr v klíčovém slově, který se hledá; &strContent představuje HTML kód, ve kterém hledání probíhá; replaceIt je pole určující které klíčové slovo se má navíc v nahrazovaném řetězci najít.
- pokud není klíčové slovo vůbec nalezeno, nic se nestane, každopádně se vždy nastaví globální proměnná intUserError na >1, aby se zamezilo dalším akcím, které v tuto chvíli nemají smysl.
  • removeAlertTags ( &strContent )
- odstraňuje z odkazovaného řetězce strContent všechny dosud neodstraněná klíčová slova typu  WTD_ALERT
  • getNavigBar ( intLangID, intReceiptID, intNavigBarOffset, intActPage, intPageCount, strScript )
- vytvoří navigační lištu podle předaných parametrů
- parametry: ID jazyka (intLangID); ID předpisu (intReceiptID); počáteční SETID skupiny konstant definujících lištu (+0 až +7) (intNavigBarOffset ); aktuální stránka (intActPage); počet stránek (intPageCount); část URL cesty s odkazem (např. "fulltxt.asp?pg=" nebo jen "?pg=") (strScript)
  • PrintErrorMessage ( strErrMsg )
- tiskne technickou chybovou hlášku strErrMsg
  • toForm ( str )
- nahrazuje v řetězci str znaky PHP funkcí htmlspecialchars( str, ENT_QUOTES )
  • toSql ( str )
- ošetří v řetězci str zpětná lomítka a apostrofy
  • FatalError (errID, errMsg )
- vypisuje fatální chybu errMsg
  • getTemplate ( settingID, langID, intReceiptID=NULL )
- hledá a vrací obsah šablony podle čísla nastavení v MODSETTINGS v rámci daného modulu (settingID) a ID jazyka (langID); intReceiptID určuje vynucení jiné předlohy
  • getWTDStyle ( settingID, langID, &a, intReceiptID=NULL )
- načítá do parametru a WTD styl podle nastavení v MODSETTING (settingID) a ID jazyka (langID)
  • getGlobals ( prefix='f_' )
- vytváří spustitelný php příkaz global s parametry podle vzoru pro automatické zpřístupnění globálních proměnných do funkcí; použití přes eval()
  • getPathToModules ( )
- vrací cestu do adresáře s moduly pro použití v URL, cesta je ukončena "/"
  • wtdReplaceSimple ( keyword, value, body, metaBegin=strMetaBegin, metaEnd=strMetaEnd )
- nahrazuje v řetězci body všechny WTD metatagy s klíčovým slovem keyword za hodnotu value. Celé klíčové slovo se skládá ze spojení metaBegin, keyword a metaEnd.
  • wtdReplaceIf ( keyword, body, clause=true, ifBegin=wtdifbegin, ifEnd=wtdifend )
- pokud je splněna podmínka clause, nahrazuje v řetězci body všechny WTD metatagy IF s podmínkou keyword jako jejich druhým parametrem. Pokud splněna není (clause = FALSE), klíčové slovo smaže.


Reference knihovny "_xutils_inc.php":
Knihovna obsahuje personalizační procedury a funkce.
  • setWTDGUIDCookie ( theGUID )
- nastavuje do Cookies expiraci k aktuálnímu jednoznačnému identifikátoru theGUID (na jeden rok)
  • getWTDGUIDCookie ( )
- získává z Cookies informaci o uživateli
  • x_ModuleRegistrationInstalled ( )
- zjišťuje, zda je nainstalovaný (a aktivní) modul 301 (Registrace a Personalizace)
  • getNewGUIDRand ( )
- interní funkce; generuje jedinečný 40 znaků dlouhý náhodný řetězec
  • getNewGUID ( )
- volá funkci getNewGUIDRand() a vrací její výsledek
  • getRandomChar ( )
- vrací náhodně zvolené písmeno
  • make_seed ( )
- vrací aktuální timestamp v desetinném tvaru (s přesností na jednu desetinu)
  • xGetUserIDInsertNew ( theGUID )
- vrací číslo uživatele, který je buď nalezen podle předaného theGUID nebo je nově založen a předané theGUID je mu přiděleno
  • xNewAnonymousUser ( theGUID )
- vkládá nový záznam do tabulky XUSER a vrací jeho ID – číslo nového uživatele
  • xGetUserID ( )
- vrací ID uživatele podle Cookie; pokud Cookie neexistuje, uloží je a použije 0
  • xGetUserIDAlways ( )
- vrací ID uživatele podle Cookie; pokud Cookie neexistuje nebo není nalezeno, založí nového uživatele a vytvoří Cookie
  • xGetUserIDNew ( )
- zakládá nového uživatele s novým Cookie a vrací jeho ID
  • xGetCurrentUserId ( )
- vrací číslo aktuálního uživatele v databázi XUSERGUID
  • xGetUserParameters ( intAuthMode, intUserID )
- vrací v poli z databáze seznam hodnot týkajících se anonymních uživatelů pro uživatele s daným ID
  • xUpdateUserParameter ( userID, paramName, pType, pValue )
- zapíše do databáze anonymních uživatelů k uživateli s ID userID hodnotu pValue datového typu pType parametru s názvem paramName
  • xRegisteredOnly ( intAuthMode )
- volá se na začátku každého modulu, který pracuje s registrovanými uživateli. Parametr intAuthMode určuje typ autentifikace.
  • xGetRegisteredUserId ( intAuthMode )
- podle registračního módu intAuthMode zjišťuje, zda je uživatel identifikován
  • xMigrateAnonymousUser ( previousID, currentID )
- volá se ve chvíli, kdy se zjistí, že uživatel byl již v anonymních uživatelích veden pod jiným ID; parametry jsou staré (previousID) a nové (currentID) ID
  • isUserActive ( intUserID )
- ověřuje, zda je uživatel s ID intUserID aktivní (má aktivní záznam v tabulce XREGISTR)

Ošetření chybových stavů ve skriptech

Skripty by měly být ošetřeny tak, aby nikdy nedošlo k chybě skriptu. Mohou v zásadě nastat dva druhy chybových stavů:

  • Fatální chyba – nenalezena šablona, styl apod.
  • Uživatelská chyba – špatný formát vstupních údajů ve formuláři apod.

Pokud dojde k fatální chybě, měla by se vždy volat funkce FatalError, která ukončí činnost skriptu. Hlášení pro fatální chyby by se měly nacházet v lokalizačním souboru. Uživatelské chyby by měly být pokud možno ošetřeny pomocí mechanismu s WTD_IF klíčovými slovy přímo v šabloně.

Hlášení typu pokynů k ošetření chyb apod. se vkládají do předlohy ve formátu

<!--WTD_IF(příznak,hláška)-->

tedy například

<!--WTD_IF(WRONGDATETO,"Chybný formát datumu v poli Datum do.")-->

Příslušný veřejný skript musí zajistit, že tento kód se "odkomentuje" v případě, že dojde k příslušné události, nebo kompletně odstraní v případě, že k této události nedojde. Tyto hlášky opět mohou být i součástí fragmentu s formulářem, který se vygeneruje jakožto předloha.

Za účelem rendrování WTD_IF tag; se používají knihovní funkce dispayUserErrorMessage a removeAlertTags.

Podpora vícejazyčných webů

Každý modul musí přímo podporovat vícejazyčnost instalace WebToDate. Tato podpora se skládá ze dvou částí:

  • Podpora prezentační grafiky ve více jazycích, tj. lze zvolit zda chci zobrazit data daného modulu uvozená určitým jazykem.
  • Podpora dat daného modulu v daném jazyce, tedy chceme nastavit, že daná diskuse je v angličtině a pak mít možnost zobrazit seznam pouze těch diskusí, kterou jsou vedeny v angličtině.

Podpora pro nastavení v administrační části je zabudována přímo do funkcí pro administrační rozhraní, takže pokud se správně definují příslušné elementy v popisném XML souboru, mělo by vše fungovat.

Ve veřejných skriptech je třeba zajistit podporu volby správného nastavení z URL pomocí parametrů lid nebo locale. Každý skript na veřejné části musí podporovat oba parametry.

  • lid – ID jazyka pro výběr nastavení
  • locale – zkratka jazyka pro výběr nastavení ("CS", "EN" atd.)

Pokud modul obsahuje i data závislá na jazyce, měly by být funkční i parametry

  • dlid – ID jazyka pro data
  • dlocale – zkratka jazyka pro data ("CS", "EN" atd.)

Přitom platí:

  • je-li uveden pouze parametr lid či locale, automaticky se berou data daného jazyka
  • je-li uveden pouze dlid nebo dlocale, zobrazují se data daného jazyka s použitím nastavení pro výchozí jazyk
  • je-li uvedeno dlid=all nebo dlocale=all, berou se data všech jazyků nezávisle na parametrech lid či locale.

Za výchozí jazyk se považuje jazyk definovaný v tabulce NEWSLANGUAGE s nejmenším ID. Například vyvolání skriptu default.asp zobrazí tutéž stránku jako default.asp?locale=CS (za předpokladu, že čeština je výchozí jazyk), URL default.asp?locale=EN pak zobrazí stejnou stránku ovšem s použitím nastavení pro angličtinu (tj. anglickou předlohu, anglický styl seznamu atd.).

Aby se volba jazyka mohla přenášet i do skriptů, které se volají z dané stránky, je třeba definovat příslušná klíčová slova pro URL stránek s jiným druhem zobrazení dat. Například odkaz na detail jedné akce v Kalendáři akcí je třeba ve stylu pro příslušný seznam definovat takto:

<a href="<!--WTD_DIARY(DIARYURL)-->"><!--WTD_DIARY(NAME)--></a>

Definice

<a href="/scripts/modules/diary/action.php?id=<!--WTD_DIARY(ID)-->"><!--WTD_DIARY(NAME)--></a>

je sice funkční, ale pouze pro jeden jazyk. Pokud se zobrazuje stránka default.php?lid=2, je třeba, aby se za klíčové slovo DIARYURL dosadilo například

/scripts/modules/diary/action.php?lid=2&id=26

Registrace a personalizace

Integrace s personalizačními funkcemi

Pokud modul nějakým způsobem aktivně pracuje s uživateli veřejné části (např. obsahuje vstupní formuláře s osobními daty uživatele) nebo dokonce má být přístupný pouze pro registrované uživatele, využívá knihovny a funkce modulu Registrace a personalizace.

Tyto funkce mají za cíl:

  • Standardizovanou metodou ošetřit přístup ke stránkám určeným pouze pro registrované uživatele
  • Vést databázi anonymních uživatelů a sbírat osobní údaje těchto uživatelů
  • Použít informace z databáze anonymních či registrovaných uživatelů tak, aby uživatel nemusel vyplňovat opakovaně údaje již jednou na server zadané.

Modul Registrace a personalizace je vyvíjen jednak jako samostatný modul, který obecně řeší problematiku registračních formulářů, přihlašování a správu registrovaných uživatelů veřejné části, jednak jako sada knihoven, které mohou využívat jiné moduly.

Každý modul, u kterého to má smysl nebo jeho část, je přepnutelný z hlediska přístupu uživatelů do jednoho ze čtyř režimů:

  • Pouze registrovaní, explicitní přihlášení - vkládání dat do modulu vyžaduje průchod přes přihlašovací stránku, údaj o přihlášení se drží v sessions
  • Pouze registrovaní, automatické rozpoznávání – mohou používat opět pouze registrovaní uživatelé, ale pokud se pomocí cookies zjistí, že jde o registrovaného uživatele, nevyžaduje se login
  • Anonymní uživatelé, automatické rozpoznávání – modul může používat kdokoliv, ale pomocí cookies se sleduje a modul mu např. předvyplní e-mail v případě, že je tento již na serveru uložen
  • Anonymní uživatelé bez rozpoznávání – v tomto případě se rezignuje na jakékoliv funkce ohledně cookies, pokud např. po sobě dvakrát zadává diskusní příspěvek a diskuse vyžaduje e-mail, musí jej dvakrát vyplnit.

Pro manipulaci s osobními údaji se používají následující zásady:

  • Údaje uživatele potřebné pro práci modulu se vždy ukládají to příslušné tabulky konkrétního modulu (např. zadává-li v modulu Poradny uživatel svůj e-mail, na který mu má přijít odpověď z poradny, zapíše se tento e-mail do databáze dotazů poradny).
  • Osobní údaje uživatele se kromě datových tabulek modulů zapisují do tabulky anonymních uživatelů ve všech případech s výjimkou toho, kdy je daný modul v režimu Anonymní uživatelé bez rozpoznávání.
  • Osobní údaje se předvyplňují do formulářů ve všech případech kromě toho, kdy je modul přepnut do režimu Anonymní uživatelé bez rozpoznávání. Přitom se data načítají z tabulky anonymních uživatelů v případě, že je modul v režimu Anonymní uživatelé, automatické rozpoznávání, z tabulky registrovaných v ostatních případech.
  • Data v tabulce registrovaných uživatelů se nikdy nemění automaticky, vždy pouze explicitně v rámci modulu Registrace a personalizace (registračním formulářem nebo z administrační části).

Data modulu Registrace a personalizace se nacházejí v tabulkách s názvem začínajícím X. Moduly by ovšem do těchto tabulek neměli přistupovat přímo, ale vždy pouze přes funkce v knihovně xutils. Příslušné databázové tabulky i knihovna xutils se instaluje s každou verzí WebToDate nezávisle na tom, zda je nebo není instalován samotný modul Registrace a personalizace.

Struktura uložených dat uživatelů je schématicky znázorněna na následujícím diagramu.

Uživatel částí vyžadujících registraci a i ostatních modulů je opatřen XUSERID, na které jsou navázána všechna data tohoto uživatele. V tomto pojetí se pak registrace (XREGISTR) považuje za další datovou strukturu svázanou s daným XUSERID. Možný postup plnění tabulek v čase je pak např. následující:

  1. Uživateli se při návštěvě nějaké stránky modulu přiřadí nějaké GUID. To automaticky neznamená, že se něco zapisuje do databáze.
  2. Uživatel např. něco zapíše do anonymní diskusní skupiny – v tom případě vznikne zápis v XUSERGUID, XUSER a tabulkách diskusí.
  3. Uživatel se zaregistruje – vznikne zápis v XREGISTR odkázaný na příslušné XUSERID.
  4. Dokud nedojde k nestandardní situaci, na dané USERID se odkazují další a další záznamy v datových tabulkách modulů.
  5. Pokud dojde ke ztrátě cookie apod. (obdobná logická situace může nastat v případě, že uživatel např. používá dva počítače a přihlašuje se k databázi registrovaných uživatelů), může dojít k problémové situaci: díky nějaké činnosti se tomuto uživateli přidělilo nové GUID, XUSERID i eventuálně nějaké záznamy v datových tabulkách modulů. Pokud se potom uživatel následně přihlásí k registrované databázi, dochází k logickému konfliktu – má v tuto chvíli dvě USERID, kterým mohou v datových tabulkách odpovídat dvě sady dat. Konflikt se v rámci přihlašovacího skriptu řeší tímto postupem (USER1 je starší číslo platné do ztráty cookie, USER2 je nové číslo spřažené s novým cookie):
  • V XUSERGUID se XUSERID přepíše u USER2 na USER1 pro aktuálně platné GUID
  • Projdou se všechny tabulky všech modulů, ve kterých se vyskytuje nové USER2 a přesměrují se na USER1 podle tohoto pravidla: je-li v dané tabulce USER2, přečíslují se tyto záznamy na USER1 s výjimkou tabulek XREGISTR A XANONYMOUS; v XREGISTR se nikdy nic nemění, v XANONYMOUS platí, že je-li v dané tabulce pouze USER2, přečíslují se tyto záznamy na USER1, pokud jsou v dané tabulce USER1 i USER2, záznamy USER2 se mažou (přednost musí mít data svázaná s registrací)
  • V tabulce XUSERGUID a XUSER se smažou záznamy s USER2, neboť již nikam neukazují.

Knihovna personalizačních funkcí

Reference knihovny je uvedena v kapitole Knihovny pro vytváření modulů.

Jako příklad použití je možné uvést skript newsquestion.php modulu Poradny (/script/modules/advice/).

<?php
/**
*@package newquestion.php
*/

include( '_constants.php');
include( '_file_inc.php');
include( '../common/_utils_inc.php');
include( '../common/_xutils_inc.php');
include( '_utils_inc.php');
getModLoc ( 'modules/advice/scripts' );
getModLoc ( 'modules/common/scripts' );

$strErrMsg = '';
$strTemplContent = '';
$blnOK = true;

$intAdviceID	= intFromForm('id');				//ID poradny, do které se bude nový dotaz přidávat
$intReceiptID 	= getAdvProperty($intAdviceID, 'RECEIPTID');	//ID předpisu, který poradna používá
$blnPrivate 	=  blnFromForm('private');
//Zjištění akt. jazyka nastavení a jazyka dat
langSettings();

//Zjištění, jestli se jedná o průchod po odeslání formuláře
$blnProcessed = isset($name) || isset($question);

//AUTENTIFIKACE
$intAuthMode = getAdvProperty($intAdviceID, 'AUTHMODE');
$intUserID = xRegisteredOnly($intAuthMode);

if (!$intUserID && $intAuthMode!=ANONYMOUS) {
	print 'Mód poradny není anonymní, ale přesto se nenastavilo ID uživatele.';die;
}

//Vytvoření objektu s popisem form. polí
$objFields = new TAdvFormFields();

$strTemplContent = getTemplate(intNQSET_TemplID, $intLangID, $intReceiptID);		//Načtení předlohy

if (!$strErrMsg){
	//Vložení polí, vypovídajících o dané poradně
	showAdviceDesc ($intAdviceID, $strTemplContent);

	//Počítáme s přítomností vyhledávacího formuláře
	showSearchForm($strTemplContent);

	if (!$blnProcessed) {
		//1. PRŮCHOD
		FirstWay();
	}else{
		//2. PRŮCHOD
		//Načteme věci z formuláře
		$objFields->readFromForm();
		//Při 3 a 4 módu, pokud je odeslané pole prázdné, předpokládáme, že jej ani admin neumístil
		//do formuláře a očekává jeho automatické dosazení z XREGISTR
		if ($intAuthMode==REGISTERED || $intAuthMode==REGISTEREDWITHRECOGNITION){
			xGetUserParameters($intAuthMode, $intUserID);
			//Opět nastavíme formpole podle DB, ale tentokrát jen prázdné hodnoty
			$objFields->setFormVarsAccordingTo ($xUserParameters, true);
		}
		//Kontrola úplnosti a správnosti vyplnění formulářových polí
		$blnOK = $objFields->checkForm($strTemplContent);
		//Při stavu bez chyb a módu 2, 3, 4 se nyní zaktualizuje tabulka XANONYMOUS
		if ($blnOK && $intAuthMode!=ANONYMOUS && $intUserID) {
			$objFields->updateDefValuesInDB($intUserID);
		}
		if (!$blnOK){
			//Nahrajeme hodnoty to předlohy, aby si to user opravil
			$objFields->parseFormVarsInTemplate ($strTemplContent);
		}else{
			//Všechno je v pořádku - uložíme dotaz do DB
			saveQuestion( $newQuestionId );
			
			//Zamailujeme adminovi, že by měl odpovědět
			
			// ...zjistime, jestli se ma administratorovi posilat e-mail
			$sendEmail = getModSettingFromDB( cAdviceGlobalLanguage, 0, intPRFSET_NewEmail);

			if( ( $sendEmail == 1 ) && ( $newQuestionId > 0 ) )
			{
				// zjistime, komu se ma email zaslat
				$query = 'select EMAIL from ADVICEMAIN where ID = '. $intAdviceID;
				$emailAdmin = $db->execute_and_get_result( $query );				
								
				// nacteme sablonu
				$templateOk = loadAdviceTemplate( $intLangID, $emailTemplateId, $emailTemplate );

				// pripravime obsah mailu
				if( ( $templateOk ) && ( checkEmail( $emailAdmin ) ) )
				{			
					$mailContent = makeAnswer( 
						$emailTemplate, $intLangID, $newQuestionId, $objFields->getValue('NAME'), 
						$objFields->getValue('QUESTION'), null, time(), null );

					// email charset
					$charset = getCharset();
					
					// nacteme email, z ktereho se odesila
					$sentFrom	= getModSettingFromDB( cAdviceGlobalLanguage, null, intPRFSET_SendEmail);					

					// pripravime hlavicku mailu
					$headers  = "MIME-Version: 1.0\r\n";
					$headers .= "Content-type: text/html; charset=$charset\r\n";
					$headers .= "From: $sentFrom\r\n";

					// odesleme mail
					$mailOk = mail( $emailAdmin, loc('c_advice_asp_062'), $mailContent, $headers );					
				}
			} // ukonceni mailu administratorovi

			$strUrl = isset($url) ? $url : '';
			//20021113 -vaclavs- Vznikl požadavek, že pokud je URL prázdné, má proběhnout přesměrování
			//na úvodní stránku poradny, do které vložil dotaz.
			if (!$strUrl) {
				$strUrl = "firstpage.php?id=$intAdviceID";
			}
			if ($strUrl && !$strErrMsg) {	//Má proběhnout přesměrování?
				redirect($strUrl);
			}else{
				//Replacneme klíč. slovo inserted
				dispayUserErrorMessage(loc('c_objIfInserted'), $strTemplContent);
				//A uděláme vše jako při prvním průchodu, protože jinak by lidé odesílali
				//předvyplněný dotaz znovu a znovu
				FirstWay();
			}
		}
	}
	

	showActLanguage($strTemplContent);
	//Odstranění nevyužitých tagů WTD_IF (if any)
	removeAlertTags ($strTemplContent);
	//Vytištění šablony
	print $strTemplContent;
}Else{
	//Bud´ se vypíše hotová  stránka, nebo technická chybová hláška
	PrintErrorMessage ($strErrMsg);
}






#### Podprogramy ###

function FirstWay(){
	global $objFields, $intAuthMode, $intUserID, $xUserParameters, $strTemplContent;
	//Postaráme se o inicalizaci všech proměnných pro form. pole, užívaných v dotazu
	$objFields->initFormVars();
	//V urč. módech vrátí to, co je uloženo pro tohoto usera v XANONYMOUS (XREGISTR) v glob. poli $xUserParameters
	xGetUserParameters($intAuthMode, $intUserID);
	//Nastavíme všechny záznamy co jen to jde podle pole $xUserParameters
	$objFields->setFormVarsAccordingTo ($xUserParameters);
	//nakonec vlož hodnoty formpolí do předlohy
	$objFields->parseFormVarsInTemplate ($strTemplContent);
	//A všechny zbývající WTD_ADICE(...) tagy smažeme
	$pat = strtr(cstrMetaBeginAdvice . '[A-Z_]*' .cstrMetaEnd, array('('=>'\\(', ')'=>'\\)'));
	$strTemplContent = ereg_replace($pat, '', $strTemplContent);
	$pat = strtr(cstrMetaBeginUser . '[A-Z_]*' .cstrMetaEnd, array('('=>'\\(', ')'=>'\\)'));
	$strTemplContent = ereg_replace($pat, '', $strTemplContent);
}

/**
* Tato funkce ulozi novou otazku
*
* @param	int		$outQuestionId	cislo pridane otazky
*/
function saveQuestion( &$outQuestionId ) {
	global $db, $intAdviceID, $intUserID, $objFields, $strErrMsg;
	$f_id = $db->get_next_id( 'ADVICEITEMS' );

	$outQuestionId = intval( $f_id ); 
	if($f_id <= 0){
		phpError( 64 );	die();
	}
	$sqlGetDate = $db->sql_getdate();
	$query =	'insert into ADVICEITEMS ( ID, ADVICEID, CATEGID, QDATE, LASTMODIF, STATUS )'.
				"values ( $f_id, $intAdviceID, 0, $sqlGetDate, $sqlGetDate, 1 )";

	$qId = $db->query( $query );
	if( ! $qId ){
		phpError( 65, $db->error() );
	}
	// priprava hodnot pro ulozeni do databaze
	$db_name		= $objFields->getValueForDb('NAME', 255);
	$db_email		= $objFields->getValueForDb('EMAIL', 255);
	$db_firstname	= $objFields->getValueForDb('FIRSTNAME', 30);
	$db_lastname	= $objFields->getValueForDb('LASTNAME', 30);
	$db_nickname	= $objFields->getValueForDb('NICKNAME', 30);
	$db_private		= $objFields->getIntValue('PRIVATE');
	$db_xuserid		= $intUserID? intval($intUserID) : 'NULL';
	// v pripade fulltextu ulozime dotaz na disk
	if( FULLTEXT ) {
		// dotaz a odpoved neukladame do databaze
		$setQuestionAndAnswer = ', QUESTION = NULL, ANSWER = NULL ';
		$f_path = getPathToAdviceFile( $f_id, $intAdviceID );
		$setQuestionAndAnswer = ', PATH = "'. $f_path .'"';
		$strLangLocale = getLangLocale(getAdvProperty($intAdviceID, 'LANGUAGEID'));
		$questionFile = makeAdviceFileContent(
			$objFields->getValue('NAME', 255), $intAdviceID, time(),
			$strLangLocale, $objFields->getValue('QUESTION'), null, false, cAdviceStateWaiting
		);
		$writeOk = writeAdviceToFile( $f_path, $questionFile );
		if( ! $writeOk ){
			$strErrMsg = getLastErrorMessage();
			return;
		}
	}else{
		// dotaz a odpoved ukladame do databaze
		$db_question	= $objFields->getValueForDb('QUESTION');
		$setQuestionAndAnswer = ', QUESTION = "'. $db_question .'", ANSWER = ""';
	}

	$query = 'update ADVICEITEMS set NAME = "'. $db_name .'",'.
		' EMAIL = "'. $db_email .'", FIRSTNAME = "'. $db_firstname .'", '.
		' LASTNAME = "'. $db_lastname .'", NICKNAME = "'. $db_nickname .'", XUSERID=' . $db_xuserid . ', '.
		' FREQUENT = 0, PRIVATE =' . $db_private . ', STATUS = 0,'.
		' CATEGID = 0, LASTMODIF = '. $sqlGetDate . ', QDATE=' . $sqlGetDate .
		$setQuestionAndAnswer . ' where ID = '. $f_id;

	$qId = $db->query( $query );
	if( ! $qId ){
		phpError( 67, $db->error() );
	}
}

//Třída objektu, do kterého se při jeho vytvoření nakešují hodnoty z tabulky ADVICEDESCRIPTION
class TAdvFormFields {
	var $arrUserItems = array ('FIRSTNAME','LASTNAME','NICKNAME','EMAIL');
	var $arrUsedKeys =array();	//Pole klíčů používaných formpolí (pro indexování ostatních polí)
	var $arrUsed=array();
	var $arrRequired=array();
	var $arrValues = array();
	var $arrDescs = array();
	function TAdvFormFields(){
		//Konstruktor načte všechny hodnoty z DB do pole
		global $db;
		$query = 'SELECT * FROM ADVICEDESCRIPTION';
		$qId = $db->query( $query );
		while($row = $db->fetch_array($qId)){
			$this->arrUsed[$row['FIELDNAME']]=$row['USED'];
			if ($row['USED']){
				$this->arrUsedKeys[]=$row['FIELDNAME'];
			}
			$this->arrRequired[$row['FIELDNAME']]=$row['REQUIRED'];
			$this->arrDescs[$row['FIELDNAME']]=$row['FIELDDESC'];
		}
	}
	function initFormVars(){
		//zinicializuje všechny proměnné, používané ve formuláři
		foreach ($this->arrUsedKeys as $value){
			$this->arrValues[$value]='';
		}
	}
	function setFormVarsAccordingTo (&$arrDefaultParams, $blnEmptyFieldsOnly=false){
		//Nastavení všech formpolí podle tohoto pole
		foreach ($this->arrUsedKeys as $value){
			if (array_key_exists ($value, $arrDefaultParams) && $arrDefaultParams[$value] && (!$blnEmptyFieldsOnly || !$this->arrValues[$value])){
				//pokud v default poli tento udaj existuje a je nenulový, nastav podle něj formulář
				$this->arrValues[$value] = $arrDefaultParams[$value];
			}
		}
	}
	function parseFormVarsInTemplate (&$strTemplContent){
		//Vložení hodnot všech používaných polí do předlohy
		foreach ($this->arrUsedKeys as $value){
			$strBeginTag = in_array(strtoupper($value), $this->arrUserItems) ? cstrMetaBeginUser : cstrMetaBeginAdvice;
			#print '<xmp>' . $strBeginTag . strtoupper($value) . cstrMetaEnd . '</xmp><br>';
			if ($value=='PRIVATE') {
				$strTemplContent = str_replace($strBeginTag . strtoupper($value) . cstrMetaEnd, $this->arrValues[$value] ? 'checked' : '' ,$strTemplContent);
			}else{
				$strTemplContent = str_replace($strBeginTag . strtoupper($value) . cstrMetaEnd, $this->arrValues[$value] ,$strTemplContent);
			}
		}
	}
	function readFromForm(){
		//Načtení hodnot z formuláře
		global $_POST;
		foreach ($this->arrUsedKeys as $value){
			$this->arrValues[$value] = array_key_exists(strtolower($value), $_POST) ? htmlChars($_POST[strtolower($value)]) : '';
		}
	}
	function checkForm(&$strTemplContent){
		foreach ($this->arrUsedKeys as $value){
			if ($this->arrRequired[$value] && $value!='PRIVATE' && !$this->arrValues[$value]) {	//Požadované pole je prázdné
				dispayUserErrorMessage(loc('c_objIfREQUIRED'), $strTemplContent, array(cstrMetaBeginAdvice . loc('c_objIfFieldDesc') . cstrMetaEnd => 
 $this->arrDescs[$value]));
				return false;
			}
		}
		//Ještě zkontrolujeme e-mail, pokud je používaným polem a někde v předloze existuje hláška ošetřující neplatný email
		if (in_array(loc('c_objEMAIL'), $this->arrUsedKeys) && $this->arrValues[loc('c_objEMAIL')] && strpos($strTemplContent, cstrMetaBeginAlert . 
 loc('c_objIfWrongEmail'))!==false) {
			//e-mailové pole není prázdné, tak jej zkontrolujeme
			if (!ereg("^.+@.+\\..+$", $this->arrValues[loc('c_objEMAIL')])){
				dispayUserErrorMessage(loc('c_objIfWrongEmail'), $strTemplContent);
				return false;
			}
		}
		return true;
	}
	function updateDefValuesInDB($intUserID){
		//Updatne všechny updatovatelné (tj. WTD_USER) parametry v XANONYMOUS, vč. prázdných hodnot
		foreach ($this->arrUsedKeys as $value){
			if (in_array($value, $this->arrUserItems)) {	//WTD_USER?
				xUpdateUserParameter($intUserID, $value, 0, $this->arrValues[$value]);
			}
		}
	}
	function getValue($strParamName, $intMaxLength=65536){
		global $db;
		return in_array($strParamName, $this->arrUsedKeys) ? substr($this->arrValues[$strParamName], 0, $intMaxLength): '';
	}
	function getValueForDb($strParamName, $intMaxLength=65536){
		global $db;
		return in_array($strParamName, $this->arrUsedKeys) ? substr($db->check_quotes($this->arrValues[$strParamName]), 0, $intMaxLength): '';
	}
	function getIntValue($strParamName){
		global $db;
		return in_array($strParamName, $this->arrUsedKeys) ? intval(strlen($this->arrValues[$strParamName])>0): 0;
	}
}
?>

Klíčová slova a parametry URL

Parametry z URL

Každý skript veřejné části musí správně pracovat s těmito parametry:

  • lid – ID jazyka pro zvolení nastavení pro vybraný jazyk
  • locale – zkratka jazyka pro zvolení nastavení pro vybraný jazyk (jako alternativa k předchozímu bodu)
  • tmplid – ID předlohy z databáze předloh (pokud je uvedeno, vybírá se předloha přednostně podle tohoto ID)

Dále pokud stránka obsahuje seznam, který lze stránkovat, parametr s číslem stránky by se měl jmenovat pg. Názvy jakýchkoliv dalších parametrů by měly vycházet z angličtiny.

Klíčová slova modulů

Pro klíčová slova modulů platí následující konvence:

  1. Klíčová slova WTD_F se používají pouze pokud se jedná o stejný význam jako ve WebToDate, tedy o práci s databází zpráv.
  2. Klíčová slova WTD_NAVIG (tedy např. <!--WTD_NAVIG(URL)-->) se používají pro stránkovací navigační lišty ve všech modulech.
  3. Klíčová slova specifická pro daný modul by se nejlépe měla shodovat s názvem adresáře pro daný modul (tedy například <!--WTD_DIARY(NAME)-->). Všechny "parametrické" části klíčových slov (v tomto případě "NAME") by měly být definované jako konstanty v _localization_inc.php, aby je bylo eventuálně možné měnit.
  4. Pro možné hlášky, které se nacházejí v předloze a které se zobrazí pokud dojde k dané události se zásadně používá slovo WTD_IF.
  5. Seznam klíčových slov, které lze používat ve stylech a předlohách daného druhu zobrazení, je nejdůležitější součástí dokumentace. Klíčová slova musí být podrobně uvedena ve všech druzích nápovědy.