Change OutputFilter to use a delegate instead of subclassing to override behavior.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 14 Oct 2012 16:16:54 +0000 (12:16 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 14 Oct 2012 16:16:54 +0000 (12:16 -0400)
http/output_filter.php

index 98460b1726f93a5214fa5b3f2258e9a8a2cd9395..c9531596751a5ed02abfda2a2a0f6ab560a6fda0 100644 (file)
@@ -16,6 +16,7 @@
 
 namespace hoplite\http;
 
+require_once HOPLITE_ROOT . '/base/weak_interface.php';
 require_once HOPLITE_ROOT . '/http/response_code.php';
 require_once HOPLITE_ROOT . '/views/template_loader.php';
 
@@ -23,18 +24,28 @@ require_once HOPLITE_ROOT . '/views/template_loader.php';
   The OutputFilter is executed after all Actions have been processed. The
   primary function is to generate the actual HTTP response body from the model
   data contained within the http\Response. Depending on how the Request was
-  sent, this
+  sent, this class will encode the output properly and perform any necessary
+  processing (e.g. templates).
 */
 class OutputFilter
 {
   /*! @var RootController */
   private $controller;
 
+  /*! @var WeakInterface<OutputFilterDelegate> */
+  private $delegate;
+
   /*! @const The key in Response#context that indicates which type of output to
              produce, regardless of the request type.
   */
   const RESPONSE_TYPE = 'response_type';
 
+  /*! @const The key in a Response#context that is set by the ::FilterOutput. It
+             is derived from {@see RESPONSE_TYPE} and controls the actual output
+             type.
+  */
+  const OUTPUT_FILTER_TYPE = '_output_filter_type';
+
   /*! @const A key in Response#context to render a template with the
              Response#data when creating a HTML body.
   */
@@ -46,21 +57,31 @@ class OutputFilter
   public function __construct(RootController $controller)
   {
     $this->controller = $controller;
+    $this->delegate = new \hoplite\base\WeakInterface('hoplite\http\OutputFilterDelegate');
   }
 
   /*! Accessor for the RootController. */
   public function controller() { return $this->controller; }
 
+  /*! Accessors for the delegate. */
+  public function set_delegate($delegate)
+  {
+    $this->delegate->Bind($delegate);
+  }
+  public function delegate() { return $this->delegate->Get(); }
+
   /*! @brief Main entry point for output filtering
     This is called from the RootController to begin processing the output and
     generating the response.
   */
   public function FilterOutput(Request $request, Response $response)
   {
+    $response->context[self::OUTPUT_FILTER_TYPE] = $this->_GetResponseType($request, $response);
+
     // If there was an error during the processing of an action, allow hooking
     // custom logic.
     if ($response->response_code != ResponseCode::OK)
-      if (!$this->_ContinueHandlingResponseForCode($request, $response))
+      if ($this->delegate->OverrideOutputFiltering($request, $response))
         return;
 
     // If there's already raw data for the body, just output that. Otherwise,
@@ -76,27 +97,14 @@ class OutputFilter
     print $response->body;
   }
 
-  /*!
-    If the request did not generate an 200 response code, the filter gives the
-    client an opportunity to override the normal output control flow and perform
-    some other task. If you want the control flow to continue executing as
-    normal, return TRUE; otherwise, return FALSE to exit from ::FilterOutput().
-    @return boolean
-  */
-  protected function _ContinueHandlingResponseForCode(Request $request,
-                                                      Response $response)
-  {
-    return TRUE;
-  }
-
   /*!
     Fills out the Response#data field. This could be an evaluated HTML template,
     a JSON payload, XML, or any other type of response for the client.
   */
-  protected function _CreateBodyForResponse(Request $request,
-                                            Response $response)
+  private function _CreateBodyForResponse(Request $request,
+                                          Response $response)
   {
-    $type = $this->_GetResponseType($request, $response);
+    $type = $response->context[self::OUTPUT_FILTER_TYPE];
     if ($type == 'json') {
       $response->headers['Content-Type'] = 'application/json';
       $response->body = json_encode($response->data, JSON_NUMERIC_CHECK);
@@ -115,7 +123,7 @@ class OutputFilter
   /*!
     Determines based on the Request what format the response should be in.
   */
-  protected function _GetResponseType(Request $request, Response $response)
+  private function _GetResponseType(Request $request, Response $response)
   {
     // Check if an Action specified an overriding response type.
     if (isset($response->context[self::RESPONSE_TYPE]))
@@ -143,7 +151,7 @@ class OutputFilter
   /*!
     Creates an XML tree from an array. Equivalent to json_encode.
   */
-  protected function _EncodeXML($data)
+  private function _EncodeXML($data)
   {
     $response = new \SimpleXMLElement('<response/>');
 
@@ -162,3 +170,24 @@ class OutputFilter
     return $response->AsXML();
   }
 }
+
+/*!
+  Delegate interface for the OutputFilter. Called via a WeakInterface, and all
+  methods are optional.
+*/
+interface OutputFilterDelegate
+{
+  /*!
+    The delegate can abort output filtering of the request and execute custom
+    logic by returning TRUE from this function.
+
+    If the request did not generate an 200 response code, the filter gives the
+    client an opportunity to override the normal output control flow and perform
+    some other task. If you want the control flow to continue executing as
+    normal, return FALSE; otherwise, return TRUE to exit from ::FilterOutput().
+
+    @return bool TRUE if the OutputFilter should stop processing the response.
+                 FALSE for default output filtering behavior.
+  */
+  public function OverrideOutputFiltering(Request $request, Response $response);
+}