Zend_Amf-Server.xml 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="zend.amf.server">
  4. <title>Zend_Amf_Server</title>
  5. <para>
  6. <classname>Zend_Amf_Server</classname> provides an <acronym>RPC</acronym>-style server for
  7. handling requests made from the Adobe Flash Player using the <acronym>AMF</acronym>
  8. protocol. Like all Zend Framework server classes, it follows the SoapServer
  9. <acronym>API</acronym>, providing an easy to remember interface for creating servers.
  10. </para>
  11. <example id="zend.amf.server.basic">
  12. <title>Basic AMF Server</title>
  13. <para>
  14. Let's assume that you have created a class <classname>Foo</classname> with a
  15. variety of public methods. You may create an <acronym>AMF</acronym> server using the
  16. following code:
  17. </para>
  18. <programlisting language="php"><![CDATA[
  19. $server = new Zend_Amf_Server();
  20. $server->setClass('Foo');
  21. $response = $server->handle();
  22. echo $response;
  23. ]]></programlisting>
  24. <para>
  25. Alternately, you may choose to attach a simple function as a
  26. callback instead:
  27. </para>
  28. <programlisting language="php"><![CDATA[
  29. $server = new Zend_Amf_Server();
  30. $server->addFunction('myUberCoolFunction');
  31. $response = $server->handle();
  32. echo $response;
  33. ]]></programlisting>
  34. <para>
  35. You could also mix and match multiple classes and functions. When
  36. doing so, we suggest namespacing each to ensure that no method name
  37. collisions occur; this can be done by simply passing a second string
  38. argument to either <methodname>addFunction()</methodname> or
  39. <methodname>setClass()</methodname>:
  40. </para>
  41. <programlisting language="php"><![CDATA[
  42. $server = new Zend_Amf_Server();
  43. $server->addFunction('myUberCoolFunction', 'my')
  44. ->setClass('Foo', 'foo')
  45. ->setClass('Bar', 'bar');
  46. $response = $server->handle();
  47. echo $response;
  48. ]]></programlisting>
  49. <para>
  50. The <classname>Zend_Amf_Server</classname> also allows services to be dynamically
  51. loaded based on a supplied directory path. You may add as many directories as you wish
  52. to the server. The order that you add the directories to the server will be the
  53. order that the <acronym>LIFO</acronym> search will be performed on the directories to
  54. match the class. Adding directories is completed with the
  55. <methodname>addDirectory()</methodname> method.
  56. </para>
  57. <programlisting language="php"><![CDATA[
  58. $server->addDirectory(dirname(__FILE__) .'/../services/');
  59. $server->addDirectory(dirname(__FILE__) .'/../package/');
  60. ]]></programlisting>
  61. <para>
  62. When calling remote services your source name can have underscore ("_") and dot (".")
  63. directory delimiters. When an underscore is used <acronym>PEAR</acronym> and Zend
  64. Framework class naming conventions will be respected. This means that if you call the
  65. service com_Foo_Bar the server will look for the file
  66. <filename>Bar.php</filename> in the each of the included paths at
  67. <filename>com/Foo/Bar.php</filename>. If the dot notation is used for your remote
  68. service such as <filename>com.Foo.Bar</filename> each included path will have
  69. <filename>com/Foo/Bar.php</filename> append to the end to autoload
  70. <filename>Bar.php</filename>
  71. </para>
  72. <para>
  73. All <acronym>AMF</acronym> requests sent to the script will then be handled by the
  74. server, and an <acronym>AMF</acronym> response will be returned.
  75. </para>
  76. </example>
  77. <note>
  78. <title>All Attached Methods and Functions Need Docblocks</title>
  79. <para>
  80. Like all other server components in Zend Framework, you must document your class
  81. methods using <acronym>PHP</acronym> docblocks. At the minimum, you
  82. need to provide annotations for each required argument as well as
  83. the return value. As examples:
  84. </para>
  85. <programlisting language="php"><![CDATA[
  86. // Function to attach:
  87. /**
  88. * @param string $name
  89. * @param string $greeting
  90. * @return string
  91. */
  92. function helloWorld($name, $greeting = 'Hello')
  93. {
  94. return $greeting . ', ' . $name;
  95. }
  96. ]]></programlisting>
  97. <programlisting language="php"><![CDATA[
  98. // Attached class
  99. class World
  100. {
  101. /**
  102. * @param string $name
  103. * @param string $greeting
  104. * @return string
  105. */
  106. public function hello($name, $greeting = 'Hello')
  107. {
  108. return $greeting . ', ' . $name;
  109. }
  110. }
  111. ]]></programlisting>
  112. <para>
  113. Other annotations may be used, but will be ignored.
  114. </para>
  115. </note>
  116. <sect2 id="zend.amf.server.flex">
  117. <title>Connecting to the Server from Flex</title>
  118. <para>
  119. Connecting to your <classname>Zend_Amf_Server</classname> from your Flex
  120. project is quite simple; you simply need to point your endpoint <acronym>URI</acronym>
  121. to your <classname>Zend_Amf_Server</classname> script.
  122. </para>
  123. <para>
  124. Say, for instance, you have created your server and placed it in the
  125. <filename>server.php</filename> file in your application root, and thus the
  126. <acronym>URI</acronym> is <filename>http://example.com/server.php</filename>. In this
  127. case, you would modify your <filename>services-config.xml</filename> file to set the
  128. channel endpoint uri attribute to this value.
  129. </para>
  130. <para>
  131. If you have never created a <filename>service-config.xml</filename> file you can do so
  132. by opening your project in your Navigator window. Right click on the project name and
  133. select 'properties'. In the Project properties dialog go into 'Flex Build Path' menu,
  134. 'Library path' tab and be sure the '<filename>rpc.swc</filename>' file is added to your
  135. projects path and Press Ok to close the window.
  136. </para>
  137. <para>
  138. You will also need to tell the compiler to use the
  139. <filename>service-config.xml</filename> to find the RemoteObject endpoint. To do this
  140. open your project properties panel again by right clicking on the project folder from
  141. your Navigator and selecting properties. From the properties popup select 'Flex
  142. Compiler' and add the string: <command>-services "services-config.xml"</command>. Press
  143. Apply then OK to return to update the option. What you have just done is told the Flex
  144. compiler to look to the <filename>services-config.xml</filename> file for runtime
  145. variables that will be used by the RemotingObject class.
  146. </para>
  147. <para>
  148. We now need to tell Flex which services configuration file to use for connecting to
  149. our remote methods. For this reason create a new
  150. '<filename>services-config.xml</filename>' file into your Flex project src folder. To
  151. do this right click on the project folder and select 'new' 'File' which will popup a
  152. new window. Select the project folder and then name the file
  153. '<filename>services-config.xml</filename>' and press finish.
  154. </para>
  155. <para>
  156. Flex has created the new <filename>services-config.xml</filename> and has it open. Use
  157. the following example text for your <filename>services-config.xml</filename> file. Make
  158. sure that you update your endpoint to match that of your testing server. Make sure you
  159. save the file.
  160. </para>
  161. <programlisting language="xml"><![CDATA[
  162. <?xml version="1.0" encoding="UTF-8"?>
  163. <services-config>
  164. <services>
  165. <service id="zend-service"
  166. class="flex.messaging.services.RemotingService"
  167. messageTypes="flex.messaging.messages.RemotingMessage">
  168. <destination id="zend">
  169. <channels>
  170. <channel ref="zend-endpoint"/>
  171. </channels>
  172. <properties>
  173. <source>*</source>
  174. </properties>
  175. </destination>
  176. </service>
  177. </services>
  178. <channels>
  179. <channel-definition id="zend-endpoint"
  180. class="mx.messaging.channels.AMFChannel">
  181. <endpoint uri="http://example.com/server.php"
  182. class="flex.messaging.endpoints.AMFEndpoint"/>
  183. </channel-definition>
  184. </channels>
  185. </services-config>
  186. ]]></programlisting>
  187. <para>
  188. There are two key points in the example. First, but last in the
  189. listing, we create an <acronym>AMF</acronym> channel, and specify the endpoint as the
  190. <acronym>URL</acronym> to our <classname>Zend_Amf_Server</classname>:
  191. </para>
  192. <programlisting language="xml"><![CDATA[
  193. <channel-definition id="zend-endpoint"
  194. <endpoint uri="http://example.com/server.php"
  195. class="flex.messaging.endpoints.AMFEndpoint"/>
  196. </channel-definition>
  197. ]]></programlisting>
  198. <para>
  199. Notice that we've given this channel an identifier, "zend-endpoint".
  200. The example create a service destination that refers to this channel,
  201. assigning it an ID as well -- in this case "zend".
  202. </para>
  203. <para>
  204. Within our Flex <acronym>MXML</acronym> files, we need to bind a RemoteObject to the
  205. service. In <acronym>MXML</acronym>, this might be done as follows:
  206. </para>
  207. <programlisting language="xml"><![CDATA[
  208. <mx:RemoteObject id="myservice"
  209. fault="faultHandler(event)"
  210. showBusyCursor="true"
  211. destination="zend">
  212. ]]></programlisting>
  213. <para>
  214. Here, we've defined a new remote object identified by "myservice"
  215. bound to the service destination "zend" we defined in the
  216. <filename>services-config.xml</filename> file. We then call methods on it
  217. in our ActionScript by simply calling "myservice.&lt;method&gt;".
  218. As an example:
  219. </para>
  220. <programlisting language="ActionScript"><![CDATA[
  221. myservice.hello("Wade");
  222. ]]></programlisting>
  223. <para>
  224. When namespacing, you would use
  225. "myservice.&lt;namespace&gt;.&lt;method&gt;":
  226. </para>
  227. <programlisting language="ActionScript"><![CDATA[
  228. myservice.world.hello("Wade");
  229. ]]></programlisting>
  230. <para>
  231. For more information on Flex RemoteObject invocation, <ulink
  232. url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
  233. visit the Adobe Flex 3 Help site</ulink>.
  234. </para>
  235. </sect2>
  236. <sect2 id="zend.amf.server.errors">
  237. <title>Error Handling</title>
  238. <para>
  239. By default, all exceptions thrown in your attached classes or
  240. functions will be caught and returned as <acronym>AMF</acronym> ErrorMessages. However,
  241. the content of these ErrorMessage objects will vary based on whether
  242. or not the server is in "production" mode (the default state).
  243. </para>
  244. <para>
  245. When in production mode, only the exception code will be returned.
  246. If you disable production mode -- something that should be done for
  247. testing only -- most exception details will be returned: the
  248. exception message, line, and backtrace will all be attached.
  249. </para>
  250. <para>
  251. To disable production mode, do the following:
  252. </para>
  253. <programlisting language="php"><![CDATA[
  254. $server->setProduction(false);
  255. ]]></programlisting>
  256. <para>
  257. To re-enable it, pass a <constant>TRUE</constant> boolean value instead:
  258. </para>
  259. <programlisting language="php"><![CDATA[
  260. $server->setProduction(true);
  261. ]]></programlisting>
  262. <note>
  263. <title>Disable production mode sparingly!</title>
  264. <para>
  265. We recommend disabling production mode only when in development.
  266. Exception messages and backtraces can contain sensitive system
  267. information that you may not wish for outside parties to access.
  268. Even though <acronym>AMF</acronym> is a binary format, the specification is now
  269. open, meaning anybody can potentially deserialize the payload.
  270. </para>
  271. </note>
  272. <para>
  273. One area to be especially careful with is <acronym>PHP</acronym> errors themselves.
  274. When the <property>display_errors</property> <acronym>INI</acronym> directive is
  275. enabled, any <acronym>PHP</acronym> errors for the current error reporting level are
  276. rendered directly in the output -- potentially disrupting the <acronym>AMF</acronym>
  277. response payload. We suggest turning off the <property>display_errors</property>
  278. directive in production to prevent such problems
  279. </para>
  280. </sect2>
  281. <sect2 id="zend.amf.server.response">
  282. <title>AMF Responses</title>
  283. <para>
  284. Occasionally you may desire to manipulate the response object
  285. slightly, typically to return extra message headers. The
  286. <methodname>handle()</methodname> method of the server returns the response
  287. object, allowing you to do so.
  288. </para>
  289. <example id="zend.amf.server.response.messageHeaderExample">
  290. <title>Adding Message Headers to the AMF Response</title>
  291. <para>
  292. In this example, we add a 'foo' MessageHeader with the value
  293. 'bar' to the response prior to returning it.
  294. </para>
  295. <programlisting language="php"><![CDATA[
  296. $response = $server->handle();
  297. $response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  298. echo $response;
  299. ]]></programlisting>
  300. </example>
  301. </sect2>
  302. <sect2 id="zend.amf.server.typedobjects">
  303. <title>Typed Objects</title>
  304. <para>
  305. Similar to <acronym>SOAP</acronym>, <acronym>AMF</acronym> allows passing objects
  306. between the client and server. This allows a great amount of flexibility and
  307. coherence between the two environments.
  308. </para>
  309. <para>
  310. <classname>Zend_Amf</classname> provides three methods for mapping
  311. ActionScript and <acronym>PHP</acronym> objects.
  312. </para>
  313. <itemizedlist>
  314. <listitem>
  315. <para>
  316. First, you may create explicit bindings at the server level,
  317. using the <methodname>setClassMap()</methodname> method. The first
  318. argument is the ActionScript class name, the second the <acronym>PHP</acronym>
  319. class name it maps to:
  320. </para>
  321. <programlisting language="php"><![CDATA[
  322. // Map the ActionScript class 'ContactVO' to the PHP class 'Contact':
  323. $server->setClassMap('ContactVO', 'Contact');
  324. ]]></programlisting>
  325. </listitem>
  326. <listitem>
  327. <para>
  328. Second, you can set the public property <varname>$_explicitType</varname>
  329. in your <acronym>PHP</acronym> class, with the
  330. value representing the ActionScript class to map to:
  331. </para>
  332. <programlisting language="php"><![CDATA[
  333. class Contact
  334. {
  335. public $_explicitType = 'ContactVO';
  336. }
  337. ]]></programlisting>
  338. </listitem>
  339. <listitem>
  340. <para>
  341. Third, in a similar vein, you may define the public method
  342. <methodname>getASClassName()</methodname> in your <acronym>PHP</acronym> class;
  343. this method should return the appropriate ActionScript class:
  344. </para>
  345. <programlisting language="php"><![CDATA[
  346. class Contact
  347. {
  348. public function getASClassName()
  349. {
  350. return 'ContactVO';
  351. }
  352. }
  353. ]]></programlisting>
  354. </listitem>
  355. </itemizedlist>
  356. <para>
  357. Although we have created the ContactVO on the server we now need to make its
  358. corresponding class in <acronym>AS3</acronym> for the server object to be mapped to.
  359. </para>
  360. <para>
  361. Right click on the src folder of the Flex project and select New -> ActionScript
  362. File. Name the file ContactVO and press finish to see the new file. Copy the
  363. following code into the file to finish creating the class.
  364. </para>
  365. <programlisting language="as"><![CDATA[
  366. package
  367. {
  368. [Bindable]
  369. [RemoteClass(alias="ContactVO")]
  370. public class ContactVO
  371. {
  372. public var id:int;
  373. public var firstname:String;
  374. public var lastname:String;
  375. public var email:String;
  376. public var mobile:String;
  377. public function ProductVO():void {
  378. }
  379. }
  380. }
  381. ]]></programlisting>
  382. <para>
  383. The class is syntactically equivalent to the <acronym>PHP</acronym> of the same name.
  384. The variable names are exactly the same and need to be in the same case
  385. to work properly. There are two unique <acronym>AS3</acronym> meta tags in this class.
  386. The first is bindable which makes fire a change event when it is updated.
  387. The second tag is the RemoteClass tag which defines that this class can
  388. have a remote object mapped with the alias name in this case
  389. <emphasis>ContactVO</emphasis>. It is mandatory that this tag the value that was set
  390. is the <acronym>PHP</acronym> class are strictly equivalent.
  391. </para>
  392. <programlisting language="as"><![CDATA[
  393. [Bindable]
  394. private var myContact:ContactVO;
  395. private function getContactHandler(event:ResultEvent):void {
  396. myContact = ContactVO(event.result);
  397. }
  398. ]]></programlisting>
  399. <para>
  400. The following result event from the service call is cast instantly onto the Flex
  401. ContactVO. Anything that is bound to myContact will be updated with the returned
  402. ContactVO data.
  403. </para>
  404. </sect2>
  405. <sect2 id="zend.amf.server.resources">
  406. <title>Resources</title>
  407. <para>
  408. <classname>Zend_Amf</classname> provides tools for mapping resource types
  409. returned by service classes into data consumable by ActionScript.
  410. </para>
  411. <para>
  412. In order to handle specific resource type, the user needs to create a plugin class named
  413. after the resource name, with words capitalized and spaces removed (so, resource
  414. type "mysql result" becomes MysqlResult), with some prefix, e.g.
  415. <classname>My_MysqlResult</classname>. This class should implement one method,
  416. <methodname>parse()</methodname>, receiving one argument - the resource - and returning
  417. the value that should be sent to ActionScript. The class should be located in the file
  418. named after the last component of the name, e.g. <filename>MysqlResult.php</filename>.
  419. </para>
  420. <para>
  421. The directory containing the resource handling plugins should be registered with
  422. <classname>Zend_Amf</classname> type loader:
  423. </para>
  424. <programlisting language="php"><![CDATA[
  425. Zend_Amf_Parse_TypeLoader::addResourceDirectory(
  426. "My",
  427. "application/library/resources/My"
  428. );
  429. ]]></programlisting>
  430. <para>
  431. For detailed discussion of loading plugins, please see
  432. the <link linkend="zend.loader.pluginloader">plugin loader</link> section.
  433. </para>
  434. <para>
  435. Default directory for <classname>Zend_Amf</classname> resources is registered
  436. automatically and currently contains handlers for "mysql result" and "stream"
  437. resources.
  438. </para>
  439. <programlisting language="php"><![CDATA[
  440. // Example class implementing handling resources of type mysql result
  441. class Zend_Amf_Parse_Resource_MysqlResult
  442. {
  443. /**
  444. * Parse resource into array
  445. *
  446. * @param resource $resource
  447. * @return array
  448. */
  449. public function parse($resource) {
  450. $result = array();
  451. while($row = mysql_fetch_assoc($resource)) {
  452. $result[] = $row;
  453. }
  454. return $result;
  455. }
  456. }
  457. ]]></programlisting>
  458. <para>
  459. Trying to return unknown resource type (i.e., one for which no handler plugin exists)
  460. will result in an exception.
  461. </para>
  462. </sect2>
  463. <sect2 id="zend.amf.server.flash">
  464. <title>Connecting to the Server from Flash</title>
  465. <para>
  466. Connecting to your <classname>Zend_Amf_Server</classname> from your Flash project is
  467. slightly different than from Flex. However once the connection Flash functions with
  468. <classname>Zend_Amf_Server</classname> the same way is flex. The following example can
  469. also be used from a Flex <acronym>AS3</acronym> file. We will reuse the same
  470. <classname>Zend_Amf_Server</classname> configuration along with the World class for our
  471. connection.
  472. </para>
  473. <para>
  474. Open Flash CS and create and new Flash File (ActionScript 3). Name the document
  475. <filename>ZendExample.fla</filename> and save the document into a folder that you will
  476. use for this example. Create a new <acronym>AS3</acronym> file in the same directory
  477. and call the file <filename>Main.as</filename>. Have both files open in your editor. We
  478. are now going to connect the two files via the document class. Select ZendExample and
  479. click on the stage. From the stage properties panel change the Document class to Main.
  480. This links the <filename>Main.as</filename> ActionScript file with the user interface
  481. in <filename>ZendExample.fla</filename>. When you run the Flash file ZendExample the
  482. <filename>Main.as</filename> class will now be run. Next we will add ActionScript to
  483. make the <acronym>AMF</acronym> call.
  484. </para>
  485. <para>
  486. We now are going to make a Main class so that we can send the data to the server and
  487. display the result. Copy the following code into your <filename>Main.as</filename> file
  488. and then we will walk through the code to describe what each element's role is.
  489. </para>
  490. <programlisting language="as"><![CDATA[
  491. package {
  492. import flash.display.MovieClip;
  493. import flash.events.*;
  494. import flash.net.NetConnection;
  495. import flash.net.Responder;
  496. public class Main extends MovieClip {
  497. private var gateway:String = "http://example.com/server.php";
  498. private var connection:NetConnection;
  499. private var responder:Responder;
  500. public function Main() {
  501. responder = new Responder(onResult, onFault);
  502. connection = new NetConnection;
  503. connection.connect(gateway);
  504. }
  505. public function onComplete( e:Event ):void{
  506. var params = "Sent to Server";
  507. connection.call("World.hello", responder, params);
  508. }
  509. private function onResult(result:Object):void {
  510. // Display the returned data
  511. trace(String(result));
  512. }
  513. private function onFault(fault:Object):void {
  514. trace(String(fault.description));
  515. }
  516. }
  517. }
  518. ]]></programlisting>
  519. <para>
  520. We first need to import two ActionScript libraries that perform the bulk of the work.
  521. The first is NetConnection which acts like a by directional pipe between the client and
  522. the server. The second is a Responder object which handles the return values from the
  523. server related to the success or failure of the call.
  524. </para>
  525. <programlisting language="as"><![CDATA[
  526. import flash.net.NetConnection;
  527. import flash.net.Responder;
  528. ]]></programlisting>
  529. <para>
  530. In the class we need three variables to represent the NetConnection, Responder, and
  531. the gateway <acronym>URL</acronym> to our <classname>Zend_Amf_Server</classname>
  532. installation.
  533. </para>
  534. <programlisting language="as"><![CDATA[
  535. private var gateway:String = "http://example.com/server.php";
  536. private var connection:NetConnection;
  537. private var responder:Responder;
  538. ]]></programlisting>
  539. <para>
  540. In the Main constructor we create a responder and a new connection to the
  541. <classname>Zend_Amf_Server</classname> endpoint. The responder defines two different
  542. methods for handling the response from the server. For simplicity I have called these
  543. onResult and onFault.
  544. </para>
  545. <programlisting language="as"><![CDATA[
  546. responder = new Responder(onResult, onFault);
  547. connection = new NetConnection;
  548. connection.connect(gateway);
  549. ]]></programlisting>
  550. <para>
  551. In the onComplete function which is run as soon as the construct has completed we send
  552. the data to the server. We need to add one more line that makes a call to the
  553. <classname>Zend_Amf_Server</classname> World->hello function.
  554. </para>
  555. <programlisting language="as"><![CDATA[
  556. connection.call("World.hello", responder, params);
  557. ]]></programlisting>
  558. <para>
  559. When we created the responder variable we defined an onResult and onFault function to
  560. handle the response from the server. We added this function for the successful result
  561. from the server. A successful event handler is run every time the connection is handled
  562. properly to the server.
  563. </para>
  564. <programlisting language="as"><![CDATA[
  565. private function onResult(result:Object):void {
  566. // Display the returned data
  567. trace(String(result));
  568. }
  569. ]]></programlisting>
  570. <para>
  571. The onFault function, is called if there was an invalid response from the server. This
  572. happens when there is an error on the server, the <acronym>URL</acronym> to the server
  573. is invalid, the remote service or method does not exist, and any other connection
  574. related issues.
  575. </para>
  576. <programlisting language="as"><![CDATA[
  577. private function onFault(fault:Object):void {
  578. trace(String(fault.description));
  579. }
  580. ]]></programlisting>
  581. <para>
  582. Adding in the ActionScript to make the remoting connection is now complete. Running the
  583. ZendExample file now makes a connection to <classname>Zend_Amf</classname>. In review
  584. you have added the required variables to open a connection to the remote server, defined
  585. what methods should be used when your application receives a response from the server,
  586. and finally displayed the returned data to output via <methodname>trace()</methodname>.
  587. </para>
  588. </sect2>
  589. <sect2 id="zend.amf.server.auth">
  590. <title>Authentication</title>
  591. <para>
  592. <classname>Zend_Amf_Server</classname> allows you to specify authentication and
  593. authorization hooks to control access to the services. It is using the infrastructure
  594. provided by <link linkend="zend.auth"><classname>Zend_Auth</classname></link> and
  595. <link linkend="zend.acl"><classname>Zend_Acl</classname></link> components.
  596. </para>
  597. <para>
  598. In order to define authentication, the user provides authentication adapter extening
  599. <classname>Zend_Amf_Auth_Abstract</classname> abstract class. The adapter should
  600. implement the <methodname>authenticate()</methodname> method just like regular
  601. <link linkend="zend.auth.introduction.adapters">authentication adapter</link>.
  602. </para>
  603. <para>
  604. The adapter should use properties <emphasis>_username</emphasis> and
  605. <emphasis>_password</emphasis> from the parent
  606. <classname>Zend_Amf_Auth_Abstract</classname> class in order to authenticate. These
  607. values are set by the server using <methodname>setCredentials()</methodname> method
  608. before call to <methodname>authenticate()</methodname> if the credentials are received
  609. in the <acronym>AMF</acronym> request headers.
  610. </para>
  611. <para>
  612. The identity returned by the adapter should be an object containing property
  613. <property>role</property> for the <acronym>ACL</acronym> access control to work.
  614. </para>
  615. <para>
  616. If the authentication result is not successful, the request is not proceseed further
  617. and failure message is returned with the reasons for failure taken from the result.
  618. </para>
  619. <para>
  620. The adapter is connected to the server using <methodname>setAuth()</methodname> method:
  621. </para>
  622. <programlisting language="php"><![CDATA[
  623. $server->setAuth(new My_Amf_Auth());
  624. ]]></programlisting>
  625. <para>
  626. Access control is performed by using <classname>Zend_Acl</classname> object set by
  627. <methodname>setAcl()</methodname> method:
  628. </para>
  629. <programlisting language="php"><![CDATA[
  630. $acl = new Zend_Acl();
  631. createPermissions($acl); // create permission structure
  632. $server->setAcl($acl);
  633. ]]></programlisting>
  634. <para>
  635. If the <acronym>ACL</acronym> object is set, and the class being called defines
  636. <methodname>initAcl()</methodname> method, this method will be called with the
  637. <acronym>ACL</acronym> object as an argument. The class then can create additional
  638. <acronym>ACL</acronym> rules and return <constant>TRUE</constant>, or return
  639. <constant>FALSE</constant> if no access control is required for this class.
  640. </para>
  641. <para>
  642. After <acronym>ACL</acronym> have been set up, the server will check if access is
  643. allowed with role set by the authentication, resource being the class name (or
  644. <constant>NULL</constant> for
  645. function calls) and privilege being the function name. If no authentication was
  646. provided, then if the <emphasis>anonymous</emphasis> role was defined, it will be used,
  647. otherwise the access will be denied.
  648. </para>
  649. <programlisting language="php"><![CDATA[
  650. if($this->_acl->isAllowed($role, $class, $function)) {
  651. return true;
  652. } else {
  653. require_once 'Zend/Amf/Server/Exception.php';
  654. throw new Zend_Amf_Server_Exception("Access not allowed");
  655. }
  656. ]]></programlisting>
  657. </sect2>
  658. </sect1>
  659. <!--
  660. vim:se ts=4 sw=4 et:
  661. -->