| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.amf.server">
- <title>Zend_Amf_Server</title>
- <para>
- <classname>Zend_Amf_Server</classname> bietet einen <acronym>RPC</acronym>-artigen Server
- für die Behandlung der Anfragen die vom Adobe Flash Player durchgeführt werden indem das
- <acronym>AMF</acronym> Protokoll verwendet wird. Wie alle Zend Framework Serverklassen,
- folgt es der SoapServer <acronym>API</acronym>, und bietet ein einfach zu merkendes
- Interface für die Erstellung von Servern.
- </para>
- <example id="zend.amf.server.basic">
- <title>AMF Server Grundlagen</title>
- <para>
- Angenommen wir haben eine Klasse <classname>Foo</classname> mit einer Anzahl von
- öffentlichen Methoden erstellt. Man kann einen <acronym>AMF</acronym> Server erstellen
- indem der folgende Code verwendet wird:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Amf_Server();
- $server->setClass('Foo');
- $response = $server->handle();
- echo $response;
- ]]></programlisting>
- <para>
- Alternativ kann stattdessen man eine einfache Funktion als Callback anhängen:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Amf_Server();
- $server->addFunction('myUberCoolFunction');
- $response = $server->handle();
- echo $response;
- ]]></programlisting>
- <para>
- Man kann auch mehrere Klassen und Funktionen mischen und verwenden. Wenn man das macht
- wird empfohlen das jede von Ihnen einen Namespace erhält um sicherzustellen das keine
- Kollision von Methodennamen stattfindet; das kann durchgeführt werden indem man einfach
- ein zweites Stringargument entweder an <methodname>addFunction()</methodname> oder an
- <methodname>setClass()</methodname> übergibt:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Amf_Server();
- $server->addFunction('myUberCoolFunction', 'my')
- ->setClass('Foo', 'foo')
- ->setClass('Bar', 'bar');
- $response = $server->handle();
- echo $response;
- ]]></programlisting>
- <para>
- <classname>Zend_Amf_Server</classname> erlaubt es auch Services das Sie dynamisch
- geladen werden, basierend auf dem angegebenen Verzeichnispfad. Man kann dem Server so
- viele Verzeichnisse wie man will hinzufügen. Die Reihenfolge in der man die
- Verzeichnisse zum Server hinzufügt ist die Reihenfolge in der die
- <acronym>LIFO</acronym> Suche auf den Verzeichnissen durchgeführt wird um die Klasse
- zu finden. Das Hinzufügen von Verzeichnissen wird mit der
- <methodname>addDirectory()</methodname> Methode durchgeführt.
- </para>
- <programlisting language="php"><![CDATA[
- $server->addDirectory(dirname(__FILE__) .'/../services/');
- $server->addDirectory(dirname(__FILE__) .'/../package/');
- ]]></programlisting>
- <para>
- Wenn entfernte Services aufgerufen werden kann der Quellname einen Unterstrich ("_")
- oder Punkt (".") Begrenzer im Verzeichnis haben. Wenn ein Unterstrich verwendet wird
- werden die Namenskonventionen der <acronym>PEAR</acronym> und Zend Framework Klassen
- verwendet. Das bedeutet das wenn man das Sevice com_Foo_Bar
- aufruft wird der Server nach der Datei <filename>Bar.php</filename> suchen, und zwar in
- jedem der eingefügten Pfade unter <filename>com/Foo/Bar.php</filename>. Wenn die Punkt
- Notation für entfernte Services wie für <filename>com.Foo.Bar</filename> verwendet
- wird, wird jedem eingefügten Pfad <filename>com/Foo/Bar.php</filename> am Ende
- hinzugefügt um <filename>Bar.php</filename> automatisch zu laden.
- </para>
- <para>
- Alle <acronym>AMF</acronym> Anfragen die an das Skript gesendet werden, werden dann
- durch den Server behandelt, und eine <acronym>AMF</acronym> Antwort wird zurückgegeben.
- </para>
- </example>
- <note>
- <title>Alle angehängten Methoden und Funktionen benötigen einen Docblock</title>
- <para>
- Wie alle anderen Serverkomponenten im Zend Framework müssen die Klassenmethoden
- dokumentiert werden indem <acronym>PHP</acronym> Docblocks verwendet werden. Mindestens
- muß für jedes benötigte Argument eine Beschreibung angegeben werden sowie ein
- Rückgabewert. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- // Funktion zum Anhängen:
- /**
- * @param string $name
- * @param string $greeting
- * @return string
- */
- function helloWorld($name, $greeting = 'Hello')
- {
- return $greeting . ', ' . $name;
- }
- ]]></programlisting>
- <programlisting language="php"><![CDATA[
- // Angehängte Klasse
- class World
- {
- /**
- * @param string $name
- * @param string $greeting
- * @return string
- */
- public function hello($name, $greeting = 'Hello')
- {
- return $greeting . ', ' . $name;
- }
- }
- ]]></programlisting>
- <para>
- Andere anmerkungen können verwendet werden, werden aber ignoriert.
- </para>
- </note>
- <sect2 id="zend.amf.server.flex">
- <title>Zum Server von Flex aus verbinden</title>
- <para>
- Zum eigenen <classname>Zend_Amf_Server</classname> von einem Flex Projekt aus zu
- verbinden ist recht einfach; man muß zur Endpunkt <acronym>URI</acronym> des
- <classname>Zend_Amf_Server</classname> Sripts zeigen.
- </para>
- <para>
- Nehmen wir zum Beispiel an das man einen Server erstellt hat und Ihn in der
- <filename>server.php</filename> Datei im Anwendungsroot platziert, und die
- <acronym>URI</acronym> deswegen <filename>http://example.com/server.php</filename> ist.
- In diesem Fall würde man die <filename>services-config.xml</filename> Datei so
- modifizieren damit das channel endpoint uri Attribut auf diesen Wert gesetzt ist.
- </para>
- <para>
- Wenn man noch keine <filename>service-config.xml</filename> Datei erstellt hat kann man
- das tun, indem man das Projekt im Navigator Fenster öffnet. Auf dem Projektnamen
- rechts-klickt und 'properties' auswählt. Im Fenster der Projekteigenschaften muß man in
- das 'Flex Build Path' Menü, auf den 'Library path' Tab und sicherstellen das die
- '<filename>rpc.swc</filename>' Datei bei den Projektpfaden hinzugefügt ist und auf Ok
- drücken um das Fenster zu schließen.
- </para>
- <para>
- Man muß dem Compiler auch mitteilen das er die <filename>service-config.xml</filename>
- verwenden soll um den Endpunkt des RemoteObjects zu finden. Um das zu tun muß das
- Fenster der Projekteigenschaften nochmals durch einen rechts-klick auf das
- Projektverzeichnis vom Navigator aus geöffnet und Eigenschaften ausgewählt werden. Vom
- Eigenschaften-Popup muß 'Flex Compiler' aufgewählt und der String:
- <command>-services "services-config.xml"</command> hinzugefügt werden. Auf Apply
- drücken, anschließend auf OK um die Option zu aktualisieren. Was man jetzt getan hat,
- ist dem Flex Compiler zu sagen das er in der Datei
- <filename>services-config.xml</filename> nach Laufzeitvariablen schauen soll die von
- der RemotingObject Klasse verwendet werden.
- </para>
- <para>
- Jetzt müssen wir Flex mitteilen welche Konfigurationsdateien der Services für die
- Verbindung zu unseren entfernten Methoden zu verwenden sind. Aus diesem Grund muß eine
- neue '<filename>services-config.xml</filename>' Datei im Flexprojekt src Verzeichnis
- erstellt werden. Um das zu tun, muß man auf den Projektfolder rechts klicken und 'new'
- 'File' auswählen was ein neues Fenster öffnet. Anschließend das Projektverzeichnis
- auswählen und dann die Datei '<filename>services-config.xml</filename>' benennen und
- auf Beenden drücken.
- </para>
- <para>
- Flex hat eine neue <filename>services-config.xml</filename> erstellt und Sie geöffnet.
- Verwende den folgenden Beispieltext für die <filename>services-config.xml</filename>
- Datei. Es muß sichergestellt werden das der Endpunkt so aktualisiert wird das er zu dem
- des eigenen Testservers passt. Anschließend sicherstellen das die Datei gespeichert
- wird.
- </para>
- <programlisting language="xml"><![CDATA[
- <?xml version="1.0" encoding="UTF-8"?>
- <services-config>
- <services>
- <service id="zend-service"
- class="flex.messaging.services.RemotingService"
- messageTypes="flex.messaging.messages.RemotingMessage">
- <destination id="zend">
- <channels>
- <channel ref="zend-endpoint"/>
- </channels>
- <properties>
- <source>*</source>
- </properties>
- </destination>
- </service>
- </services>
- <channels>
- <channel-definition id="zend-endpoint"
- class="mx.messaging.channels.AMFChannel">
- <endpoint uri="http://example.com/server.php"
- class="flex.messaging.endpoints.AMFEndpoint"/>
- </channel-definition>
- </channels>
- </services-config>
- ]]></programlisting>
- <para>
- Es gibt zwei Schlüsselpunkt im Beispiel. Erstens, aber letztes im Code, erstellen wir
- einen <acronym>AMF</acronym> Kanal, und spezifizieren den Endpunt als die
- <acronym>URL</acronym> zu unserem <classname>Zend_Amf_Server</classname>:
- </para>
- <programlisting language="xml"><![CDATA[
- <channel-definition id="zend-endpoint"
- <endpoint uri="http://example.com/server.php"
- class="flex.messaging.endpoints.AMFEndpoint"/>
- </channel-definition>
- ]]></programlisting>
- <para>
- Es ist zu beachten das wir diesem Kanal einen Identifikator, "zend-endpoint", gegeben
- haben. Das Beispiel erstellt ein Ziel für den Service auf zu diesen Kanal zeigt,
- und fügt es auch als ID hinzu -- in diesem Zall "zend".
- </para>
- <para>
- In unseren Flex <acronym>MXML</acronym> Dateien müssen wir ein RemoteObject an das
- Service binden. In <acronym>MXML</acronym> kann das wie folgt getan werden:
- </para>
- <programlisting language="xml"><![CDATA[
- <mx:RemoteObject id="myservice"
- fault="faultHandler(event)"
- showBusyCursor="true"
- destination="zend">
- ]]></programlisting>
- <para>
- Hier haben wir ein neues entferntes Objekt definiert das durch "myservice"
- identifiziert an das Serviceziel "zend" gebunden ist das wir in der
- <filename>services-config.xml</filename> Datei definiert haben. Dann rufen wir die
- Methoden auf Ihnen in unserem ActionScript einfach durch Aufruf von
- "myservice.<method>" auf. Als Beispiel:
- </para>
- <programlisting language="ActionScript"><![CDATA[
- myservice.hello("Wade");
- ]]></programlisting>
- <para>
- Wenn wir Namespaces aktivieren würden wir "myservice.<namespace>.<method>"
- verwenden:
- </para>
- <programlisting language="ActionScript"><![CDATA[
- myservice.world.hello("Wade");
- ]]></programlisting>
- <para>
- Für weitere Informationen über den Aufruf von Flex RemoteObject, <ulink
- url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">besuchen
- Sie die Adobe Flex 3 Hilfeseite</ulink>.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.errors">
- <title>Fehlerbehandlung</title>
- <para>
- Standardmäßig werden alle Exceptions die in den angehängten Klassen oder Funktionen
- geworfen werden gefangen und als <acronym>AMF</acronym> Fehlermeldungen zurückgegeben.
- Trotzdem wird der Inhalt des ErrorMessage Objekts variieren basierend darauf ob der
- Server im "Produktions" Modus ist (der Standardzustand) oder nicht.
- </para>
- <para>
- Wenn er in Produktionsmodus ist wird nur der Exceptioncode zurückgegeben. Wenn der
- Produktionsmodus ausgeschaltet wird -- etwas das nur für das Testen getan werden sollte
- -- werden die meisten Exceptiondetails zurückgegeben: Die Meldung der Exception, die
- Zeile, und der Backtrace werden alle angehängt.
- </para>
- <para>
- Um den Produktionsmodus auszuschalten muß das folgende getan werden:
- </para>
- <programlisting language="php"><![CDATA[
- $server->setProduction(false);
- ]]></programlisting>
- <para>
- Um Ihn wieder einzuschalten, muß stattdessen einfach ein boolscher
- <constant>TRUE</constant> Wert übergeben werden:
- </para>
- <programlisting language="php"><![CDATA[
- $server->setProduction(true);
- ]]></programlisting>
- <note>
- <title>Der Produktionsmode sollte sparsam deaktiviert werden!</title>
- <para>
- Wir empfehlen den Produktionsmode nur während der Entwicklung auszuschalten.
- Exceptionmeldungen und Backtraces können sensitive Systeminformationen enthalten
- auf die nicht von Aussenstehenden zugegriffen werden darf. Selbst wenn
- <acronym>AMF</acronym> ein binäres Format ist, ist die Spezifikation offen, was
- bedeutet das jeder den Payload potentiell deserialisieren kann.
- </para>
- </note>
- <para>
- Ein Feld bei dem man im speziellen Vorsichtig sein muß ist bei <acronym>PHP</acronym>
- Fehlern selbst. Wenn die <acronym>INI</acronym> Direktive
- <property>display_errors</property> aktiviert ist, wird jeder <acronym>PHP</acronym>
- Fehler für das aktuelle Error Reporting Level direkt in der Ausgabe dargestellt -- was
- den <acronym>AMF</acronym> Antwortpayload potentiell unterbrechen kann. Wir empfehlen
- die <property>display_errors</property> Direktive in der Produktion auszuschalten um
- solche Probleme zu verhindern.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.response">
- <title>AMF Antworten</title>
- <para>
- Fallweise ist es gewünscht das Antwortobjekt leicht zu manipulieren, typischerweise um
- zusätzliche Nachrichtenheader zurückzugeben. Die <methodname>handle()</methodname>
- Methode des Servers gibt das Antwortobjekt zurück, was es erlaubt das zu tun.
- </para>
- <example id="zend.amf.server.response.messageHeaderExample">
- <title>Nachrichtenheader der AMF Antwort hinzufügen</title>
- <para>
- In diesem Beispiel fügen wir einen 'foo' Nachrichtenheader mit dem Wert 'bar' zu der
- Antwort hinzu bevor sie zurückgegeben wird.
- </para>
- <programlisting language="php"><![CDATA[
- $response = $server->handle();
- $response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
- echo $response;
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.amf.server.typedobjects">
- <title>Typ Objekte</title>
- <para>
- Ähnlich wie <acronym>SOAP</acronym>, erlaubt es <acronym>AMF</acronym> Objekte zwischen
- dem Client und dem Server zu übergeben. Das erlaubt eine große Flexibilität und Bindung
- zwischen den zwei Umgebungen.
- </para>
- <para>
- <classname>Zend_Amf</classname> bietet drei Methoden für das Mappen von ActionScript und
- <acronym>PHP</acronym> Objekten.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Erstens kann man explizite Bindungen auf Serverlevel erstellen indem die
- <methodname>setClassMap()</methodname> Methode verwendet wird. Das erste
- Argument ist der ActionScript Klassenname, das zweite ist der Name der
- <acronym>PHP</acronym> Klasse auf die gemappt wird:
- </para>
- <programlisting language="php"><![CDATA[
- // Die ActionScript Klasse 'ContactVO' auf die PHP Klasse 'Contact' mappen:
- $server->setClassMap('ContactVO', 'Contact');
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Zweitens kann die öffentliche Eigenschaft <varname>$_explicitType</varname> in
- der <acronym>PHP</acronym> Klasse gesetzt werden, wobei der Wert die
- ActionScript Klasse repräsentiert auf die gemappt wird:
- </para>
- <programlisting language="php"><![CDATA[
- class Contact
- {
- public $_explicitType = 'ContactVO';
- }
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Drittens, in ähnlicher Art und Weise, kann eine öffentliche Methode
- <methodname>getASClassName()</methodname> in der <acronym>PHP</acronym> Klasse
- definiert werden; diese Methode sollte die passende ActionScript Klasse
- zurückgeben:
- </para>
- <programlisting language="php"><![CDATA[
- class Contact
- {
- public function getASClassName()
- {
- return 'ContactVO';
- }
- }
- ]]></programlisting>
- </listitem>
- </itemizedlist>
- <para>
- Auch wenn wir nun den ContactVO auf dem Server erstellt have müssen wir nun seine
- korrespondierende Klasse in <acronym>AS3</acronym> für das Server Objekt erstellen das
- gemappt werden soll.
- </para>
- <para>
- Einen Rechtsklick auf das src Verzeichnis des Flex Projekts und New -> ActionScript File
- auswählen. Name der Datei ContactVO und finish drücken um die neue Datei zu sehen.
- Den folgenden Code in die Datei kopieren um die Erstellung der Klasse fertigzustellen.
- </para>
- <programlisting language="as"><![CDATA[
- package
- {
- [Bindable]
- [RemoteClass(alias="ContactVO")]
- public class ContactVO
- {
- public var id:int;
- public var firstname:String;
- public var lastname:String;
- public var email:String;
- public var mobile:String;
- public function ProductVO():void {
- }
- }
- }
- ]]></programlisting>
- <para>
- Die Klasse ist syntaktisch identisch zu der von <acronym>PHP</acronym> mit dem gleichen
- Namen. Die Variablennamen sind exakt die gleichen und müssen im gleichen Fall sein um
- korrekt zu arbeiten. Es gibt zwei eindeutige <acronym>AS3</acronym> Metatags in dieser
- Klasse. Das Erste kann gebunden werden was ein Änderungsevent wirft wenn es
- aktualisiert wird. Das zweite Tag ist das RemoteClass Tag welches definiert das diese
- Klasse ein gemapptes entferntes Objekt haben kann, in diesem Fall mit dem Aliasnamen
- <emphasis>ContactVO</emphasis>. Es ist erforderlich das dieses Tag und der Wert der in
- der <acronym>PHP</acronym> Klasse gesetzt wurde, strikt identisch sind.
- </para>
- <programlisting language="as"><![CDATA[
- [Bindable]
- private var myContact:ContactVO;
- private function getContactHandler(event:ResultEvent):void {
- myContact = ContactVO(event.result);
- }
- ]]></programlisting>
- <para>
- Das folgende Ergebnisevent vom Serviceaufruf wird sofort zu Flex ContactVO gecastet.
- Alles das bei myContact gebunden ist, wird mit den von ContactVO zurückgegebenen
- Daten aktualisiert.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.resources">
- <title>Ressourcen</title>
- <para>
- <classname>Zend_Amf</classname> bietet Tools für das Mappen von Ressource Typen die
- von Service Klassen in von ActionScript verwendbaren Daten zurückgegeben werden.
- </para>
- <para>
- Um spezielle Ressource Typen zu behandeln, muss der Benutzer eine Plugin Klasse
- erstellen die nach dem Ressource Namen benannt ist, mit großgeschriebenen Wörtern
- und entfernten Leerzeichen (ein Ressouce Typ "mysql result" wird zu MysqlResult),
- mit einem Präfix, z.B. <classname>My_MysqlResult</classname>. Diese Klasse sollte eine
- Methode implementieren, <methodname>parse()</methodname>, die ein Argument - die
- Ressource - annimmt und den Wert zurückgibt der an das ActionScript gesendet werden
- sollte. Die Klasse sollte in der Datei vorhanden sein nachdem die letzte Komponente des
- Namens benannt ist, z.B. <filename>MysqlResult.php</filename>.
- </para>
- <para>
- Das Verzeichnis das die Plugins für das Ressource Handling enthält sollte beim Typloader
- von <classname>Zend_Amf</classname> registriert sein:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_Amf_Parse_TypeLoader::addResourceDirectory(
- "My",
- "application/library/resources/My"
- );
- ]]></programlisting>
- <para>
- Für eine detailierte Diskussion für das Laden von Plugins, sehen Sie bitte in das
- Kapitel <link linkend="zend.loader.pluginloader">Plugin Loader</link>.
- </para>
- <para>
- Das Standardverzeichnis für Ressourcen von <classname>Zend_Amf</classname> wird
- automatisch registriert und enthält aktuell Handler für "mysql result" und "stream"
- Ressourcen.
- </para>
- <programlisting language="php"><![CDATA[
- // Beispiel für die Implementierung von Ressourcen und die Behandlung
- // von Mysql Ergebnis Typen
- class Zend_Amf_Parse_Resource_MysqlResult
- {
- /**
- * Parse resource into array
- *
- * @param resource $resource
- * @return array
- */
- public function parse($resource) {
- $result = array();
- while($row = mysql_fetch_assoc($resource)) {
- $result[] = $row;
- }
- return $result;
- }
- }
- ]]></programlisting>
- <para>
- Der Versuch einen unbekannten Ressource Typ zurückzugeben (z.B. einen für den kein
- Handler Plugin existiert) führt zu einer Exception.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.flash">
- <title>Von Flash aus auf den Server verbinden</title>
- <para>
- Auf den <classname>Zend_Amf_Server</classname> vom Flash Projekt aus zu verbinden ist
- etwas anders als von Flex aus. Trotzdem sind die Funktionen mit
- <classname>Zend_Amf_Server</classname> die gleichen wie mit Flex sobald die Verbindung
- erstellt wurde. Das folgende Beispiel kann auch von einer Flex <acronym>AS3</acronym>
- Datei aus verwendet werden. Wir werden die selbe <classname>Zend_Amf_Server</classname>
- Konfiguration mit der World Klasse unserer Verbindung wiederverwenden.
- </para>
- <para>
- Öffne Flash CS und erstelle eine neue Flash Datei (ActionScript 3). Benenne das
- Dokument <filename>ZendExample.fla</filename> und speichere das Dokument in einem
- Verzeichnis das wir für dieses Beispiel verwenden werden. Erstelle eine neue
- <acronym>AS3</acronym> Datei im selben Verzeichnis und benenne die Datei
- <filename>Main.as</filename>. Öffne beide Dateien im Editor. Wir werden jetzt diese
- zwei Dateien über die Document Klasse verbinden. Wähle ZendExample aus und klicke auf
- "stage". Im Eigenschaftsfenster von "stage" ändere die Document Klasse auf Main. Das
- verbindet die <filename>Main.as</filename> ActionScript Datei mit dem Benutzer
- Interface von <filename>ZendExample.fla</filename>. Wenn die Flashdatei ZendExample
- ausgeführt wird, dann wird die Klasse <filename>Main.as</filename> gestartet. Als
- nächstes werden wir ein ActionScript hinzufügen um den <acronym>AMF</acronym> Aufruf
- durchzuführen.
- </para>
- <para>
- Jetzt werden wir eine Main Klasse erstellen damit wir die Daten zum Server schicken und
- das Ergebnis anzeigen lassen können. Kopiere den folgenden Code in die
- <filename>Main.as</filename> Datei und wird werden den Code anschauen um zu erklären
- was die Rolle eines jeden Elements ist.
- </para>
- <programlisting language="as"><![CDATA[
- package {
- import flash.display.MovieClip;
- import flash.events.*;
- import flash.net.NetConnection;
- import flash.net.Responder;
- public class Main extends MovieClip {
- private var gateway:String = "http://example.com/server.php";
- private var connection:NetConnection;
- private var responder:Responder;
- public function Main() {
- responder = new Responder(onResult, onFault);
- connection = new NetConnection;
- connection.connect(gateway);
- }
- public function onComplete( e:Event ):void{
- var params = "Zum Server geschickt";
- connection.call("World.hello", responder, params);
- }
- private function onResult(result:Object):void {
- // Die zurückgegebenen Daten anzeigen
- trace(String(result));
- }
- private function onFault(fault:Object):void {
- trace(String(fault.description));
- }
- }
- }
- ]]></programlisting>
- <para>
- Wir müssen zuerst zwei ActionScript Bibliotheken importieren die den Haufen an Arbeit
- erledigen. Das erste ist NetConnection welches wie eine Zweiwege-Leitung, zwischen dem
- Client und dem Server, funktioniert. Das zweite ist ein Responder Objekt welches die
- Rückgabewerte des Servers behandelt relativ zum Erfolg oder Mißerfolg des Aufrufs.
- </para>
- <programlisting language="as"><![CDATA[
- import flash.net.NetConnection;
- import flash.net.Responder;
- ]]></programlisting>
- <para>
- In der Klasse benötigen wir drei Variable um NetConnection, Responder, und die Gateway
- <acronym>URL</acronym> zu unserer <classname>Zend_Amf_Server</classname> Installation
- zu repräsentieren.
- </para>
- <programlisting language="as"><![CDATA[
- private var gateway:String = "http://example.com/server.php";
- private var connection:NetConnection;
- private var responder:Responder;
- ]]></programlisting>
- <para>
- Im Main Contructor erstellen wir einen Responder und eine neue Verbindung zum
- <classname>Zend_Amf_Server</classname> Endpunkt. Der Responder definiert zwei
- unterschiedliche Methoden für die Behandlung des Servers. Der Einfachheit halber haben
- wir Sie onResult und onFault benannt.
- </para>
- <programlisting language="as"><![CDATA[
- responder = new Responder(onResult, onFault);
- connection = new NetConnection;
- connection.connect(gateway);
- ]]></programlisting>
- <para>
- In der onComplete Funktion, welche ausgeführt wird sobald das Konstrukt fertiggestellt
- wurde, senden wir die Daten zum Server. Wird benötigen eine weitere zusätzliche Zeile
- die den Aufruf der <classname>Zend_Amf_Server</classname> World->hello Funktion
- durchführt.
- </para>
- <programlisting language="as"><![CDATA[
- connection.call("World.hello", responder, params);
- ]]></programlisting>
- <para>
- Als wir die Responder Variable erstellt haben, haben wir auch eine onResult und eine
- onFault Funktion definiert welche die Antwort des Servers behandeln. Wir haben diese
- Funktionen für ein erfolgreiches Ergebnis der Servers hunzugefügt. Ein erfolgreicher
- Eventhandler wird immer dann ausgeführt wenn die Verbindung zum Server richtig
- handgehabt wird.
- </para>
- <programlisting language="as"><![CDATA[
- private function onResult(result:Object):void {
- // Display the returned data
- trace(String(result));
- }
- ]]></programlisting>
- <para>
- Die onFault Funktion wird aufgerufen wenn eine ungültige Antwort vom Server
- zurückgekommen ist. Das passiert wenn auf dem Server ein Fehler stattgefunden hat, die
- <acronym>URL</acronym> zum Server ungültig ist, der entfernte Service oder die Methode
- nicht existiert, und bei jedem anderen Verbindungsrelevanten Problem.
- </para>
- <programlisting language="as"><![CDATA[
- private function onFault(fault:Object):void {
- trace(String(fault.description));
- }
- ]]></programlisting>
- <para>
- Das ActionScripts für die Erstellung der entfernten Verbindung ist jetzt fertiggestellt.
- Der Aufruf der ZendExample Datei führt jetzt die Verbindung zu
- <classname>Zend_Amf</classname> aus. Rückblickend haben wir die benötigten Variablen
- hinzugefügt um eine Verbindung zum entfernten Server zu öffnen, definiert welche
- Methoden in der Anwendung verwendet werden sollen wenn die Anwendung eine Antwort vom
- Server empfängt, und schlußendlich die Anzeige der zurückgegebenen Daten über
- <methodname>trace()</methodname>.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.auth">
- <title>Authentication</title>
- <para>
- <classname>Zend_Amf_Server</classname> erlaubt es Authentifizierung und Authorisierungs-
- Hooks zu spezifizieren um den Zugriff auf Services zu kontrollieren. Es wird die
- Infrastruktur verwendet die von den
- <link linkend="zend.auth"><classname>Zend_Auth</classname></link> und
- <link linkend="zend.acl"><classname>Zend_Acl</classname></link> Komponenten angeboten
- wird.
- </para>
- <para>
- Um Authentifizierung zu definieren, muß der Benutzer einen Authentifizierungs-Adapter
- anbieten der die abstrakte Klasse <classname>Zend_Amf_Auth_Abstract</classname>
- erweitert. Der Adapter sollte die <methodname>authenticate()</methodname> Methode
- implementieren so wie jeder normale
- <link linkend="zend.auth.introduction.adapters">Authentifizierungs-Adapter</link>.
- </para>
- <para>
- Der Adapter sollte die Eigenschaften <emphasis>_username</emphasis> und
- <emphasis>_password</emphasis> von der Vorgängerklasse
- <classname>Zend_Amf_Auth_Abstract</classname> verwenden um authentifizieren zu können.
- Diese Werte werden vom Server gesetzt, indem die
- <methodname>setCredentials()</methodname> Methode verwendet wird, bevor
- <methodname>authenticate()</methodname> aufgerufen wird wenn die Zugangsdaten in den
- <acronym>AMF</acronym> Anfrage-Headern empfangen wurden.
- </para>
- <para>
- Die Identität die vom Adapter zurückgegeben wird sollte ein Objekt sein das die
- Eigenschaft <property>role</property> enthält damit die Zugriffskontrolle von
- <acronym>ACL</acronym> funktioniert.
- </para>
- <para>
- Wenn das Authentifizierungs Ergebnis nicht erfolgreich war, wird die Anfrage nicht
- weiter bearbeitet und eine Fehlermeldung wird zurückgegeben mit den Gründen für den
- Fehlschlag genommen vom Ergebnis
- </para>
- <para>
- Der Adapter wird zum Server verbunden indem die <methodname>setAuth()</methodname>
- Methode verwendet wird:
- </para>
- <programlisting language="php"><![CDATA[
- $server->setAuth(new My_Amf_Auth());
- ]]></programlisting>
- <para>
- Die Zugriffskontrolle wird durchgeführt indem das <classname>Zend_Acl</classname>
- Objekt verwendet wird das von der <methodname>setAcl()</methodname> Methode gesetzt
- wurde:
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- createPermissions($acl); // Zugriffs-Struktur erstellen
- $server->setAcl($acl);
- ]]></programlisting>
- <para>
- Wenn das <acronym>ACL</acronym> Objekt gesetzt ist, und die Klasse die aufgerufen wird
- die <methodname>initAcl()</methodname> Methode definiert wird diese Methode, mit dem
- <acronym>ACL</acronym> Objekt als Argument, aufgerufen. Die Klasse kann dann
- zusätzliche <acronym>ACL</acronym> Regeln erstellen und <constant>TRUE</constant>
- zurückgeben, oder <constant>FALSE</constant> wenn keine Zugriffskontrolle für diese
- Klasse benötigt wird.
- </para>
- <para>
- Nachdem die <acronym>ACL</acronym> gesetzt wurde, wird der Server prüfen ob mit der,
- von der Authentifizierung gesetzten, Rolle Zugriff erlaubt ist, die Ressource im
- Klassennamen ist (oder <constant>NULL</constant> für Funktionsaufrufe) und ob die
- Privilegien der Funktionsname sind. Wenn keine Authentifizierung angegeben wurde, wird
- die <emphasis>anonymous</emphasis> verwendet, wenn diese definiert wurde, andernfalls
- wird der Zugriff verweigert.
- </para>
- <programlisting language="php"><![CDATA[
- if($this->_acl->isAllowed($role, $class, $function)) {
- return true;
- } else {
- require_once 'Zend/Amf/Server/Exception.php';
- throw new Zend_Amf_Server_Exception("Access not allowed");
- }
- ]]></programlisting>
- </sect2>
- </sect1>
|