Tworzenie Aplikacji Internetowych

advertisement
Tworzenie Aplikacji Internetowych
dr Wojciech M. Gańcza
6
Dostęp do danych
Dane możemy zapisywać lub
odczytywać poleceniami SQL
 Niestety różne serwery baz danych
mają różne wymagania co do zapytań
 Baza może ulegać zmianom
 Nie będziemy ciągle modyfikowali
wszystkich miejsc w których
korzystamy z danych
 Warto umieścić zapytania w jednym
miejscu.

Konstrukcja bazy
Bazę można przygotować w
dowolnym narzędziu do edycji danych
 Można ją odzyskiwać z backupu
 Ale co jeśli zmieni się struktura?
 Lepiej przygotować program który
wypełni bazę danymi!
 Najlepiej jeśli będzie to funkcja w tej
samej klasie do konstrukcja bazy

DatabaseConstructor
class DatabaseConstructor
{
var $database;
var $dbcreator;
var $creator;
var $config;
function DatabaseConstructor()
{
$this->database = new DatabaseAccess();
$this->dbcreator = new DBDatabaseCreator(&$this->database);
$this->config = new DatabaseConfiguration();
$this->creator = new DBTableCreator(&$this->database);
}

Na początek przygotujemy sobie
warsztat pracy
Przydatne informacje
Warto pamiętać stan bazy danych
 Oczywiście najprościej – w samej
bazie danych
 Dodajmy tablicę w której będzie
przechowywany numer wersji bazy
oraz opis wersji (informacje o tym
jakie dane znajdują się w bazie)
 Tak więc funkcja konstruująca bazę
powinna zawierać:

Tworzymy bazę
$this->dbcreator->createDatabase(
$this->config->database_name);
$this->creator->startTable("Version");
$this->creator->addField("VerVersion",
"name");
$this->creator->addField("VerState",
"name");
$this->creator->createTable();
this->insert("insert into Version
(VerVersion, VerState) values ('UUK
0.1.0', 'Empty');");
Status bazy

Przed jakimikolwiek operacjami na
bazie – warto sprawdzić jej stan:
function state()
{
$data = $this->database->query(
"select VerState from Version;");
if ($data->eof())
return "Nonexisting";
else
{
$data = $data->get();
return $data[0];
}
}
Insert
Dodając rekordy warto wiedzieć jaki
identyfikator baza nadała nowemu
wpisowi
 Można to sprawdzić zadając
odpowiednie zapytanie
 Warto takie zapytanie dodać do
metody która wstawia dane do bazy
 Napiszmy metodę ‘insert’:

Insert …
function insert($query)
{
$this->database->query($query);
$set = $this->database->query(
"select LAST_INSERT_ID();");
$set = $set->get();
return $set[0];
}

Funkcja wykonuje zapytanie i zwraca nadany
identyfikator
Dodawanie danych

Do dodawania danych warto
przygotować sobie funkcje
function addSubject($subject)
{
$this->insert("insert into
Subjects (SubjectsName)
values ('$subject');" );
}
Tworzymy tabelę i dane
Tabele i dane testowe powinny być
tworzone w jednej klasie
 Warto przygotować różne metody do

Tworzenia pustej bazy – zawierającej
same struktury danych
 Wypełniania danymi testowymi pustej
bazy (warto sprawdzać status  )
 Wypełniania danymi niezbędnymi do
pracy z pustą bazą

Wypełnianie danymi
W relacyjnej bazie danych dane mogą
od siebie zależeć
 Jeśli chcemy umieścić referencje – to
musimy ją znać
 Najprościej zapamiętać identyfikatory
w tablicach
 I używać ich gdy są potrzebne przy
wywoływaniu funkcji dodających
elementy do kolejnych tabel

Wypełnianie danymi …
$subjects = array();
$subjects["angielski"] =
$this->addSubject('Język
angielski');
$subjects["biologia"] =
$this->addSubject('Biologia');
$subjects["chemia"] =
$this->addSubject('Chemia');
$subjects["fizyka"] =
$this->addSubject('Fizyka');
Wypełnianie danymi …
$books = array();
$books[0] = $this->addBook(
'Język polski. Między tekstami.
Część 1. Podręcznik. Początki.
Średniowiecze (echa
współczesne)',
$types["podrecznik"],
$publishers["gwo"] );
$this->addBookSubject($books[0],
$subjects["polski"]);
$this->addBookAuthor($books[0],
$authors["mackiewicz"]);
Wypełnianie danymi …
Metody wypełniające danym mogą
być dość długie (paręset linii)
 Nie muszą być eleganckie – są pisane
na potrzeby testowania programu
 A jeśli o testowaniu mowa – to warto
przetestować czy wszystkie dane
poprawnie dodały się do bazy
 To ważne – bo inne testy będą
zakładały odpowiednią zawartość
bazy

Test danych testowych
function test_000100_TestingTestdatabase(&$tester)
{
$tester->message("Testing test database");
$constructor = new DatabaseConstructor();
$constructor->dropDatabase();
$constructor->createDatabase();
$constructor->fillWithTestData();
$tester->test("Testing count of records in Authors
table", countRowsOfTable(&$database, "Authors"),
80);
$tester->test("Testing count of records in Books
table", countRowsOfTable(&$database, "Books"), 88);
$tester->test("Testing count of records in BooksAuthors
relation table", countRowsOfTable(&$database,
"BooksAuthors"), 217);

I już wiemy czy wszystkie dane się dodały
Dostęp do danych
Dostęp do danych zorganizujemy w
postaci pojedynczej klasy
 Metody będą zwracały źródła danych
 W metodach będziemy się odwoływali
do bazy budując odpowiednie
zapytania
 Centralizacja wszystkich zapytań
bardzo ułatwia późniejsze
modyfikacje struktury bazy (nie
mamy oporów przed zmianami)

Dostęp do danych …
Dostęp rozpoczniemy od odczytu listy
książek potrzebnych wybranemu
użytkownikowi.
 Jako parametr – musimy podać
użytkownika – pozostałe parametry są
w bazie
 Dostęp do danych nie jest prosty –
przy bazie zdefiniowanej tak jak to
pokazywaliśmy – musimy utworzyć
zapytanie ze złączeniami

Lista książek
function getBooksNeededByUser($userId)
{
return $this->database->query(
"select distinct
Books.BooksID, TypesName,
BchSubjects, BokTitle,
BchAuthors, PublishersName
from
UsersGrups inner join
BooksGrups on
UsersGrups.GrupsID=BooksGrups.GrupsID
inner join
Books on BooksGrups.BooksID=Books.BooksID
left outer join
BooksCache on Books.BooksID=BookId
left outer join
Publishers on PublishersID = PublisherID
left outer join
Types on TypesID = TypeID
where UsersID=$userId
order by BokTitle;");
}
Lista książek …
Wyświetlenie takiej listy jest
skomplikowane a nie mamy jeszcze
informacji czy książka jest w
posiadaniu użytkownika oraz czy jest
przez niego sprzedawana
 Ale wszystko po kolei…
 Najpierw test!
 Test jest bardzo prosty – wynik
działania tej metody dla wybranego
parametry – porównujemy ze
wzorcem

Test listy książek

Możemy utworzyć nową funkcję
testową lub dodać nowy test do
istniejącego testu bazy testowej
$tester->testRecordset(
"Testing all books in database",
$dataAccess->getBooksNeededByUser(1),
341760974);

Możemy test wykonać także dla
innych użytkowników
Panel - Widok danych
Panel naszego programu będzie
zawierał listę książek
 Mogą to być różne listy

Lista wszystkich książek (posiadanych i
potrzebnych)
 Lista książek które trzeba kupić
 Listę książek które można sprzedać


Panel powinien wyświetlać dane z
podanego źródła danych
Lista książek

Wystarcz podać obiektowi klasy
GridRenderer źródło danych i mamy
gotową stronę
$output = new Output();
$page = new PageFrame();
$panel = new BookPanel(
/* definicja tabeli */,
/* dane – na przykład userId */);
$page->setPanel(&$panel);
$page->render(&$output);
BookPanel
class BookPanel
{
function render(&$output)
{
$db = new DatabaseAccess();
$data = new DataSource(&$db);
$grid = new GridBuilder("
Tytuł:LB3|
Autor:CN3:60|
Wydawnictwo:CN1:160|
Przedmiot:LN1:250");
$grid->renderGrid(&$output,
$data->getBooksNeededByUser(1));
}
}
Operacje na źródłach danych
Dane ze źródła są mapowane do pola
tabeli w stosunku 1:1
 A tymczasem często chcemy umieścić
kilka informacji w jednym polu tabeli
– wyróżniając poszczególne części
różnym krojem pisma
 Czy można osiągnąć taki efekt bez
modyfikacji klasy tworzącej kod
tabeli?

Operacje na źródłach danych
Użyjemy „dekoratora” – klasy która
ma taki sam interface jak oryginalne
źródło danych i przeformatowuje
dane ze źródła podanego jako
parametr
 Przygotujmy taki dekorator który
umieści wszystkie informacje na
temat ksiązki w jednej kolumnie
 Pozostałe kolumny będą nam
potrzebne do określenia statusu
ksiązki

Składanie kolumn
class Concatenator
{
var $src;
function Concatenator(&$src)
{
$this->src = $src;
}
function eof()
{
return $src->eof();
}
Składanie kolumn …
function get()
{
$arr = $src->get();
$res = array();
$res[] = „<b>” . $arr[0] .
„</b><i>” . $arr[1] .
„</i><u>” . $arr[2] .
„</u>” . $arr[3];
for ($i=4; $i<count($arr); ++$i)
{
$res[] = $arr[i];
};
}
Składanie kolumn…
Dobrze jest przygotować sobie kasę
przeformatowująca dane w bardziej
elastycznej postaci
 Przekażemy informacje o tym które
kolumny powinny być łączone by
utworzyć kolumnę wynikową
 Jeśli określimy tak informacje o
wszystkich kolumnach – to możemy
je także przetasowywać

Formatowanie
Dobrze sobie przygotować klasy
bazowe do formatowania
 Klasy takie mogą wstępnie
interpretować przekazane informacje
dotyczące kolumn
 Wszystkie operacje będą miały taki
sam interfejs
 Klasy formatujące będą wtedy bardzo
proste
 Ale o tym – za tydzień.

W następnym odcinku
Co zrobić gdy zapytania są zbyt
skomplikowane.
 Formatowanie danych ze źródła „w
locie”
 Operacje na źródłach danych

Download