AmfphpFlexMessaging.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * This file is part of amfPHP
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the license that is bundled
  8. * with this package in the file license.txt.
  9. */
  10. /**
  11. * includes
  12. * */
  13. require_once dirname(__FILE__) . '/AcknowledgeMessage.php';
  14. require_once dirname(__FILE__) . '/ErrorMessage.php';
  15. /**
  16. * Support for flex messaging.
  17. *
  18. * This plugin can be deactivated if the project doesn't need flex messaging, usually a RemoteObject in Flex.
  19. *
  20. * Flex doesn't use the basic packet system. When using a remote objct, first a CommandMessage is sent, expecting an AcknowledgeMessage in return.
  21. * Then a RemotingMessage is sent, expecting an AcknowledgeMessage in return.
  22. * This plugin adds support for this message flow.
  23. *
  24. * In case of an error, an ErrorMessage is expected
  25. *
  26. * @link http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html
  27. * @package Amfphp_Plugins_FlexMessaging
  28. * @author Ariel Sommeria-Klein
  29. */
  30. class AmfphpFlexMessaging {
  31. const FLEX_TYPE_COMMAND_MESSAGE = 'flex.messaging.messages.CommandMessage';
  32. const FLEX_TYPE_REMOTING_MESSAGE = 'flex.messaging.messages.RemotingMessage';
  33. const FLEX_TYPE_ACKNOWLEDGE_MESSAGE = 'flex.messaging.messages.AcknowledgeMessage';
  34. const FLEX_TYPE_ERROR_MESSAGE = 'flex.messaging.messages.ErrorMessage';
  35. const FIELD_MESSAGE_ID = 'messageId';
  36. /**
  37. * if this is set, special error handling applies
  38. * @var Boolean
  39. */
  40. protected $clientUsesFlexMessaging;
  41. /**
  42. * the messageId of the last flex message. Used for error generation
  43. * @var String
  44. */
  45. protected $lastFlexMessageId;
  46. /**
  47. * the response uri of the last flex message. Used for error generation
  48. * @var String
  49. */
  50. protected $lastFlexMessageResponseUri;
  51. /**
  52. * return error details.
  53. * @see Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS
  54. * @var boolean
  55. */
  56. protected $returnErrorDetails = false;
  57. /**
  58. * constructor.
  59. * @param array $config optional key/value pairs in an associative array. Used to override default configuration values.
  60. */
  61. public function __construct(array $config = null) {
  62. Amfphp_Core_FilterManager::getInstance()->addFilter(Amfphp_Core_Amf_Handler::FILTER_AMF_REQUEST_MESSAGE_HANDLER, $this, 'filterAmfRequestMessageHandler');
  63. Amfphp_Core_FilterManager::getInstance()->addFilter(Amfphp_Core_Amf_Handler::FILTER_AMF_EXCEPTION_HANDLER, $this, 'filterAmfExceptionHandler');
  64. $this->clientUsesFlexMessaging = false;
  65. $this->returnErrorDetails = (isset($config[Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS]) && $config[Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS]);
  66. }
  67. /**
  68. * filter amf request message handler
  69. * @param Object $handler null at call. If the plugin takes over the handling of the request message,
  70. * it must set this to a proper handler for the message, probably itself.
  71. * @param Amfphp_Core_Amf_Message $requestMessage the request message
  72. * @return array
  73. */
  74. public function filterAmfRequestMessageHandler($handler, Amfphp_Core_Amf_Message $requestMessage) {
  75. if ($requestMessage->targetUri == 'null') {
  76. //target uri is null for Flex messaging, so it's an easy way to detect it. This plugin will handle it
  77. $this->clientUsesFlexMessaging = true;
  78. return $this;
  79. }
  80. }
  81. /**
  82. * filter amf exception handler
  83. * @param Object $handler null at call. If the plugin takes over the handling of the request message,
  84. * it must set this to a proper handler for the message, probably itself.
  85. * @return array
  86. */
  87. public function filterAmfExceptionHandler($handler) {
  88. if ($this->clientUsesFlexMessaging) {
  89. return $this;
  90. }
  91. }
  92. /**
  93. * handle the request message instead of letting the Amf Handler do it.
  94. * @param Amfphp_Core_Amf_Message $requestMessage
  95. * @param Amfphp_Core_Common_ServiceRouter $serviceRouter
  96. * @return Amfphp_Core_Amf_Message
  97. */
  98. public function handleRequestMessage(Amfphp_Core_Amf_Message $requestMessage, Amfphp_Core_Common_ServiceRouter $serviceRouter) {
  99. $explicitTypeField = Amfphp_Core_Amf_Constants::FIELD_EXPLICIT_TYPE;
  100. $messageType = $requestMessage->data[0]->$explicitTypeField;
  101. $messageIdField = self::FIELD_MESSAGE_ID;
  102. $this->lastFlexMessageId = $requestMessage->data[0]->$messageIdField;
  103. $this->lastFlexMessageResponseUri = $requestMessage->responseUri;
  104. if ($messageType == self::FLEX_TYPE_COMMAND_MESSAGE) {
  105. //command message. An empty AcknowledgeMessage is expected.
  106. $acknowledge = new AmfphpFlexMessaging_AcknowledgeMessage($requestMessage->data[0]->$messageIdField);
  107. return new Amfphp_Core_Amf_Message($requestMessage->responseUri . Amfphp_Core_Amf_Constants::CLIENT_SUCCESS_METHOD, null, $acknowledge);
  108. }
  109. if ($messageType == self::FLEX_TYPE_REMOTING_MESSAGE) {
  110. //remoting message. An AcknowledgeMessage with the result of the service call is expected.
  111. $remoting = $requestMessage->data[0];
  112. $serviceCallResult = $serviceRouter->executeServiceCall($remoting->source, $remoting->operation, $remoting->body);
  113. $acknowledge = new AmfphpFlexMessaging_AcknowledgeMessage($remoting->$messageIdField);
  114. $acknowledge->body = $serviceCallResult;
  115. return new Amfphp_Core_Amf_Message($requestMessage->responseUri . Amfphp_Core_Amf_Constants::CLIENT_SUCCESS_METHOD, null, $acknowledge);
  116. }
  117. throw new Amfphp_Core_Exception('unrecognized flex message');
  118. }
  119. /**
  120. * flex expects error messages formatted in a special way, using the ErrorMessage object.
  121. * @return Amfphp_Core_Amf_Packet
  122. * @param Exception $exception
  123. */
  124. public function generateErrorResponse(Exception $exception) {
  125. $error = new AmfphpFlexMessaging_ErrorMessage($this->lastFlexMessageId);
  126. $error->faultCode = $exception->getCode();
  127. $error->faultString = $exception->getMessage();
  128. if ($this->returnErrorDetails) {
  129. $error->faultDetail = $exception->getTraceAsString();
  130. $error->rootCause = $exception;
  131. }
  132. $errorMessage = new Amfphp_Core_Amf_Message($this->lastFlexMessageResponseUri . Amfphp_Core_Amf_Constants::CLIENT_FAILURE_METHOD, null, $error);
  133. $errorPacket = new Amfphp_Core_Amf_Packet();
  134. $errorPacket->messages[] = $errorMessage;
  135. return $errorPacket;
  136. }
  137. }
  138. ?>