1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
|
<sect1 id="zend.xmlrpc.server">
<title>Zend_XmlRpc_Server</title>
<sect2 id="zend.xmlrpc.server.introduction">
<title>Wprowadzenie</title>
<para>Klasa Zend_XmlRpc_Server jest przeznaczona do użycia jako
pełnofunkcjonalny serwer XML-RPC, zgodny ze
<ulink url="http://www.xmlrpc.com/spec">specyfikacją przedstawioną
na www.xmlrpc.com</ulink>. Dodatkowo implementuje ona metodę
system.multicall(), pozwalającą na wywołanie wielu metod podczas
jednego żądania.
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.usage">
<title>Podstawowe użycie</title>
<para>
Przykład najbardziej podstawowego przypadku użycia:
</para>
<programlisting role="php"><![CDATA[
$server = new Zend_XmlRpc_Server();
$server->setClass('My_Service_Class');
echo $server->handle();
]]>
</programlisting>
</sect2>
<sect2 id="zend.xmlrpc.server.structure">
<title>Struktura serwera</title>
<para>
Zend_XmlRpc_Server składa się z wielu różnych komponentów, od
samego serwera, przez obiekty żądania, obiekty odpowiedzi aż do
obiektów błędów.
</para>
<para>
Aby uruchomić serwer Zend_XmlRpc_Server, programista musi dołączyć
jedną lub więcej klas albo funkcji do serwera, za pomocą metod
<code>setClass()</code> oraz <code>addFunction()</code>.
</para>
<para>
Kiedy jest to już zrobione, możesz przekazać obiekt
<code>Zend_XmlRpc_Request</code> do metody
<code>Zend_XmlRpc_Server::handle()</code>, lub zostanie utworzona
instancja obiektu <code>Zend_XmlRpc_Request_Http</code> w przypadku
gdy nie zostanie zapewniony żaden obiekt -- spowoduje to pobieranie
żądań z <code>php://input</code>.
</para>
<para>
<code>Zend_XmlRpc_Server::handle()</code> próbuje wtedy uruchomić
odpowiednią klasę obsługującą, zależnie od użytej metody dostępu.
Zwraca wtedy obiekt oparty na <code>Zend_XmlRpc_Response</code> lub
obiekt <code>Zend_XmlRpc_Server_Fault</code>. Oba te obiekty mają
dostępne metody <code>__toString()</code>, ktore tworzą poprawne
odpowiedzi XML-RPC, pozwalając na bezpośrednie ich wyświetlenie.
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.conventions">
<title>Konwencje</title>
<para>
Zend_XmlRpc_Server pozwala programiście dołączać funkcje oraz metody
klas jako uruchamialne metody XML-RPC. Poprzez Zend_Server_Reflection,
przeprowadzana jest introspekcja dla wszystkich dołączanych metod,
używając bloków dokumentacji funkcji i metod do określenia opisów
pomocy dla metod oraz sygnatur metod.
</para>
<para>
XML-RPC nie mają w typach PHP dokładnych odpowiedników. Jednak skrypt
spróbuje dopasować najlepszy typ na podstawie wartości znajdujących
się w polach @param oraz @return. Niektóre typy XML-RPC nie mają
dokładnych odpowiedników w typach PHP, więc powinny być rzutowane
używając typów XML-RPC w komentarzach phpdoc. Są to:
</para>
<itemizedlist>
<listitem><para>dateTime.iso8601, łańcuch znaków sformatowany jako
YYYYMMDDTHH:mm:ss</para></listitem>
<listitem><para>base64, dane zakodowane jako base64</para></listitem>
<listitem><para>struct, dowolna tablica asocjacyjna</para></listitem>
</itemizedlist>
<para>
Przykład wywołania przykładowej funkcji:
</para>
<programlisting role="php"><![CDATA[
/**
* To jest przykładowa funkcja
*
* @param base64 $val1 Dane zakodowane jako Base64
* @param dateTime.iso8601 $val2 Data ISO
* @param struct $val3 Tablica asocjacyjna
* @return struct
*/
function myFunc($val1, $val2, $val3)
{
}
]]>
</programlisting>
<para>
PhpDocumentor nie przeprowadza weryfikacji typów określonych dla
parametrów lub zwracanych wartości, więc nie będzie to miało wpływu
na twoją dokumentację API
Providing the hinting is necessary, however, when the
server is validating the parameters provided to the method call.
</para>
<para>
Poprawne jest określenie wielu typów zarówno dla parametrów jak i
dla zwracanych wartości; specyfikacja XML-RPC sugeruje nawet, że
metoda system.methodSignature powinna zwracać tablicę wszystkich
możliwych sygnatur metody (np. wszystkie możliwe kombinacje
parametrów i zwracanych wartości). Możesz to zrobić tak jak robisz
to w PhpDocumentor, używając operatora '|':
</para>
<programlisting role="php"><![CDATA[
/**
* To jest przykładowa funkcja
*
* @param string|base64 $val1 Łańcuch znaków lub dane zakodowane jako base64
* @param string|dateTime.iso8601 $val2 Łańcuch znaków lub data ISO
* @param array|struct $val3 Normalnie indeksowana tablica lub tablica asocjacyjna
* @return boolean|struct
*/
function myFunc($val1, $val2, $val3)
{
}
]]>
</programlisting>
<para>
Jedna uwaga: dopuszczanie do utworzenia wielu różnych sygnatur może
doprowadzić do dezorientacji programistów używających serwisów;
W zasadzie metoda XML-RPC powinna mieć tylko jedną sygnaturę.
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.namespaces">
<title>Używanie przestrzeni nazw</title>
<para>
XML-RPC posiada system przestrzeni nazw; najprościej mówiąc, pozwala
to na grupowanie metod XML-RPC w przestrzenie nazw oddzielone
znakiem kropki. Ułatwia to zapobieganie konfliktom pomiędzy metodami
pochodzącymi z rożnych klas. Przykładowo, serwer XML-RPC powinien
udostępniać kilka metod w przestrzeni nazw 'system':
</para>
<itemizedlist>
<listitem><para>system.listMethods</para></listitem>
<listitem><para>system.methodHelp</para></listitem>
<listitem><para>system.methodSignature</para></listitem>
</itemizedlist>
<para>
Wewnątrz odpowiada to metodom o tych samych w obiekcie
Zend_XmlRpc_Server.
</para>
<para>
Jeśli chcesz dodać przestrzenie nazw do metod, które oferujesz, po
prostu podaj przestrzeń nazw do odpowiedniej metody wtedy, gdy
dołączasz funkcję lub klasę:
</para>
<programlisting role="php"><![CDATA[
// Wszystkie publiczne metody klasy My_Service_Class będą dostępne jako
// myservice.METHODNAME
$server->setClass('My_Service_Class', 'myservice');
// Funkcja 'somefunc' będzie dostępna jako funcs.somefunc
$server->addFunction('somefunc', 'funcs');
]]>
</programlisting>
</sect2>
<sect2 id="zend.xmlrpc.server.request">
<title>Własny obiekt żądania</title>
<para>
W większości przypadków będziesz używał domyślnego obiektu żądania
dostarczanego przez Zend_XmlRpc_Server, którym jest obiekt
Zend_XmlRpc_Request_Http. Jednak czasem możesz chcieć aby usługa
XML-RPC była dostępna przez CLI, GUI lub inne środowisko, lub możesz
chcieć zapisywać informacje o przychodzących żądaniach. Aby to
zrobić, możesz utworzyć własny obiekt żądania, który rozszerza
obiekt Zend_XmlRpc_Request. Najważniejszą rzeczą jest zapamiętanie
aby zawsze implementować metody getMethod() oraz getParams() co
pozwoli na to, że serwer XML-RPC będzie mógł pobrać te informacje w
celu uruchomienia żądania.
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.response">
<title>Własne odpowiedzi</title>
<para>
Podobnie jak obiekty żądania, Zend_XmlRpc_Server może zwracać własne
obiekty odpowiedzi; domyślnie zwracany jest obiekt
Zend_XmlRpc_Response_Http, który wysyła odpowiedni nagłówek HTPP
Content-Type do użycia z XML-RPC. Możliwym powodem użycia własnego
obiektu może być potrzeba logowania odpowiedzi, lub wysyłanie
odpowiedzi spowrotem do STDOUT.
</para>
<para>
Aby użyć własnej klasy odpowiedzi, użyj metody
Zend_XmlRpc_Server::setResponseClass() przed wywołaniem handle().
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.fault">
<title>Obsługa wyjątków poprzez odpowiedzi błędów</title>
<para>
Obiekt Zend_XmlRpc_Server łapie wyjątki wyrzucone przez uruchomioną
metodę i generuje odpowiedź błędu (fault) wtedy gdy taki wyjątek
zostanie złapany. Domyślnie informacje o wyjątkach i ich kody nie są
używane w odpowiedzi błędu. Jest to celowe zachowanie chroniące twój
kod; wiele wyjątków ujawnia dużo informacji o kodzie oraz środowisku,
czemu programista powinien zapobiec (dobrym przykładem mogą być
informacje o wyjątkach związanych z bazą danych)
</para>
<para>
Klasy wyjątków, które mają być użyte jako odpowiedzi błędów mogą być
dodane do listy dozwolonych wyjątków. Aby to zrobić wystarczy użyć
metody Zend_XmlRpc_Server_Fault::attachFaultException() w celu
przekazania klasy wyjątku do listy dozwolonych wyjątków:
</para>
<programlisting role="php"><![CDATA[
Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
]]>
</programlisting>
<para>
Jeśli dodasz do listy wyjątków klasę wyjątku z którego dziedziczą
inne wyjątki, możesz w ten sposób dodać do listy całą rodzinę
wyjątków za jednym razem. Wyjątki Zend_XmlRpc_Server_Exceptions
zawsze znajdują się na liście dozwolonych wyjątków, aby pozwolić na
informowanie o specyficznych wewnętrznych błędach (niezdefiniowanie
metody itp.).
</para>
<para>
Każdy wyjątek spoza listy dozwolonych wyjątków spowoduje
wygenerowanie odpowiedzi błędu o kodzie '404' i informacji
'Unknown error' (Nieznany błąd).
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.caching">
<title>Buforowanie definicji serwera pomiędzy żądaniami</title>
<para>
Dołączanie wielu klas do instancji serwera XML-RPC może zajmować
wiele zasobów; za pomocą Reflection API (przez Zend_Server_Reflection)
musi być dokonana introspekcja każdej klasy co w rezultacie wygeneruje
listę wszystkich możliwych sygnatur metod w celu przekazania jej
do klasy serwera.
</para>
<para>
Aby zredukować straty wydajności, możemy użyć obiektu
Zend_XmlRpc_Server_Cache do buforowania definicji serwera pomiędzy
żądaniami. Gdy połączymy to z funkcją __autoload(), może to mocno
zwiększyć wydajność.
</para>
<para>
Przykładowe użycie:
</para>
<programlisting role="php"><![CDATA[
function __autoload($class)
{
Zend_Loader::loadClass($class);
}
$cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
$server = new Zend_XmlRpc_Server();
if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
require_once 'My/Services/Glue.php';
require_once 'My/Services/Paste.php';
require_once 'My/Services/Tape.php';
$server->setClass('My_Services_Glue', 'glue'); // przestrzeń nazw glue
$server->setClass('My_Services_Paste', 'paste'); // przestrzeń nazw paste
$server->setClass('My_Services_Tape', 'tape'); // przestrzeń nazw tape
Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
}
echo $server->handle();
]]>
</programlisting>
<para>
Powyższy przykład próbuje pobrać definicję serwera z pliku bufora
xmlrpc.cache znajdującego się w tym samym katalogu co skrypt. Jeśli
się to nie uda, załaduje on potrzebne klasy serwisu, dołączy do
instancji serwera i spróbuje utworzyć nowy plik bufora z definicją
sderwera.
</para>
</sect2>
<sect2 id="zend.xmlrpc.server.use">
<title>Przykład użycia</title>
<para>
Poniżej znajduje się kilka przykładów użycia, pokazując pełne
spektrum opcji dostępnych dla programistów. Każdy z przykładów
użycia jest oparty na poprzednich przykładach.
</para>
<sect3 id="zend.xmlrpc.server.use.case1">
<title>Podstawowe użycie</title>
<para>
Poniższy przykład dołącza funkcję jaką uruchamialną przez
XML-RPC metodę i obsługuje przychodzące wywołania.
</para>
<programlisting role="php"><![CDATA[
/**
* Zwraca sumę MD5 zadanej wartości
*
* @param string $value wartość do obliczenia sumy md5
* @return string MD5 suma wartości
*/
function md5Value($value)
{
return md5($value);
}
$server = new Zend_XmlRpc_Server();
$server->addFunction('md5Value');
echo $server->handle();
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case2">
<title>Dołączanie klasy</title>
<para>
Poniższy przykład pokazuje dołączanie publicznych metod klasy
jako uruchamialnych metod XML-RPC.
</para>
<programlisting role="php"><![CDATA[
$server = new Zend_XmlRpc_Server();
$server->setClass('Services_Comb');
echo $server->handle();
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case3">
<title>Dołączanie wielu klas używając przestrzeni nazw</title>
<para>
Poniższy przykład pokazuje dołączanie kilku klas, każdej z
własną przestrzenią nazw.
</para>
<programlisting role="php"><![CDATA[
$server = new Zend_XmlRpc_Server();
$server->setClass('Services_Comb', 'comb'); // metody wywoływane jako comb.*
$server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
$server->setClass('Services_Pick', 'pick'); // metody wywoływane jako pick.*
echo $server->handle();
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case4">
<title>Określenie wyjątków dla odpowiedzi błędów</title>
<para>
Poniższy przykład pozwala dowolnej klasie pochodzącej od
Services_Exception na przekazywanie informacji o wyjątkach w
postaci kodu i wiadomości w odpowiedzi błędu.
</para>
<programlisting role="php"><![CDATA[
// Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
$server = new Zend_XmlRpc_Server();
$server->setClass('Services_Comb', 'comb'); // metody wywoływane jako comb.*
$server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
$server->setClass('Services_Pick', 'pick'); // metody wywoływane jako pick.*
echo $server->handle();
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case5">
<title>Użycie własnego obiektu żądania</title>
<para>
Poniższy przykład tworzy instancję własnego obiektu żądania i
przekazuje go do obiektu serwera.
</para>
<programlisting role="php"><![CDATA[
// Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
$server = new Zend_XmlRpc_Server();
$server->setClass('Services_Comb', 'comb'); // metody wywoływane jako comb.*
$server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
$server->setClass('Services_Pick', 'pick'); // metody wywoływane jako pick.*
// Tworzenie obiektu żądania
$request = new Services_Request();
echo $server->handle($request);
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case6">
<title>Użycie własnego obiektu odpowiedzi</title>
<para>
Poniższy przykład pokazuje określanie własnej klasy odpowiedzi
dla zwracanej odpowiedzi.
</para>
<programlisting role="php"><![CDATA[
// Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
$server = new Zend_XmlRpc_Server();
$server->setClass('Services_Comb', 'comb'); // metody wywoływane jako comb.*
$server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
$server->setClass('Services_Pick', 'pick'); // metody wywoływane jako pick.*
// Utwórz obiekt żądania
$request = new Services_Request();
// Użyj własnego obiektu żądania
$server->setResponseClass('Services_Response');
echo $server->handle($request);
]]>
</programlisting>
</sect3>
<sect3 id="zend.xmlrpc.server.use.case7">
<title>Buforowanie definicji serwera pomiędzy żądaniami</title>
<para>
Poniższy przykład pokazuje buforowanie definicji serwera pomiędzy
żądaniami.
</para>
<programlisting role="php"><![CDATA[
// Określ plik cache
$cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
// Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
$server = new Zend_XmlRpc_Server();
// Spróbuj pobrać definicje serwera z bufora
if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
$server->setClass('Services_Comb', 'comb'); // metody wywoływane jako comb.*
$server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
$server->setClass('Services_Pick', 'pick'); // metody wywoływane jako pick.*
// Zapisz cache
Zend_XmlRpc_Server_Cache::save($cacheFile, $server));
}
// Utwórz obiekt żądania
$request = new Services_Request();
// Użyj własnej klasy odpowiedzi
$server->setResponseClass('Services_Response');
echo $server->handle($request);
]]>
</programlisting>
</sect3>
</sect2>
</sect1>
|