Współczesne witryny internetowe tworzone w PHP powstają w oparciu o języki: XHTML, CSS, PHP, Smarty, SQL, którym niekiedy towarzyszą JavaScript oraz DOM. Jakie argumenty przemawiają za tak dużym stopniem złożoności, wydawałoby się, prostego zadania? W artykule opiszę rolę każdego z języków oraz przedstawię przykładową aplikację przygotowaną w taki sposób, by wprowadzanie modyfikacji wymagało jak najmniej pracy.Aplikacje internetowe – Stosowane języki
Współczesne witryny internetowe tworzone w PHP powstają w oparciu o języki:
XHTML, CSS, PHP, Smarty, SQL, którym niekiedy towarzyszą JavaScript oraz DOM.
Jakie argumenty przemawiają za tak dużym stopniem złożoności, wydawałoby się,
prostego zadania? W artykule opiszę rolę każdego z języków oraz przedstawię
przykładową aplikację przygotowaną w taki sposób, by wprowadzanie modyfikacji
wymagało jak najmniej pracy.
XHTML
Język XHTML służy do opisania struktury dokumentu WWW. W chwili obecnej nie ma żadnego zamiennika dla tego języka, jest to
więc element absolutnie konieczny każdej witryny internetowej. XHTML wyparł swojego poprzednika – HTML. Pomimo tego, że większa część internetu jest wykonana w języku HTML
oraz faktu, że języki HTML i XHTML są niemal tożsame, w nowych projektach trzymać się języka XHTML.
W odniesieniu do języka XHTML należy zwrócić
uwagę na:
- pracę w trybie zgodności ze standardami,
- poprawność,
- rezygnację z układów tabelkowych na rzecz układów tworzonych przy użyciu elementów div i stylów CSS,
- semantyczność.
Pracę w trybie zgodności ze standardami wymuszamy stosując odpowiednią deklarację
DOCTYPE. Deklaracja języka XHTML 1.0 stict:
zapewnia tryb zgodności ze standardami.
Poprawność dokumentu należy kontrolować od
samego początku pracy nad projektem, wykorzystując:
- HTML Validator (wtyczkę programu Firefox),
- W3C Validator (walidator dostępny pod adresem
http://validator.w3c.org), - interpretację dokumentów XML przez przeglądarkę Firefox (wymuszenie typu application/xhmtl+xml).
Jeśli witryna jest tworzona w PHP, to walidację
trzecim sposobem wykonasz, dodając do kodu PHP
wywołanie:
header(\'Content-Type: application/xhtml+xml; charset=utf-8\');
Wówczas jakiekolwiek błędy w kodzie XHTML
spowodują, że Firefox wyświetli – zamiast strony
WWW – jedynie komunikat o błędzie.
Kolejnym wymaganiem jest rezygnacja z układów tabelkowych. Nowoczesne witryny są tworzone
w oparciu o elementy div i arkusze stylów CSS. Nie ma od tego odwrotu. Zdarzają się sytuacje,
w których można mieć wątpliwości: czy prezentowane dane należy traktować jako tabelaryczne.
Przykładami powodów takich dylematów są:
- zestawienie: zdjęcie samochodu, podpis i opis
prezentowane jedno po drugim, - lista ofert: nazwa produktu, zdjęcie, opis.
Nie ma jednak wątpliwości co do tego, że
wykonywanie menu w postaci tabelki jednowierszowej czy jednokolumnowej jest błędem
(przynajmniej z punktu widzenia zgodności strony ze standardami). Menu należy wykonywać w postaci
list ul bądź ol. Zaletą takiego rozwiązania – oprócz minimalizacji kodu XHTML – jest także to,
że przeglądarka może wyznaczyć liczbę elementów menu. Ma to znaczenie w przypadku przeglądarek
czytających witryny internetowe, z których korzystają osoby niewidome oraz niedowidzące.
Ostatnim z wymienionych wymagań jest
semantyczność kodu XHTML. Semantyczność kodu XHTML oznacza, że powinien on odzwierciedlać strukturę informacji na witrynie WWW, a nazwy identyfikatorów i klas powinny informować o roli elementu, a nie o jego formacie. Pierwszym etapem osiągnięcia semantyczności jest rezygnacja z układów tabelkowych na rzecz divów, stylów CSS oraz menu w postaci list.
Dodatkowo, tytuły i podtytuły różnych rodzajów wykonujemy, stosując
nagłówki h1, …, h6. Należy zwracać uwagę na nadmiarowość kodu, zarówno jeśli chodzi
o nadawanie zbyt dużej liczby identyfikatorów id i klas class, jak i o liczbę elementów div czy span.
Głównym narzędziem, jakie stosuję do minimalizacji liczby klas i identyfikatorów, są selektory typu
potomek w arkuszach stylów. Polega to na tym, że jeśli w kodzie XHTML występuje element
:
Lorem ipsum...
Dolor sit amet...
to style elementów zawartych wewnątrz sekcji {html}
{/html} definiuję bez użycia
klas czy identyfikatorów. Na przykład ustalenie formatu akapitów i wyróżnienia można osiągnąć
selektorami:
#menu p {
...
}
#menu p em {
...
}
CSS
Język CSS służy do zdefiniowania prezentacyjnych właściwości dokumentu XHTML. W chwili
obecnej nie ma alternatywy dla języka CSS, jest to zatem element konieczny.
Pracując w języku CSS,
należy zwrócić uwagę na:
- pracę w trybie standardów,
- wygląd witryny,
- quirksy, hacki i łatki dla wybranych starszych
przeglądarek (np. IE5),
- elastyczność i kuloodporność witryny,
- wygląd dokumentów przy wyłączonych stylach,
- wygląd dokumentu przy wyłączonych obrazkach.
Praca w trybie standardów w dokumencie CSS wynika ze stosowanego typu dokumentu.
Deklaracja DOCTYPE języka XHTML 1.0 strict powoduje,że style CSS będą interpretowane w trybie standardów.
Oczywiście głównym zadaniem języka CSS jest modyfikacja wyglądu witryny. Należy zatem
przeprowadzić testy wyglądu witryny w kilku przeglądarkach, dla których witryna została przygotowana.
Zestawem minimum są nowe wersje trzech najpopularniejszych obecnie przeglądarek, czyli IE, Firefox i Opera.
Jeśli zależy ci na wsparciu starszych przeglądarek,
np. IE5, możesz wykorzystać rozwiązania dedykowane dla poszczególnych aplikacji, dzięki
wykorzystaniu różnych trików, hacków i sztuczek. Najpopularniejszą sztuczką są rozwiązania nazywane
Box Model Hack, przeznaczone dla przeglądarki IE5. Ja w ich miejsce wolę stosować komentarze:
W każdym razie: najpierw przygotowuję witrynę dla nowych przeglądarek, a potem staram
się różnymi metodami zapewnić, by witryna była czytelna w IE5. Nigdy na odwrót!
Elastyczność i kuloodporność witryny WWW to pojęcia doskonale opisane w książce \”Kuloodporne
strony internetowe\” Dana Cederholma wydanej przez wydawnictwo Helion w 2006 roku.
Pojęcia te należy wiązać ze:
- zmianą wielkości czcionki (opcja Widok > Rozmiar
tekstu w przeglądarkach IE oraz Firefox),
- zmianą ilości tekstu w wybranym elemencie XHTML.
Po pierwsze, witryna powinna umożliwiać zmianę wielkości tekstu. Zatem nie należy stosować
jednostek px czy pt:
font-size : 12pt;
font-size : 10px;
gdyż jednostki te wyłączają możliwość skalowania
tekstu w przeglądarce IE.
Dostosowanie układu witryny WWW do zmiany ilości tekstu w wybranych elementach XHTML ma
na celu ułatwienie modyfikacji witryny. Witryna powinna być tak zaprojektowana, by wymiana
opcji menu:
o nas
na nieco dłuższą:
nasza firma
nie zburzyła układu.
Wreszcie ostatnimi testami, jakie należy wykonać, jest sprawdzenie wyglądu witryny przy
wyłączonych stylach CSS oraz przy wyłączonym pobieraniu obrazków. Witryna powinna w obydwu
sytuacjach być czytelna.
JavaScript i DOM
JavaScript jest językiem, który umożliwia oprogramowanie zachowania witryny WWW
w przeglądarce klienta. Kod JavaScript jest zapisany w dokumencie XHTML (lub w osobnym pliku
o rozszerzeniu .js) i jest pobierany przez przeglądarkę
z serwera WWW wraz z kodem XHMTL oraz CSS. Po pobraniu, przeglądarka wykonuje
kod JavaScript. Innymi słowy skrypty JavaScript są wykonywane przez przeglądarkę, a nie przez
serwer, co jest określane mianem wykonywania po stronie klienta.
Elementy XHTML posiadają zdarzenia: onchange,
onclick, ondblclick, onfocus, onkeydown, onkeypress, onkeyup, onload, onmousedown,
onmousemove, onmouseout, onmouseover, onmouseup, onreset, onselect, onsubmit, onunload.
Poprzez przypisanie do zdarzeń kodu Java-Script:
możemy powodować wykonanie różnych akcji przez przeglądarkę. Powyższy kod powoduje
włączenie drukowania bieżącego dokumentu po kliknięciu obrazu.
JavaScript jest powszechnie stosowany do:
- wstępnej walidacji formularzy,
- wykonywania rozwijanego menu
- oraz do wykonywania efektu rollover (czyli
wymiany obrazów po wskazaniu opcji menu
myszką).
Moim zdaniem jedynie wstępną walidację formularzy należy uznać za konieczną. W przypadku
witryny niezawierającej formularzy JavaScript jest dodatkiem, który może zostać wyeliminowany.
Stosując skrypty JavaScript warto wiedzieć, że język ten został poddany procesowi standaryzacji.
Wynikiem standaryzacji jest język ECMAScript, opisany w specyfikacji ECMAScript Language
Specification (ECMA 262).
Dokument XHTML wyświetlany przez przeglądarkę jest dostępny w języku JavaScript w postaci
interfejsu DOM (ang. Document Object Model). W ramach tego interfejsu możemy uzyskać dostęp
do dowolnego elementu XHTML zawartego w dokumencie i dynamicznie modyfikować jego zawartość
czy styl.
Na przykład dostęp do elementu div o identyfikatorze menu:
...
uzyskamy, wywołując funkcję getElementBy-Id():
var tmp = document.getElementBy-Id(\"menu\");
Tak utworzona zmienna tmp jest interfejsem do elementu div wyświetlanego na stronie. Modyfikując
jej właściwości:
tmp.style.width = 300;
zmienimy dynamicznie wygląd dokumentu. Szczegółowy opis atrybutów dostępnych w modelu
DOM jest zawarty w specyfikacji Document Object Model (DOM) Level 2 Style Specyfication.
PHP
Język PHP jest silnikiem napędowym aplikacji internetowej. Witryna WWW wyświetlana przez
przeglądarkę jest wynikiem wykonania pewnego skryptu PHP, który zazwyczaj:
- sprawdza poprawność danych pobranych od
użytkownika,
- ustala wybraną podstronę,
- pobiera potrzebne informacje z bazy danych,
- formatuje dane w postaci kodu XHTML i wysyła
gotową stronę do przeglądarki.
Skrypty PHP są uruchamiane na serwerze WWW. Do przeglądarki docierają wyłącznie wyniki
wykonania skryptu wydrukowane instrukcjami echo (i innymi metodami). Taki rodzaj działania jest
nazywany wykonaniem po stronie serwera.
Rozwiązaniami alternatywnymi w stosunku do PHP są JSP (Java Server Pages) oraz ASP (Active
Server Pages).
Smarty
Skrypty PHP, które drukują kod XHTML instrukcjami
echo, np.:
echo \"
\";
echo \" - opcja 1
\";
echo \" - opcja 2
\";
echo \"
\";
stają się bardzo niewygodne przy wprowadzaniu zmian i poprawek. W takiej sytuacji zmiana identyfikatora
elementu, czy zagnieżdżenia elementów XHTML, pociąga za sobą konieczność modyfikacji
kodu PHP.
Wymiana layoutu takiej witryny może stać się – bez względu na technikę wykonania
skórki, czyli nawet wówczas, gdy jest to kuloodporny i elastyczny kod XHTML/CSS wykonany
w oparciu o elementy div/ul i style CSS – koszmarem. Dlatego uważam, że wykorzystanie systemu
szablonów w aplikacji internetowej jest konieczne.
Nie upieram się przy żadnym rozwiązaniu, chociaż
osobiście stosuję szablony Smarty. Główną cechą skryptów wykorzystujących
Smarty, widoczną już na pierwszy rzut oka jest to, że nie pojawia się w nich instrukcja echo.
Za
drukowanie wyników jest odpowiedzialny szablon.
Cały kod XHTML/CSS powinien być przeniesiony albo do szablonu .tpl, albo do bazy danych. Skrypt
PHP nie powinien mieć (być może poza pewnymi specyficznymi przypadkami) do czynienia z kodem XHTML/CSS. Aplikacja PHP odpowiada za pobranie
danych z bazy oraz za przekazanie ich do szablonu. Struktura kodu XHTML wynika z szablonu .tpl oraz
rekordów bazy danych.
W takim rozwiązaniu modyfikacja skórki witryny przebiega w sposób zupełnie niezależny
od rozwoju aplikacji. Zmianę wyglądu osiągniemy modyfikując pliki szablonu .tpl oraz stylów CSS, bez
konieczności wprowadzania jakichkolwiek poprawek w kodzie PHP. To jest bardzo istotny argument
przemawiający za tym rozwiązaniem. Podkreślę jeszcze raz: uważam, że stosowanie systemu
szablonów jest konieczne w każdym niebanalnym skrypcie PHP.
SQL
Ostatnim z języków jest SQL: język do komunikacji z bazą danych. Możliwości relacyjnych
baz danych pracujących w systemie klient-serwer są tak duże, że właściwie wyparły one inne rozwiązania.
W chwili obecnej nawet aplikacje typu desktop, niewymagające wielodostępu, są pisane
z wykorzystaniem SQL-owych baz danych. Czym się przejawia wyższość SQL-owych
baz danych nad indywidualnymi rozwiązaniami dedykowanymi? Głównie przenośnością oraz
dostępnością gotowych rozwiązań.
Przygotowanie
dedykowanej metody przechowywania danych
wymaga między innymi:
- zdefiniowania formatu plików przechowujących
dane,
- zapewnienia kontroli wielodostępu do plików,
- oprogramowania funkcji zapisujących i odczytujących dane.
Wykorzystując SQL i jakikolwiek serwer baz danych (MySQL, Postgress, Oracle, SQLite), pracujemy
na abstrakcyjnym poziomie definiowanym przez język SQL i nie musimy się martwić o oprogramowanie
dostępu do plików, zapewnienie synchronizacji i blokowania czy format danych.
Język SQL pozwala skupić się na modelu bazy, a więc tabelach i relacjach. Wyszukiwanie,
sortowanie czy filtrowanie danych wykonujemy dołączając do zapytań klauzule WHERE czy ORDER
BY. Trudno o większe udogodnienia. O tym, czy baza danych jest konieczna, decyduje
moim zdaniem wielkość witryny WWW. Jeśli jest to prosta wizytówka firmy, zawierająca pięć podstron,
stronę taką szybciej zaimplementujemy, wykorzystując pliki. Jednak implementacje sklepu internetowego
w oparciu o pliki nie ma sensu.
Gdzie leży środek? Myślę, że to należy rozważać indywidualnie
w odniesieniu do konkretnego projektu biorąc pod uwagę nie tylko aktualne wymagania dotyczące
witryny, ale także plany na przyszłość. Jeśli chodzi o alternatywy, to język SQL należy
wiązać ściśle ze stosowanym oprogramowaniem serwera baz danych.
Każdy serwer baz danych, czy
to MySQL, czy Oracle, posiada własne rozszerzenia zapytań SQL niedostępne w innych systemach.
Trzon języka SQL, zdefiniowany w specyfikacji SQL92, pozostaje ten sam, jednak szczegóły różnią
się na tyle, że zapytania SQL zazwyczaj będą wymagały modyfikacji podczas wymiany oprogramowania
serwera baz danych.
Innymi słowy, jeśli chodzi o język SQL, mamy do czynienia z kilkoma dialektami. W odniesieniu do nich wszystkich stosuje się wspólną nazwę SQL.
Wybór konkretnego dialektu wynika z narzuconego (przez firmę hostingową czy pracodawcę) oprogramowania
baz danych.
Przykład: \”Układy cyfrowe – zbiór zadań\”
Jako przykład ilustrujący wykorzystanie wymienionych
języków omówię aplikację pt. \”Układy cyfrowe – zbiór zadań\”. Aplikacja ta jest dostępna
w internecie pod adresem http://www.gajdaw.pl/uc/.
Witryna od strony funkcjonalnej
Witryna Układy cyfrowe zawiera na stronie
głównej informacje o zmianach zawartości.W chwili uruchomienia umieściłem tam jeden wpis
opatrzony datą 8 listopada 2006 r.
Menu główne (rysunek 1) ma strukturę dwupoziomową. Opcjami głównymi są \”o stronie\”,
\”adresy\”, \”pobierz\” o następujących podopcjach:
- o stronie
- co nowego
- dla kogo
- po co
- copyright
- uwaga
- bibliografia
- mapa
- adresy
- elektronika
- układy cyfrowe
- sklepy z elementami
- pobierz
- układy cyfrowe
- reprezentacja danych
- inne
Menu główne nie posiada żadnych opcji opisujących pozycje poziomu pierwszego (czyli \”o stronie\”, \”adresy\” czy \”pobierz\”). Po wybraniu
opcji \”o stronie\” otwierana jest pierwsza podopcja (czyli \”co nowego\”). Po wybraniu opcji \”adresy\”
wybierana jest pozycja pierwsza (czyli \”elektronika\”).Zaś po wybraniu opcji \”pobierz\” wybierana
jest pozycja \”układy cyfrowe\”.
Drugie menu dostępne na stronie, zawiera opcje:
- zadania
- urządzenia
- 74xx
Jest to również menu dwupoziomowe i podobnie jak menu główne nie zawiera opisu opcji
pierwszego poziomu. Zatem wybranie opcji \”zadania\” przenosi nas do jej pierwszej podopcji (czyli
\”podstawy\”). Wybranie opcji \”urządzenia\” przenosi do podopcji \”wskaźnik\”, zaś opcja \”74xx\” przenosi
do podopcji \”7400\”.
Opcja \”zadania\” jest podzielonym na rozdziały zbiorem zadań. Podopcjami są rozdziały:
- podstawy
- projektowanie bramek
- układy o zadanym stanie wejść
- dodawanie liczb binarnych
- …
W ramach każdego rozdziału dostępna jest pewna liczba zadań. Po wybraniu rozdziału,
zadania w nim zawarte są widoczne – w skróconej postaci – w postaci listy.
Numer zadania jest hiperłączem do strony prezentującej jego pełną treść wraz ze wszystkimi
ilustracjami.
Opcja \”urządzenia\” jest również dwupoziomowa. Menu drugiego poziomu zawiera w tym przypadku
zestawienie wszystkich narzędzi i urządzeń dostępnych w programie Multimedia Logic:
- wskaźnik
- drut
- połączenie
- bramka and
- bramka or
- …
Po wybraniu opcji \”urządzenia\” ujrzymy opis pierwszego z narzędzi: wskaźnika do wskazywania
obiektów.
Natomiast podopcjami ostatniej z opcji \”74xx\” są:
- 7400
- 7402
- 7404
- 7408
- 7432
- 7486
Podopcją domyślną jest opcja \”7400\”. Każda z opcji zawiera rysunek ilustrujący
strukturę wewnętrznych połączeń jednego z układów scalonych serii 74.
Dane, których będzie przybywać
Witryna jest wykonana w taki sposób, aby
dodawanie kolejnych informacji nie wymagało żadnych zmian w kodzie aplikacji.
Elementami witryny,
które mogą się zmieniać, są:
- liczba opcje menu głównego,
- liczba podopcji każdej z opcji menu głównego,
- zawartość każdej z opcji menu głównego,
- liczba rozdziałów w zbiorze zadań,
- liczba zadań w każdym rozdziale,
- treść każdego zadania,
- liczba układów scalonych 74xx.
Wszystkie dane zawarte na witrynie pochodzą
z bazy danych.
W szczególności:
- menu główne
- opcje menu głównego powstają na podstawie
zawartości tabeli topcjamenu,
- podopcje menu głównego powstają na podstawie
zawartości tabeli tpunkt,
- treść podopcji menu głównego pochodzi
z tabeli ttekst,
- zbiór zadań
- rozdziały zbioru zadań pochodzą z tabeli
trozdzial,
- treść zadań pochodzi z tabeli tzadanie,
- urządzenia
- urządzenia pochodzą z tabeli turzadzenie,
- układy 74
- układy 74 pochodzą z tabeli t74,
- ponadto
- wszystkie obrazy zawarte na stronie (oprócz
trzech ikon) są zawarte w tabeli timage,
- pliki do pobrania (dział o stronie/do pobrania)
pochodzą z tabeli tzip,
- przyjazne URL-e stosowane w aplikacji pochodzą
z tabeli turl.
Podsumowując: wszystkie informacje zawarte na stronie WWW powstają na podstawie zawartości
bazy danych. Dodawanie nowych zadań, opcji menu czy układów 74 realizujemy poprzez wstawianie
rekordów do bazy danych. Nie wprowadzamy żadnych modyfikacji w kodzie aplikacji.
Implementacja dostępu do bazy danych
Cała komunikacja z bazą danych odbywa się za
pośrednictwem klas DBA (plik dba.class.php) oraz DBANextPrev (plik dbanextprev.class.php).
Klasa DBA implementuje podstawowy interfejs komunikacji z bazą danych, zaś metody klasy DBANextPrev
są wykorzystane do implementacji wskaźników następny/poprzedni do przewijania rekordów (tj.
strzałek w lewo i w prawo obok menu głównego).
Implementacja metody DBA opiera się o klasę
PEAR::DB. Wszystkie zapytania SQL są wydawane za pośrednictwem metod:
- getOne()
- getRow()
- getCol()
- getAll()
- query()
Wykorzystanie szablonów zapytań (w oryginalnej angielskiej dokumentacji nazywanych placeholders)
dodaje dodatkowy poziom zabezpieczeń aplikacji. Wszelkie dane przekazywane do zapytań
są neutralizowane przez klasę PEAR::DB właśnie dzięki placeholderom (czyli znakom ? występującym
w zapytaniach SQL).
Wydanie zapytania,
w którym pojawia się pochodząca z zewnątrz
zmienna $AId, przyjmuje postać:
$q = \'
SELECT
COUNT(timage_id)
FROM
timage
WHERE
timage_id = ?
\';
$t = array($AId);
$w = $this->Fdb->getOne($q, $t);
Zapytania SQL nie pojawiają się w kodzie aplikacji nigdzie poza klasami DBA oraz DBANextPrev.
Drugim etapem implementacji operacji bazodanowych jest przygotowanie zestawu aktywnych
rekordów.
Jako klasę bazową aktywnych rekordów
stosuję DBObject (plik dbobject.inc.php). Klasami
potomnymi są:
- Image z pliku image.class.php (klasa zapewniająca
dostęp do obrazów, tj. rekordów tabeli
timage),
- MyZip z pliku myzip.class.php (klasa zapewniająca
dostęp do plików do pobrania, tj. rekordów
tabeli tzip),
- OpcjaMenu z pliku opcjamenu.class.php (klasa
zapewniająca dostęp do opcji menu głównego,
tj. rekordów tabeli topcjamenu),
- Punkt z pliku punkt.class.php (klasa zapewniająca
dostęp do podopcji menu głównego, tj.
rekordów tabeli tpunkt),
- Rozdzial z pliku rozdzial.class.php (klasa zapewniająca
dostęp do rozdziałów zbioru zadań, tj.
rekordów tabeli trozdzial),
- Tekst z pliku tekst.class.php (klasa zapewniająca
dostęp do treści podopcji menu głównego, tj.
rekordów tabeli ttekst),
- U74 z pliku u74.class.php (klasa zapewniająca
dostęp do listy i opisu układów scalonych 74, tj.
rekordów tabeli t74),
- URL z pliku url.class.php (klasa zapewniająca
dostęp do przyjaznych URL-i, tj. rekordów tabeli
turl),
- Urzadzenie z pliku urzadzenie.class.php (klasa
zapewniająca dostęp do listy i opisu urządzeń
z opcji \”urządzenia\”, tj. rekordów tabeli turzadzenie),
- Zadanie z pliku zadanie.class.php (klasa zapewniająca
dostęp do treści zadań ze zbioru, tj.
rekordów tabeli tzadanie).
Wreszcie implementacja przewijania rekordów (czyli dodanie do interfejsu witryny strzałek:
następny/poprzedni) wymaga implementacji obiektów potomnych klasy DBWskaznik (plik dbwskaznik.inc.php). Wskaźnik następny/poprzedni jest dostępny na stronach:
- rozdziału zbioru zadań,
- konkretnego zadania,
- urządzenie,
- układu 74.
Należy więc zaimplementować klasy:
- DBRozdzialWskaznik (plik rozdzial-wskaznik.inc.
php),
- DBU74Wskaznik (plik u74-wskaznik.inc.php),
- DBUrzadzenieWskaznik (plik urzadzenie-wskaznik.
inc.php),
- DBZadanieWskaznik (plik zadanie-wskaznik.inc.
php).
Łącznie aplikacja \”Układy cyfrowe\” wykorzystuje 18 klas, których rolą jest uzyskanie dostępu do
danych zapisanych w bazie.
URL-e stosowane wewnętrznie w aplikacji
Aplikacja stosuje dwupoziomowe adresy URL.
Zmienna id (czyli $_GET[\’id\’] dołączana do zapytań jako index.php?id=XXX) identyfikuje
dział, zaś zmienna id2 (czyli $_GET[\’id2\’] dołączana do zapytań jako index.
php?id2=XXX) identyfikuje konkretny rekord w bazie danych.
Opcje menu głównego są identyfikowane przez id=12. Co ważne, w ten sposób identyfikujemy
podopcje wszystkich opcji:
o stronie/co nowego index.php?id=12&id2=1
o stronie/dla kogo index.php?id=12&id2=2
o stronie/po co index.php?id=12&id2=3
...
adresy/elektronika index.php?id=12&id2=8
adresy/układy cyfrowe index.php?id=12&id2=9
...
pobierz/układy cyfrowe index.php?id=12&id2=11
pobierz/reprezentacja danych index.php?id=12&id2=12
...
Rozdziały zbioru zadań identyfikujemy jako
id=2:
zadania/podstawy index.php?id=2&id2=1
zadania/projektowanie bramek index.php?id=2&id2=2
...
Treść zadań jest identyfikowana przez id=3:
zadanie 1.1 index.php?id=3&id2=1
zadanie 1.2 index.php?id=3&id2=2
...
Pozycje z działu urządzenia identyfikujemy jako id=6:
urządzenia/wskaźnik index.php?id=6&id2=1
urządzenia/drut index.php?id=6&id2=2
...
Układy scalone 74 są identyfikowane jako
id=8:
7xxx/7400 index.php?id=8&id2=1
7xxx/7402 index.php?id=8&id2=2
...
Pliki graficzne z tabeli timage identyfikujemy wartością id=4:
index.php?id=4&id2=1
index.php?id=4&id2=2
...
zaś pliki do pobrania (pochodzące z tabeli tzip) są adresowane przez id=13:
index.php?id=13&id2=1
index.php?id=13&id2=2
...
Implementacja silnika aplikacji
Silnik aplikacji jest zapisany w pliku index.php.
Jego rola polega na:
- sprawdzeniu poprawności danych pochodzących
od przeglądarki,
- ustaleniu wybranej podstrony witryny,
- pobraniu odpowiednich danych z bazy,
- przekazaniu danych do szablonu,
- przetworzeniu szablonu i wyświetleniu strony.
Walidacja zmiennych zawartych w tablicy
$_GET jest wykonana na podstawie tablicy $poprawne_
akcje:
$poprawne_akcje = array(2, 3, 4, 6, 8, 12, 13);
W tablicy tej zapisujemy wszystkie dopuszczone
wartości zmiennej id. Dalsza część walidacji
przebiega indywidualnie dla każdego przypadku.
Zazwyczaj sprawdzamy
- liczbę zmiennych w tablicy $_GET,
- obecność zmiennej id2,
- to, czy id2 jest poprawną liczbą całkowitą,
- oraz czy w bazie danych znajduje się rekord
o identyfikatorze identycznym jak wartość id2.
Oto jak przebiega walidacja w przypadku
podstron dotyczących układów 74:
if (
(count($_GET) === 2) && isset($_GET[\'id2\']) && str_ievpi($_GET[\'id2\']) && $db->DBA_poprawny_id_u74($_GET[\'id2\']))
{
$akcja = 8;
}
Gdy stwierdzimy, że wszystkie zmienne URL mają poprawne wartości, przechodzimy do pobierania
informacji z bazy danych. Wykorzystujemy do tego aktywne rekordy. Na przykład dane dotyczące
układu 74 pobierzemy, tworząc obiekt klasy U74 i wywołując metodę findID() aktywnego
rekordu:
$urzadzenie = new U74($db, SCRIPTNAME);
$urzadzenie->findID($_GET[\'id2\']);
Obiekt ten przekazujemy następnie do szablonu:
$s->assign(\'urzadzenie\', $urzadzenie);
Zanim przystąpimy do przetworzenia szablonu należy jeszcze przekazać szereg zmiennych pomocniczych,
m.in. menu, wskaźnik położenia czy
nazwę skryptu:
$s->assign(\'scriptName\', SCRIPTNAME);
$s->assign(\'akcja\', $akcja);
$s->assign(\'menu\', $menu);
$s->assign(\'polozenie\', $polozenie);
$s->assign(\'przyjaznyurl\', $przyjaznyurl);
Samo przetworzenie szablonu polega na pobraniu (metodą fetch()) szablonu zrenderowanego
przez Smarty:
$strona = $s->fetch(\'index.tpl\');
i wykonaniu translacji przyjaznych adresów URL:
$tmpFiltr = file_get_contents(\'filtr.log\');
$tmpFiltr= uncomment_and_trim($tmp-Filtr);
list($w, $c, $filtr) = string2VArray-
($tmpFiltr, \"\t\");
$strona = str_replace($filtr[0], $filtr[1], $strona);
echo $strona;
W tym miejscu możemy zmienić nagłówek HTTP, co spowoduje, że Firefox dokona walidacji
poprawności kodu XHTML:
header(\'Content-Type: application/xhtml+xml; charset=utf-8\');
Szablon witryny
Wygląd witryny stanowi osobną, integralną część aplikacji. Pracując nad skórką strony, nie
mamy do czynienia ze strukturą bazy danych, aktywnymi rekordami czy walidacją danych. Szablon
zapisany w pliku index.tpl jest oddzielony od problemów czysto programistycznych dotyczących
PHP czy SQL. W pliku .tpl mamy dostępne zmienne (zarówno skalarne, jak i tablice), na podstawie
których przygotowujemy ostateczny wygląd strony.
Najważniejszym trikiem do osiągnięcia niezależności
silnika aplikacji, bazy danych i szablonu jest stosowanie surowych danych. Do szablonu
przekazujemy – bez żadnych modyfikacji – wyniki zapytań SQL. Jeśli rekordy bazy danych zawierają
kod XHTML, to do szablonu trafi kod XHTML. Jeśli nie, to nie. W każdym razie: skrypt PHP nie ingeruje
w wyniki zwrócone przez metody klasy DBA. To jest klucz do produktywności.
Dodatkowo, pracę możemy sobie uprościć, stosując tablice asocjacyjne w wynikach zapytań SQL. W konstruktorze
klasy DBA wywołujemy metodę setFetch-Mode(), która spowoduje, że wyniki zwracane przez
metody klasy PEAR::DB będą tablicami asocjacyjnymi:
$this->Fdb->setFetchMode(DB_FETCHMODE_ASSOC);
Wtedy w szablonie .tpl stosujemy – w odniesieniu
do danych pobranych z bazy – notację \”z kropką\”, która jest zbliżona do rekordów w języku
Pascal czy struktur w C.
Jeśli zapytanie ma postać:
SELECT
trozdzial_id as id,
numerrozdzialu
tytul
FROM
trozdzial
ORDER BY
numerrozdzialu
to po przekazaniu do szablonu .tpl stosujemy iterację {section}, w której pola kolejnych
elementów tablicy są dostępne jako .id.numerrozdzialu
oraz .tytul:
{section name=i loop=$u}
{$u[i].id}
{$u[i].numerrozdzialu}
{$u[i].tytul}
{/section}
O tym warto pamiętać, gdyż w przeciwnym razie możemy dostać bardzo nieczytelne szablony.
Zwróć uwagę na alias: … as id
w zapytaniu SQL. Trik ten pozwala na osiągnięcie dowolnych indeksów w tablicy asocjacyjnej. Indeksy
w tablicy asocjacyjnej nie muszą się pokrywać z nazwami pól w tabelach (czasami, na przykład
wtedy, gdy dwie tabele zawierają kolumny o tej samej nazwie, jest to konieczne).
Zalety rozwiązania
Opisane rozwiązanie wprowadza podział aplikacji
na niezależne fragmenty. Głównymi częściami składowymi aplikacji są:
- dane (tj. zawartość witryny),
- skórka (tj. wygląd witryny)
- oraz silnik (czyli kod odpowiedzialny za wypełnianie
skórki danymi).
Podział taki pozwala na niezależne rozwijanie każdego fragmentu oraz izoluje zadania, które
mogą być wykonywane niezależnie przez różnych programistów (np. osoba odpowiedzialna za
XHTML/CSS nie musi wiedzieć zupełnie nic o bazie danych).
Podział na dane, skórkę oraz silnik wymaga wykorzystania wymienionych języków, przy czym
zupełnym minimum jest zestaw: XHTML/CSS/PHP/Smarty/SQL.
Dane
Dane witryny są zapisane w SQL-owej bazie danych. To wymaga znajomości języka SQL zarówno
do utworzenia bazy, jak i pobierania, wstawiania, modyfikowania czy usuwania rekordów.
Musimy przygotować pustą bazę danych, opracować metodę wypełniania bazy rekordami oraz
ustalić zapytania SQL odpowiedzialne za operacje na danych. Oczywiście do tego trzeba dobrze znać
język SQL.
Strukturę bazy danych ukrywamy przed całą aplikacją, implementując klasę dostępu DBA.
Dodatkowo warto zaimplementować aktywne rekordy, dzięki czemu dostęp do danych będzie się
sprowadzał do tworzenia obiektów i wywoływania ich metod.
Osoba odpowiedzialna za przygotowanie klasy DBA musi ustalić z osobą odpowiedzialną za oprogramowanie
silnika i aktywnych rekordów interfejs klasy DBA (czyli konieczne metody, ich parametry
i zwracane wyniki).
Skórka
Skórkę witryny opracowujemy w językach XHTML i CSS oraz ewentualnie JavaScript i DOM.
Wykorzystujemy szablon Smarty, dzięki czemu nie musimy znać kodu aplikacji.
Osoba odpowiedzialna za skórkę witryny musi ustalić z osobą opracowującą silnik zmienne przekazywane
do szablonu: ich nazwy oraz zawartość.
Silnik
Silnik aplikacji wykonujemy w PHP. Warto stosować metody obiektowe, chociażby do
implementacji aktywnych rekordów oraz funkcje biblioteczne. Zespół przygotowujący silnik musi
komunikować się z osobami odpowiedzialnymi za przygotowanie mechanizmu przechowywania
danych (czyli implementację klasy DBA oraz aktywnych rekordów), jak również z osobami odpowiedzialnymi
za skórkę (w celu ustalenia zmiennych przekazywanych do szablonu).
Zakończenie
Dla mnie osobiście największą rewolucją było wprowadzenie do aplikacji szablonów Smarty.
Odegrało to znacznie większą rolę niż wprowadzenie metod obiektowych, bazy danych czy obiektów
biblioteki PEAR. Usunięcie kodu XHTML/CSS na zewnątrz silnika aplikacji sprawiło, że wszystko
jest jasne i na swoim miejscu. Rozwiązanie wykorzystujące silnik taki, jak w pliku index.php,
posiada bowiem wspaniałą cechę: jego rozwój jest liniowy.
Dodanie nowej podstrony (czyli na
przykład w omawianej aplikacji \”Układy cyfrowe\” działu \”schematy\”, który będzie zawierał menu
kontekstowe, lub działu \”elementy elektroniczne\”, który będzie zawierał zestawienie podstawowych
elementów) sprowadza się do następujących zmian w silniku:
- dodanie jednego przypadku walidacji zmiennych URL,
- dodanie jednego przypadku wyboru stanu aplikacji
oraz dostosowania szablonu, w którym również
pojawi się jeden dodatkowy przypadek.
Tak więc można powiedzieć, że liczba wykonywanych zmian
jest 3n, gdzie n jest liczbą dodawanych podstron. Zauważ, że nie ma znaczenia charakter czy zawartość
podstrony! (Oczywiście należy odpowiednio zmodyfikować bazę danych. Jednakże ten krok
należy wykonać bez względu na metodę implementacji samej aplikacji).
Tak wykonana witryna będzie modyfikowalna w dwóch wymiarach bez żadnej ingerencji w kod
aplikacji:
- zawartość witryny zmieniamy dodając i usuwając
rekordy bazy danych,
- wygląd witryny zmieniamy, modyfikując skórkę.
Dodatkowo, modyfikację w trzecim wymiarze,
czyli dodawanie nowych podstron, usuwanie
i zmiana istniejących, wykonujemy:
- zmieniając strukturę bazy danych oraz dodając
metody klasy DBA,
- dodając przypadki w silniku aplikacji (złożoność: 3n).
I właśnie ta modyfikowalność witryny jest argumentem za wykorzystaniem wszystkich wymienionych
języków, czyli: XHTML, CSS, PHP, Smarty, SQL oraz JavaScript i DOM.