2007.06_AJAX w CakePHP _[Ajax].pdf

(545 KB) Pobierz
440328207 UNPDF
Rozwiązania
AJAX w CakePHP
Zwiększenie funkcjonalności serwisu
Tradycyjne serwisy WWW przeważnie posiadają interfejs użytkownika
zbudowany z wykorzystaniem formularzy HTML. Powoduje to, iż nie są
interaktywne – wprowadzane dane są wysyłane do serwera, co z kolei
powoduje odświeżanie całej strony.
Dowiesz się...
• Poznasz praktyczne zastosowanie technologii
AJAX w środowisku Framework'u CakePHP. Po
analizie przedstawionego kodu będziesz mógł
wzgobacić własny serwis o dynamicznie pre-
zentowane dane.
Powinieneś wiedzieć...
• Wymagana jest znajomość Framework'u Cake-
PHP, umożliwiająca samodzielne skoniguro-
wanie środowiska Apache, MySQL i PHP. Przy-
datna będzie także znajomość podstaw języ-
ka JavaScript.
Script, to o wiele wygodniej jest operować
na danych, które w prosty sposób można
przetwarzać w tym języku;
Cascading StyleSheets ( CSS ) – kaskadowe
arkusze stylów to język służący do opisu
sposobu wizualizacji stron WWW. Za je-
go pomocą można przypisać atrybuty, takie
jak np.: kolor, wielkość czcionki, margine-
sy do poszczególnych elementów XHTML
lub XML;
Document Object Model ( DOM ) – obiektowy
model umożliwiający nawigację w struktu-
rze dokumentu XML oraz modyfikację za-
wartości jego określonych fragmentów;
JSON (ang. JavaScript Object Notation )
umożliwia prostą zamianę obiektów Java-
Script do postaci tekstu (tzw. proces seria-
lizacji), który może być przesyłany za po-
mocą XHR. Proces odwrotny przebiega
równie sprawnie.
Poziom trudności
iwem łączącym DOM z XHR (opis poni-
żej). Innymi słowy, pozwala na aktualiza-
cję fragmentów stron WWW o dane ode-
brane dynamicznie za pomocą XHR;
XMLHttpRequest ( XHR ) – obiekt umoż-
liwiający wymianę danych między serwe-
rem WWW i przeglądarką. Pomimo XML
w nazwie, XHR nie wymusza używania
tego formatu przy przesyłaniu informacji.
Ponieważ, po otrzymaniu danych, ich dal-
sza obróbka odbywa się za pomocą Java-
fika, szablony stylów, informacje pobiera-
ne ze źródeł danych – mimo, że strona po-
zostaje prawie niezmieniona! Technologia AJAX
(ang. Asynchronous JavaScript And XML) powsta-
ła, by zerwać z dotychczasowym modelem funk-
cjonowania aplikacji webowych. Jest świetnym na-
rzędziem do tworzenia interaktywnych witryn
internetowych, które umożliwia maksymalnie
upodobnić aplikacje webowe do ich odpowied-
ników ze stacji roboczych. Wprowadza asynchro-
niczną komunikację między przeglądarką użyt-
kownika i serwerem WWW, która pozwala na ak-
tualizację tylko wymaganych fragmentów stron,
zamiast przeładowywania całej zawartości.
W artykule przedstawimy praktyczne wpro-
wadzenie do technologii AJAX, na przykładzie
framework'u CakePHP. Zbudujemy przykłado-
wy serwis WWW ilustrujący korzyści (i ograni-
czenia) AJAX.
Czym jest AJAX?
AJAX nie jest językiem programowania stron
WWW. To nowy sposób wykorzystania zna-
nych wcześniej technologii:
JavaScript – język programowania działa-
jący w środowisku przeglądarki interne-
towej, po stronie użytkownika. Jest spo-
Rysunek 1. Zasilanie aplikacji danymi – tryb scafold
38
06/2007
P rzeładowywana jest cała zawartość – gra-
440328207.033.png
 
440328207.034.png 440328207.035.png 440328207.001.png 440328207.002.png 440328207.003.png 440328207.004.png 440328207.005.png 440328207.006.png 440328207.007.png
AJAX
Na szczęście nie ma potrzeby, by samodziel-
nie tworzyć kod, umożliwiający połączenie
powyższych technologii. Nie ma również po-
trzeby samodzielnego operowania na pozio-
mie obiektu XHR, czy troszczenia się o współ-
pracę z różnymi typami przeglądarek inter-
netowych. W internecie znajduje się wiele go-
towych bibliotek rozszerzających JavaScript
i ułatwiających integrację z PHP. W dalszej
części artykułu skupimy się na bibliotekach
Prototype oraz script.aculo.us, których obsłu-
ga jest częścią funkcjonalności framework'u
CakePHP.
nie ma konieczności przechodzenia mię-
dzy stronami, więc pojęcie poprzednia stro-
na traci swoje znaczenie).
o elementy zwiększające jej interaktywność
(i atrakcyjność). Model danych, który wyko-
rzystamy będzie prosty: pojedyncza tabela po-
wiązana z modelem Task (pol. zadanie ). Szcze-
góły związane z implementacją tej części apli-
kacji znajdują się na Listingach 1. oraz 2.
Przygotowane struktury nie zawierają jesz-
cze danych. Uzupełnimy je, wykorzystując
tryb scaffold , w którym CakePHP automaty-
cznie stworzy interfejs, umożliwiający dostęp
do danych za pomocą strony WWW. Tryb ten
jest aktywowany, gdy w kontrolerzejest zdefi-
niowana zmienna $scaffold . Nie ma potrzeby
definiowania funkcji obsługi modelu danych
– framework zrobi to za nas automatycznie.
Utworzymy teraz kontroler TasksControl-
ler odpowiadający modelowi danych Task
(Listing 3.).
CakePHP
Jak już wiemy, obsługa AJAX w CakePHP,
wymaga obecności biblioteki Prototype oraz
script.aculo.us . Niestety nie są one częścią
framework'u – musimy je samodzielnie po-
brać z internetu oraz zmodyfikować konfigura-
cję CakePHP, by ich obecność została uwzględ-
niona przy tworzeniu dynamicznych stron
WWW.
Zacznijmy od przygotowania prostego ser-
wisu, umożliwiającego zapisywanie do bazy
danych informacji wprowadzanych do formu-
larza. Najpierw przygotujemy wersję działają-
cą bez AJAX, którą następnie rozbudujemy
Korzyści ze stosowania
technologii AJAX
• AJAX umożliwia wykorzystanie doświad-
czeń użytkowników pracujących z aplika-
cjami desktopowymi. Podobne zachowanie
aplikacji, zbudowanej z wykorzystaniem
AJAX, może sprawić, iż będą one używa-
ne efektywniej;
• AJAX pozwala na ograniczenie ilości da-
nych przesyłanych między przeglądar-
ką internetową użytkownika i serwerem
WWW, przy zachowaniu dotychczaso-
wych funkcjonalności. Zamiast przesy-
łania zawartości całych stron, aktualizo-
wane są tylko te fragmenty, które uległy
zmianie;
• AJAX umożliwia tworzenie interaktyw-
nych metod prezentacji danych, które nie
były możliwe przy zastosowaniu dotych-
czasowych technologii (np. drag'n'drop , dy-
namicznie rozwijające się listy czy auto-
matyczne uzupełnianie tekstów wprowa-
dzanych do formularzy).
Ograniczenia
Rysunek 2. Wynik działania przykładowej aplikacja działającej bez AJAX
• AJAX wymaga od użytkowników, by po-
sługiwali się nowoczesnymi przeglądar-
kami obsługującymi technologie: DOM,
JavaScript, CSS. Wymaga to również posia-
dania równie nowoczesnych komputerów
o odpowiedniej mocy obliczeniowej;
• AJAX to dodatkowe kilobajty kodu, któ-
ry musi być dołączony do strony WWW.
W przypadku bibliotek Prototype oraz
script.aculo.us należy się liczyć z dodat-
kowymi 200KB kodu przesyłanych do
przeglądarki użytkownika. Ilość nowo
wprowadzanych danych można w znacz-
nym stopniu zmniejszyć, wcześniej kom-
presując przesyłane pliki (zobacz „kom-
presowanie komponentów”);
• AJAX zmienia funkcjonalność serwisów
WWW, ale nie przeglądarki internetowej.
Funkcje związane z przeglądaniem histo-
rii stron, w tym i przycisk wstecz , przywo-
łujący oglądane wcześniej dane, będą za-
chowywały się odmiennie, co może wpro-
wadzać użytkowników w błąd (w AJAX
Rysunek 3. Przykładowa aplikacja wykorzystująca technologię AJAX
www.phpsolmag.org
39
 
440328207.008.png 440328207.009.png 440328207.010.png 440328207.011.png 440328207.012.png
Rozwiązania
Listing 1. Struktura danych wykorzystywana w przykładowej aplikacji
CREATE TABLE `tasks` (
`id` int ( 10 ) NOT NULL auto_increment,
`title` varchar ( 60 ) ,
`done` int ( 1 ) NOT NULL default '0' ,
PRIMARY KEY ( `id` )
) ENGINE=MyISAM;
Nasza przykładowa aplikacja jest już goto-
wa. Wystarczy uruchomić przeglądarkę in-
ternetową i wpisać adres IP serwera Cake-
PHP, razem z nazwą kontrolera np. http://
127.0.0.1/tasks . Teraz możemy w prosty
sposób wprowadzić dane, które później bę-
dziemy wyszukiwać za pomocą formularza
HTML (Rysunek 1.).
Pobieranie danych tak zdefiniowanych struk-
tur powierzymy kontrolerowi TodoControl-
ler (Listing 3.) oraz domyślnemu widoko-
wi (plik app/views/todo/index.thtml) ,
w którym umieścimy kod generujący formu-
larz WWW (Listing 4.).
Po zasileniu testowymi danymi, nasza
aplikacja zachowuje się w sposób standar-
dowy – wprowadzenie informacji do for-
mularza i naciśnięcie przycisku Wyślij , po-
woduje przeładowanie całej strony i wyświe-
tlenie tytułów zadań pasujących do zadane-
go kryterium (Rysunek 2.). Wybierane są za-
dania nie ukończone (Task.done = 0) o na-
zwie identycznej z podanym ciągiem zna-
ków (Task.title = $title) , posortowa-
ne według kolejności utworzenia (Task.id
DESC).
Listing 2. Model danych Task
// plik app/models/task.php
class Task extends AppModel
{
// jeżeli używamy PHP4 musimy zdeiniować zmienną zawierającą nazwę klasy
var $name = 'Task' ;
// domyślnie nazwa klasy odpowiada nazwie tabeli w liczbie pojedynczej
// jeżeli jest inaczej i np. zamierzamy wykorzystać
// inną tabelę z bazy danych musimy zdeiniować jej nazwę
var $useTable = 'tasks' ;
}
Listing 3. Kontroler odpowiadający za zasilanie struktur danych informacjami z formularza WWW
(tryb scafold)
// plik app/controllers/tasks_controller.php
class TasksController extends AppController
{
Wprowadzamy
technologię AJAX
Zastanówmy się teraz jak, w naszym uprosz-
czonym przykładzie, wykorzystać technologię
AJAX. Wiemy już, że AJAX umożliwia dyna-
miczną (przebiegającą w tle) wymianę infor-
macji między serwerem WWW i przeglądar-
ką internetową. Możemy więc spróbować prze-
szukiwać bazę danych, w miarę jak użytkownik
wprowadza dane do formularza. Za każdym ra-
zem, gdy zmieni się kryterium wyszukiwania,
przeglądarka automatycznie wyśle zapytanie
do naszej aplikacji, która sprawdzi, czy odpo-
wiednie rekordy znajdują się w bazie danych.
Przekazana z serwera odpowiedź zostanie wy-
świetlona, dając wizualną podpowiedź o rezul-
tatach poszukiwań.
Realizacja powyższego schematu funkcjono-
wania aplikacji wymaga od nas kilku dodatko-
wych zabiegów:
// jeżeli używamy PHP4 musimy zdeiniować zmienną zawierającą nazwę klasy
var $name = 'Tasks' ;
var $uses = array ( 'Task' ) ;
var $helpers = array ( 'Html' ) ;
var $scaffold ;
}
// plik app/controllers/todo_controller.php
class TodoController extends AppController
{
// jeżeli używamy PHP4 musimy zdeiniować zmienną zawierającą nazwę klasy
var $name = 'Todo' ;
var $uses = array ( 'Task' ) ;
var $helpers = array ( 'Html' , 'Time' ) ;
// nie wyświetlaj żadnych informacji
function index( ) {
}
function search( )
{
if ( ! empty ( $this > data ))
{
$data = $this > data;
$title = strip_tags ( $data [ 'Task' ][ 'title' ]) ;
$tasks = $this > Task– > indAll (
array ( 'Task.done' = > 0, 'Task.title' = > $title ) , null, 'Task.id DESC' ) ;
$this > set ( 'todo' , $tasks ) ;
}
else
{
$this > redirect ( '/todo/index' ) ;
}
• musimy cyklicznie badać, czy w formula-
rzu pojawiły się nowe dane;
• musimy utworzyć metodę kontrolera, któ-
ra będzie sprawdzała obecność wyszuki-
wanych informacji w bazie danych;
• musimy znaleźć sposób, by informacje zwra-
cane przez serwer pojawiały się w prze-
glądarce bez konieczności przeładowania
całej strony WWW.
Na szczęście nie jesteśmy pierwszymi, któ-
rzy zadają sobie pytanie Jak to zrobić? Wspo-
mniana wcześniej biblioteka Prototype zawie-
ra wszystkie niezbędne funkcje, które maksy-
malnie ułatwią nam to zadanie. Uwolni ona
nas od konieczności samodzielnego badania
}
}
40
06/2007
440328207.013.png
 
440328207.014.png 440328207.015.png 440328207.016.png 440328207.017.png 440328207.018.png 440328207.019.png
 
AJAX
Listing 4. Widoki deiniujące formularz WWW
stanu formularza, obsługi obiektu XHR i ak-
tualizacji strony WWW o zwrócone informa-
cje. Po naszej stronie pozostanie tylko przygo-
towanie metody kontrolera, odpowiedzialne-
go za wyszukiwanie danych (będzie wywo-
ływany przy każdej aktualizacji formularza)
oraz powiązanie ze sobą odpowiednich kom-
ponentów CakePHP i Prototype.
Zacznijmy od początku. Włączenie obsługi
Prototype i script.aculo.us w CakePHP wymaga
pobrania bibliotek i umieszczenia ich w kata-
logu app/webroot/js . W kolejnym kroku mu-
simy zmodyfikować domyślny szablon serwi-
su: wymusić kodowanie UTF–8 (niezbędne do
poprawnej pracy AJAX) oraz załadować biblio-
teki Prototype oraz script.aculo.us (Listing
5.). Następnie dołączamy do kontrolera dodat-
kowe moduły, przez umieszczenie deklaracji:
// plik app/views/todo/index.thtml
< ?php
echo $html– > formTag('/todo/search');
?>
< div >
Wyszukiwanie zadań:
< div >
< ?php
echo $html– > input('Task/title', array('id' => 'search'));
?>
< ?php
echo $html– > submit('Wyślij');
?>
< /div >
< div >
< /div >
< /form >
// plik app/views/todo/search.thtml
var $helpers = array('Html',
'Javascript', 'Ajax');
< h2 > Znalezione zadania: < /h2 >
< ?php if (count($todo) > 0): ?>
< ul >
< ?php foreach ($todo as $task): ? >
< li >
< ?php
echo $task[ 'Task' ][ 'title' ];
? >
< /li >
< ?php endforeach ? >
< /ul >
< ?php else: ? >
< p > Nic nie znaleziono!? < /p >
< ?php endif ? >
< ?php
echo $html– > link('> powrót do formularza wyszukiwania', '/todo/index');
?>
W pierwszym momencie można się przera-
zić wielkością kodu, który będzie dołączony
do generowanych stron WWW. Obydwie bi-
blioteki to ponad 200KB dodatkowych da-
nych, które z pewnością nie przyspieszą star-
tu naszej aplikacji. Wielkość przesyłanych pli-
ków można jednak zmniejszyć o ponad poło-
wę, kompresując je przed przesłaniem do prze-
glądarki użytkownika (zobacz Kompresowanie
komponentów ).
Następnym wyzwaniem jest wykrycie zmian
w formularzu – chcemy przecież reagować na
każdy znak wprowadzony przez użytkowni-
ka. Biblioteka Prototype zawiera gotowe ele-
menty, które nas wyręczą w tej czynności.
Chodzi o metodę element: observe() , która
pozwala na automatyczne wywołanie funk-
cji JavaScript w przypadku, gdy obserwowa-
ny element (określany za pomocą identyfika-
tora DOM ID) uległ zmianie. Nie musimy jed-
nak umieszczać kodu JavaScript w naszej apli-
kacji – CakePHP zawiera funkcję, która za-
troszczy się o inicjalizację niezbędnych struk-
tur (plik plik app/views/todo/index.thtml
na Listingu 6.).
Jak widzimy, parametry do metody AjaxHel-
per::observeField() są przekazywane w asocja-
cyjnej tablicy $options. Ponieważ większość
metod obsługujących AJAX w CakePHP ko-
rzysta z tego sposobu, omówimy poszczegól-
ne parametry i ich znaczenie dla funkcjonowa-
nia aplikacji:
Listing 5. Modyikacja domyślnego szablonu strony CakePHP w celu automatycznego
wczytywania bibliotek Prototype i script.aculo.us
< ?php echo $html– > charsetTag('UTF–8'); ?>
< ?php echo $javascript– > link('prototype'); ?>
< ?php
echo $javascript– > link('scriptaculous.js?load=effects');
?>
Kompresowanie komponentów
Czas potrzebny na przesłanie kodu HTML do użytkownika, może być znacznie zredukowany za
pomocą różnego rodzaju buforowania (cache, proxy). Innym czynnikiem, który wpływa na szyb-
kość przesyłania danych jest ich wielkość. Możemy przyspieszyć przesyłanie stron WWW, pod-
dając je wcześniejszej kompresji. Protokół HTTP/1.1 umożliwia stacjom klienckim sygnalizowanie
obsługi skompresowanych danych za pomocą nagłówka: Accept–Encoding: gzip, delate. Jeżeli
serwer WWW wykryje takie informacje, może wysłać dane skompresowane, za pomocą jednej z
metod obsługiwanej po stronie klienta.
Kompresja gzip umożliwia zmniejszenie ilości danych średnio o 60–70%, w zależności od ich
rodzaju (typu). Największe redukcje osiągniemy kompresując pliki HTML, szablony CSS oraz kod
JavaScript (dane tekstowe). Kompresja plików graicznych, plików PDF czy archiwów jest zbędna,
gdyż dane w nich zapisane już wcześniej zostały poddane kompresji.
W chwili obecnej, ponad 90% przeglądarek internetowych, używanych do przeglądania
stron WWW obsługuje kompresję danych. Od strony serwera niezbędna jest koniguracja odpo-
wiedniego modułu – w przypadku Apache 1.3 jest to mod_gzip, w Apache 2.x – mod_delate.
• $options['url'] – adres URL akcji Ca-
kePHP, która ma zostać wywołana (w na-
szym przypadku – po modyfikacji formu-
larza);
• $options['frequency'] – liczba sekund
między kolejnymi testami wykrywający-
mi zmiany;
• $options['update'] – identyfikator DOM
elementu, który ma zostać zaktualizowa-
www.phpsolmag.org
41
 
440328207.020.png 440328207.021.png 440328207.022.png 440328207.023.png 440328207.024.png 440328207.025.png
Rozwiązania
Listing 6. Kod CakePHP umożliwiający reagowanie na zmiany w formularzu WWW
ny informacjami otrzymanymi w wyniku
działania akcji zawartej w $options['url'];
• $options['with'] – identyfikator DOM
elementu, który ma zostać dołączony do
żądania wysyłanego przez AJAX;
• $options['type'] – sposób komunika-
cji przeglądarki z serwerem aplikacji. Do-
myślnie przybiera wartość 'asynchronous'
(pol. asynchronicznie, w tle), jednak można
wymusić połączenie synchroniczne przez
umieszczenie wartości 'synchronous';
• $options['loading'] – kod JavaScript,
który będzie wywołany podczas pobiera-
nia danych z serwera;
• $options['loaded'] – kod JavaScript,
który będzie wywołany po zakończeniu
pobierania danych z serwera;
• $options['complete'] – kod JavaScript,
który będzie wywołany, gdy obiekt XHR
zakończył transfer danych;
• $options['condition'] – kod JavaScript
zawierający warunki, które muszą być
spełnione, zanim obiekt XHR zostanie za-
inicjalizowany;
• $options['conirm'] – tekst, który bę-
dzie wyświetlony w okienku potwierdze-
nia rozpoczęcia transferu danych przez
obiekt XHR (tzn. przed rozpoczęciem
transferu danych);
• $options['before'] – kod JavaScript,
który będzie wywołany, zanim żądanie
dostępu do danych będzie wysłane do ser-
wera WWW;
• $options['after'] – kod JavaScript, któ-
ry będzie wywołany po żądanie dostę-
pu do danych serwera WWW (zdarzenie
'after' występuje przed 'loading').
// plik app/views/todo/index.thtml
< !–– informacja o wczytywaniu danych jest domyślnie ukryta (display: none)– >
< div id= "loading" style= "display: none; padding: 4px; color: black;
background–color: #FAD163; width:400px" >
< center > Trwa ładowanie danych... < /center >
< /div >
< form onsubmit= "return false" >
< p >
< h2 > Wyszukiwanie: < /h2 >
< input type= "text" id= "search" name= "search" / >
< /p >
< /form >
<? php
// obserwacja zmian tekstu w formularzu wyszukiwania
$options = array (
'update' = > 'results' ,
'url' = > '/todo/search' ,
'frequency' = > 1,
'loading' = > "Element.hide ( 'results' ) ",
'complete' = > "Element.show ( 'results' ) "
) ;
echo $ajax > observeField ( 'search' , $options ) ;
?>
< !–– miejsce na wyniki poszukiwań domyślnie jest ukryte (display: none) –– >
< div id= "results" style= "display: none; margin–top: 10px;
background–color: #EEEEEE; padding:
4px; border: 1px solid #DDDDDD; width: 400px" >< /div >
< div style= "margin–top: 10px;" >
<? php
// link umożliwiający czyszczenie wyników wyszukiwania
// bez przeładowania strony WWW
$options = array (
'update' = > 'results' ,
'loading' = > "Element.hide ( 'results' ) ",
'complete' = > "Element.show ( 'results' ) "
) ;
echo $ajax > link ( 'Wyczyść listę wyszukiwania!' , '/todo/clear' , $options ) ;
?>
< /div >
Wracając do naszej aplikacji i Listingu 6. Za po-
mocą przedstawionego kodu będziemy moni-
torowali formularz (search) co jedną sekundę
($options['frequency'] => 1) . W przypad-
ku wykrycia zmian zostanie wywołana akcja
CakePHP , powodująca przeszukiwanie bazy da-
nych ($options['url'] => '/todo/search') , któ-
rej wyniki zostaną wyświetlone w przeglądarce
($options['update'] => 'results') . Kolejne
zmiany w stosunku do serwisu działającego bez
AJAX, dotyczą uniemożliwienia przeładowania
strony, w wyniku wysłaniaformularza. Standar-
dowo, klikając na przycisk Wyślij , powodujemy
wczytanie i wyświetlenie strony określonej pa-
rametrem <form action="URL">. W AJAX za-
bezpieczamy się przed tym, umieszczając para-
metr <form onsubmit="return false"> . Nie-
wielkie modyfikacje dotknęły także metodę To-
do Controller::search() , która teraz umożli-
wia wybieranie wszystkich danych pasujących
do ciągu znaków wprowadzonych do formula-
rza. Jest to możliwe dzięki zastosowaniu opera-
tora SQL "LIKE" (Listing 7.).
Modyfikacja formularza spowoduje wysła-
nie zapytania do serwera WWW, który w od-
powiedzi prześle listę danych pasujących do
// plik app/views/todo/clear.thtml
// zawiera informację wyświetlaną przy czyszczeniu wyników wyszukiwania
< center > Brak danych < /center >
// plik app/views/todo/search.thtml
<? php if ( count ( $todo ) > 0 ) : ?>
< ul >
<? php foreach ( $todo as $task ) : ?>
< li ><? php echo $task [ 'Task' ][ 'title' ] ; ?>< /li >
<? php endforeach ?>
< /ul >
<? php else : ?>
Nic nie znaleziono! ?
<? php endif ?>
42
06/2007
440328207.026.png
 
440328207.027.png 440328207.028.png 440328207.029.png 440328207.030.png 440328207.031.png 440328207.032.png
 
Zgłoś jeśli naruszono regulamin