tworzenie aplikacji internetowych
DESCRIPTION
Tworzenie Aplikacji Internetowych. 7. dr Wojciech M. Gańcza. Co z formatowaniem danych. Format poszczególnych kolumn można wymusić przy użyciu znacznika Można tak określić wszystko co można określić stylem, ale co na przykład z formatowaniem daty albo liczb - PowerPoint PPT PresentationTRANSCRIPT
Tworzenie Aplikacji Internetowychdr Wojciech M. Gańcza 7
Co z formatowaniem danych Format poszczególnych kolumn
można wymusić przy użyciu znacznika <col …>
Można tak określić wszystko co można określić stylem, ale co na przykład z formatowaniem daty albo liczb
Tu musimy uciec się do odpowiedniego formatowania danych
Formatowanie danych Umożliwienie formatowania na
poziomie tworzenia kodu tabeli – bardzo skomplikowałoby ten kod
Jakiekolwiek zmiany czy rozszerzenia – wymagałyby zmian w dość skomplikowanej klasie
Formatowanie na poziomie tworzenia źródła danych – ma dokładnie te same wady
A jakby tak wstawić coś pomiędzy…
Formatowanie danych …
Co można włożyć pomiędzy źródło danych a generowanie tabelki w html-u?
To coś musi mieć interfejs źródła danych, i ze źródła danych czerpać dane
Zauważmy, że nie musimy czytać wszystkich danych – możemy formatować dane ‘w locie’
Formatowanie danych … Formatowanie dotyczy zazwyczaj
pojedynczych kolumn, ale warto przygotować możliwość formatowania kilku kolumn pojedynczym obiektem
Zapamiętanie kolumn do przeformatowania warto przygotować we wspólnej dla wielu formaterów klasie bazowej
Definicję kolumn warto podać w jakiś wygodny sposób – na przykład w stringu z wybranym separatorem
Formaterclass FieldFormater{ var $fields; var $source;
function FieldFormater(&$source, $fieldList) { $this->fields = split($fieldList, ”|”); $this->source = &$source; }
function eof() { return $this->source->eof(); }
Formater … function get() { $rec = $this->source->get(); foreach($this->fields as $field) { $rec[$field] = $this->format( $rec[$field]) } return $ret; }
// Ta funkcja powinna być nadpisana function format($field) { return $field; }}
Formatowanie kwoty Przygotowanie przykładowego
formatera jest teraz dość proste Zbudujmy formater który liczbę
zapisze jako kwotę, wymuszając: Dwa miejsca po przecinku W części całkowitej – odstęp co trzy
pozycje Pisząc symbol waluty za wartością
Można przygotować też uniwersalny formater, ale na razie nie jest nam potrzebny.
Formatowanie kwoty
class MoneyFormater extends Formater
{
function MoneyFormater(&$source,
$fieldList)
{
$this->Formater(&$source,
$fieldList)
}
function format($field) ...
}
Metoda formatującafunction format($field){ $integral = (int)($field); $fraction = round(100*( $field - $integral)); $frac = ","; if ($fraction < 10) { $frac = ',0' . $fraction; } else { $frac = ',' . $fraction; }
Metoda formatująca … $str = (string)($integral); $len = strlen($str); $ret = ""; while ($len > 3) { $ret = ' ' . substr($str, $len-3, 3) . $ret; $len -= 3; } $ret = substr($str, 0, $len) . $ret; return $ret . $frac . " zł";}
Inny przykład Całą metryczkę ksiązki można
umieścić w jednym polu Informacje o książkach zawierają:
Tytuł ksiązki Autora Wydawnictwo Rodzaj ksiązki (podręcznik/atlas/
ćwiczenia) Warto tylko różnie je sformatować
tak by poszczególne pola się odróżniały
Inny przykład … Niestety – tym razem nasz
formater będzie mieszał pola, nie możemy więc skorzystać z bazowego formatera pól
Ale i tu warto przygotować klasę bazową
Musimy tylko zdecydować się na dwa separatory: Oddzielający pola wynikowego
rekordsetu ( na przykład ‘|’) Oddzielające łączone pola (na
przykład ‘+’)
MultiFormaterclass MultiFieldFormater
{
var $fields;
var $source;
function MultiFieldFormater(&$source, $fieldList)
{
$this->fields = split($fieldList, ”|”);
for ($i=0; $i<count($this->fields); ++$i)
{
$this->fields[$i] = split(
$this->fields[$i], ”+”);
}
$this->source = &$source;
}
MultiFormater … function get() { $rec = $this->source->get(); $ret = array(); for ($i=0; $i<count($this->fields); ++$i) { $ret[] = $this->format(
&$rec, $this->fields[$i]) } return $ret; }
// Ta funkcja powinna być nadpisana function format(&$record, $fieldArr) { ... }}
MultiFormater …
Teraz trzeba zdecydować jak będą łączone poszczególne pola
Propozycja:Tytuł; autor; Wydawca; Typ
Jeśli występuje mniej pól – nie są formaty nie są wykorzystane.
Nie przewidujemy łączenia większej liczby pól, ale można założyć że formaty będą stosowane cyklicznie
Metoda formatująca …function format(&$record, $fieldArr){ $begins = array("", "<i>", "<b>", "<u>"); $ends = array("; ", "; </i>", "; </b>", "; </u>"); $ret = "";
for ($i=0; $i<count($fieldArr); ++$i) { $ret .= $begins[$i] . $record[$fildArr[$i]] . $end[$i]; }
return $ret;}
Poprawki
Warto zadbać o to by zamiast stałych znaczników formatujących – użyć odwołań do styli
Średnik po ostatnim polu nie jest potrzebny – ale nie wiemy ile pól będzie użytych
Czy takie rozszerzenie funkcjonalności niesie a sobą komplikację kodu?
Może, ale nie musi :-)
Metoda formatująca …function format(&$record, $fieldArr){ $ret = $record[$fildArr[0]] ;
for ($i=1; $i<count($fieldArr); ++$i) { $ret .= ‘; <span class=„field‘ . $i . ‘">‘ . $record[$fildArr[$i]] . "</span>"; }
return $ret;}
Większa funkcjonalność – a kod znacznie prostszy!
Inne zastosowania
Tak przygotowany formater można także używać do zmiany kolejności pól lub do wybierania pól które są potrzebne.
Ale zapomnieliśmy o jednej ważnej rzeczy – o tym jak używać formaterów.
Może dlatego, że wydaje się to oczywiste :-)
Przykład użycia
Mamy metodę getBooksWithPrice w klase DataAccess, która zwraca dane w postaci: Tytuł Przedmiot Autor Wydawca Typ ksiązki Cena
Jak sformatować dane ?
Przykład użycia formaterów$dbacc = new DataAccess( … );
$data0 = $dbacc->getBooksWithPrice();
$data1 = new MoneyFormater(&$data0,
"5");
$data2 = new MultiFormater(&$data1,
"1|0+2+3+4|5");
$out = new Output();
$grid = new GridRenderer();
$grid->render(&$out, &$data2);
Prawda, że proste?
Coś bardziej złożonego
Formatery mogą być użyte także do bardziej złożonych operacji
Jeśli konstrukcja bazy wymaga bardzo skomplikowanych operacji – dotarcie do potrzebnych danych wymagać może bardzo skomplikowanych zapytań
A nie wszystkie bazy sobie z takimi zapytaniami radzą
Lista książek W naszej bazie w miarę prosto
można zapytać o listę potrzebnych książek, oraz o listę książek które użytkownik posiada
Potrzebna książka może być na kilku listach do których użytkownik jest zapisany
Bez podzapytań sobie nie poradzimy
Ale MySQL nie radzi sobie (dobrze) z podzapytaniami
Działania na danych
Zamiast budować połączenia pomiędzy skomplikowanymi zapytaniami możemy użyć prostych zapytań i złożyć wyniki w PHP
Potrzebujemy operacji na źródłach danych
Będzie to źródło danych oparte na wielu (na przekład dwóch) źródłach danych:
Suma danych W przypadku książek
potrzebujemy wszystkie takie które mamy oraz wszystkie takie które są nam potrzebne
Potrzebujemy więc wszystkie rekordy które są w pierwszym rekordsecie uzupełnione o takie które są w drugim ale nie ma ich w pierwszym
Nie ma sensu czytać całych rekordsetów i operować na danch w pamięci
Suma danych…
Aby operacja miała sens – oba źródłowe rekordsety muszą mieć taki sam format.
Jeśli oba rekodrsety są posortowane i posiadają pole które wyróznia dane sprawa mocno się upraszcza …
class RecordsetMerge
{
...
RecordsetMergevar $key;var $order;var $first;var $second;var $firstRecord;var $secondRecord; function RecordsetMerge( &$firstRecordset, &$secondRecordset, $keyField, $compareForOrderField){ $this->key = $keyField; $this->order = $compareForOrderField; $this->first = &$firstRecordset; $this->second = &$secondRecordset; $this->firstRecord = ($this->first->eof() ? null : $this->first->get(); ); $this->secondRecord = ($this->second->eof() ? null : $this->second->get(); );}
RecordsetMerge …function eof(){ return $this->firstRecord != null && $this->secondRecord != null;}
function get(){ if (!$this->firstRecord) return $this->getSecondAndSkipSecond(); else if (!$this->secondRecord) return $this->getFirstAndSkipFirst(); else if ($this->firstRecord[$this->key] == $this->secondRecord[$this->key]) return $this->getFirstAndSkipFirstSecond(); else if (str_compare_polish( $this->firstRecord[$this->order], $this->secondRecord[$this->order]) < 0) return $this->getFirstAndSkipFirst(); else return $this->getSecondAndSkipSecond(); }
W następnym odcinku
Co można zrobić po stronie klienta
Co warto zrobić po stronie klienta Dostęp do dokumentu poprzez
JavaScript Przykład czegoś nieco bardziej
skomplikowanego