Tworzenie Aplikacji Internetowych
dr Wojciech M. Gańcza
2
Klasa GridRenderer
Klasa pisząca grid powinna
Przyjąć dane
Wyświetlić na wyjściu tabelę zawierającą
dane
Dane możemy przekazać w
konstruktorze
Albo przy wywołaniu metody render
Konstruktorowi zostawmy definicję
tabeli (nagłówki, formaty) – dane
będą przekazane do metody render
Klasa GridRenderer …
class GridRenderer
{
function GridRenderer()
{
}
function render(&$out,
&$data)
…
}
Klasa GridRenderer …
function render(&$out, &$data)
{
$out->out(”<table>”);
while(!$data->eof())
{
$out->out(”<tr>”);
$row = $data->get();
foreach ($field in $row)
{
$out->out(”<td>$field</td>”);
}
$out->out(”</tr>”);
}
$out->out(”</table>”);
}
Klasa DataSource
Interfejs klasy określony jest przez to
czego się od niej wymaga.
Można stworzyć interfejs który jest
prostszy – get może zwracać false
gdy nie ma danych
Wtedy kod korzystający ze żródła
danych musi być na taką sytuacje
uczulony
Ja wolę oddzielne metody (ale to
kwestia gustu)
Klasa DataSource …
class DataSource
{
function eof()
{
}
function get()
{
}
}
Przykładowe źródło danych
Do testów wyświetlania przyda nam
się jakiekolwiek źródło danych
Zauważmy – że dane w czele nie
muszą pochodzić z bazy czy pliku!
W przykładowym (testowym) źródle
możemy użyć wartości zaszytych na
sztywno w kodzie źródła
Ma to swoje zalety – widok przy
każdym uruchomieniu będzie
dokładnie taki sam (testy!)
Przykładowe źródło danych
class ExampleSource
{
var $row;
function ExampleSource()
{
$this->row = 0;
}
function eof()
{
return $this->row == 3;
}
Przykładowe źródło danych
function get()
{
switch ($this->row)
{
case 0:
return array(1, ”Pierwszy”);
case 1:
return array(2, ”Btopou”);
case 2:
return array(3, ”Tres”);
};
}
}
Kilka uwag
Aby dostać się do składowych i
metod– musimy ZAWSZE używać this
Jeśli tego nie zrobimy
Dla metod – dostaniemy informację o
tym, że taka funkcja (globalna) nie
istnieje (a jeśli istnieje – to zostanie
zawołana!)
Dla składowych – otrzymamy zmienną
globalna o takiej nazwie – jeśli taka
istnieje lub utworzymy zmienną lokalną
– nie będzie informacji o błędzie!!!
Podział na pliki
Na początek wszystkie klasy możemy
definiować w jednym pliku
Ale gdy program będzie się
komplikował
Trudno będzie znaleźć odpowiednią klasę
Co z pracą w kilka osób
Warto umieszczać po jednej klasie w
pliku (i nazywać pliki jak klasy)
Program w wielu plikach
Kod umieszczony w innych plikach
możemy włączać do naszej strony
używając funkcji
include(…);
require(…);
require_once(…);
To nie są dyrektywy preprocesora
tylko funkcje – można przekazywać
nazwy plików w zmiennych, albo
włączać warunkowo
Strona
W aplikacji, wiele stron ma podobna
konstrukcję.
Nagłówek HTML
Nagłówek aplikacji
Menu
Część robocza
Stopka
Zamknięcia znaczników strony
Warto przygotować sobie klasę która
je kapsułkuje
Klasa Page
class Page
{
var $body;
function setBody(&$body)
{
$this->body = &$body;
}
function render(&$out)
…
}
Klasa Page …
function render(&$out)
{
$out->out(”<html><head>”);
$out->out(”</head><body>”);
$this->body->render(&$out)
$out->out(”</body></html>”);
}
Ale jak podpiąć tu klasę rysującą grid z
danych
Budowa całej strony
Klasa tworząca grid potrzebuje przy
jego rysowaniu – drugiego parametru
Nie można więc wstawić obiektu typu
GridRenderer jako ciała strony
Co chyba wydaje się … dobre
Grid – nie jest ciałem strony – ale
może być jej elementem
Ciałem strony – powinien być Panel
Klasa Panel
class GridTestingPanel
{
function render(&$out)
{
$dat = new ExampleSource();
$grd = new GridRenderer();
$grd->render(&$out, &$dat);
}
}
Nareszcie pierwsza strona !
require_once(”Output.php”);
require_once(”Page.php”);
require_once(”GridRenderer.php”);
require_once(”ExampleSource.php”);
require_once(”ExampleSource.php”);
$out = new Output();
$page = new Page();
$panel = new GridTestingPanel();
$page->setBody(&$panel);
$page->render(&$out);
Po co to wszystko
Można prościej – pisząc po prostu kod
w HTML przeplatając poleceniami PHP
Szybciej otrzymujemy gotową stronę
Kod jest szybciej interpretowany
Nie robimy sobie bałaganu na dysku
Ale gdy aplikacja się rozrasta
Zmiany trzeba prowadzać w wielu
miejscach
Trudno te miejsca znaleźć
Po co to wszystko …
Dodanie elementu do wszystkich
stron – wymaga zmiany klasy Page
Zmiana metody pobierania danych –
wymaga użycia innego źródła
Zmiana widoku, dodanie
formatowania czy dodanie innych
wariantów wyświetlania (PDF?)
wymaga jedynie zmiany renderera
Łatwo można testować program
Testy
Testy są istotne
Testujemy zawsze cały kod
Testujemy każdą funkcjonalność
Testy nie powinny zajmować nam
zbyt wiele czasu
Potrzebujemy możliwości
automatycznego testowania aplikacji
Testy automatyczne
Testy automatyczne – to nic innego
jak funkcje.
Każda taka funkcja powinna
wyświetlić informacje o tym
Jaki test jest wykonywany
Czy się powiódł
Jeśli nie – to co się nie zgadza
Istnieje wiele środowisk testowych,
ale na nasze potrzeby napiszemy
własne
Tester
class Tester
{
var $passed;
var $failed;
var $out;
function Tester()
{
$this->passed = 0;
$this->falied = 0;
}
Tester
function render(&$out)
{
$this->out = &$out;
// tu wołamy wszystkie funkcje
// testowe przekazując im $this
// jako tester na którym testy są
// sprawdzane.
// funcje te mogą wołać metodę
// test która sprawdza warunek…
$out->out(”<p>Passed: ” . $this->passed);
$out->out(”<p>Failed: ” . $this->failed);
}
Tester - test
function test($label, $should, $is)
{
$this->out->out(”Testing $label”);
if ($should == $is)
{
$this->out->out(” … passed<br>”);
++$this->passed;
}
else
{
$this->out->out(” … FAILED (found ‘$is’
but should be ‘$should’)<br>”);
++$this->failed;
}
}
Jak uruchomić testy?
Tester – ma taki sam interfejs jak
Panel – można więc go użyć jako
ciało strony
Budując stronę testów możemy
wykorzystać klasę Page
Funkcje testowe warto umieszczać w
oddzielnych plikach
Ciało pierwszej funkcji testowej
możemy po prostu skopiować…
Test pierwszej strony
require_once(”Output.php”);
require_once(”Page.php”);
require_once(”GridRenderer.php”);
require_once(”ExampleSource.php”);
require_once(”ExampleSource.php”);
function TestOfFirstPage(&$tester)
{
$out = new TestingOutput();
$page = new Page();
$panel = new GridTestingPanel();
$page->setBody(&$panel);
$page->render(&$out);
$tester->test(”First page”, $out->getCRC(), 0);
}
Teraz wystarczy dodać wywołanie funnkcji do
testera
Rozbudowa testera
Przeszukiwanie katalogu z testami i
włączanie wszystkich znalezionych
plików.
Uruchamianie wszystkich funkcji
testowych (jakoś je trzeba wyróżnić)
Dodanie funkcji testujących konkretne
elementy które powtarzają się w
programie (źródeł danych, paneli, …)
Inne – w miarę potrzeb
W następnym odcinku
Jak dostać się do bazy danych
Elementy języka SQL
Konstruktor bazy
Dodawanie danych testowych
Źródło danych
I może uda się pokazać dane z bazy