Skip to content

Commit

Permalink
Defining Response Handlers
Browse files Browse the repository at this point in the history
Rewrite per feedback. Passing entire \Bullet\Response object to the
callbacks
  • Loading branch information
jcbwlkr committed Mar 27, 2013
1 parent f80d1c4 commit f1f3c21
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 52 deletions.
99 changes: 55 additions & 44 deletions src/Bullet/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class App extends \Pimple
'custom' => array()
);
protected $_helpers = array();
protected $_contentConverters = array();
protected $_responseHandlers = array();

/**
* New App instance
Expand Down Expand Up @@ -48,14 +48,14 @@ public function __construct(array $values = array())
return filter_var($value, FILTER_VALIDATE_EMAIL);
});

$this->registerContentConverter(
function($value) {
return is_array($value);
$this->registerResponseHandler(
function($response) {
return is_array($response->content());
},
function($value) {
return json_encode($value);
},
'application/json'
function($response) {
$response->contentType('application/json');
$response->content(json_encode($response->content()));
}
);

// Pimple constructor
Expand Down Expand Up @@ -192,22 +192,8 @@ public function run($method, $uri = null)
}
}

// Ensure response is always a Bullet\Response
if($response === false) {
// Boolean false result generates a 404
$response = $this->response(404);
} elseif(is_int($response)) {
// Assume int response is desired HTTP status code
$response = $this->response($response);
} else {
// Convert response to Bullet\Response object if not one already
if(!($response instanceof \Bullet\Response)) {
$response = $this->response(200, $response);
}
}

// Apply defined response content converters
$this->_convertResponseContent($response);
// Perform last minute operations on our response
$response = $this->_handleResponse($response);

// Set current outgoing response
$this->response($response);
Expand Down Expand Up @@ -695,41 +681,66 @@ public function __sleep()
}

/**
* Add a set of content converter closures. If a response's content matches
* our test closure we will run it through a converter closure and set the
* content type.
* Register a response handler to potentially be applied to responses
* returned by \Bullet\App::run. Each callback is given the
* \Bullet\Response object as a parameter.
*
* @param \Closure $test Closure to test against response content.
* @param \Closure $converter Closure to modify response content.
* @param string $contentType The new contentType for the response
* @param callable $condtion Function name or closure to test against response
* @param callable $handler Function name or closure to modify response
*
* @returns \Bullet\App
*/
public function registerContentConverter(\Closure $test, \Closure $converter, $contentType)
public function registerResponseHandler($condition, $handler)
{
$this->_contentConverters[] = array(
'test' => $test,
'converter' => $converter,
'contentType' => $contentType
if(null !== $condition && !is_callable($condition)) {
throw new \InvalidArgumentException("First argument to " . __METHOD__ . " must be a valid callback or NULL. Given argument was neither.");
}
if(!is_callable($handler)) {
throw new \InvalidArgumentException("Second argument to " . __METHOD__ . " must be a valid callback. Given argument was not callable.");
}

$this->_responseHandlers[] = array(
'condition' => $condition,
'handler' => $handler
);

return $this;
}

/**
* Loop through registered content converters and apply the first that
* passes. Will modify response content and contentType
* Modify response to prepare it for returning.
*
* @param \Bullet\Response $response The response to convert
* Applies special logic for particular response types and ensure response
* is a \Bullet\Response object.
*
* Loops through registered response handlers and applies any with a null
* condition or whose condition evaluates to true.
*
* @param mixed $response The response to act upon.
*/
protected function _convertResponseContent($response)
protected function _handleResponse($response)
{
foreach($this->_contentConverters as $converter) {
if(call_user_func($converter['test'], $response->content())) {
$response->content(call_user_func($converter['converter'], $response->content()));
$response->header('Content-Type', $converter['contentType']);
break;
// Ensure response is always a Bullet\Response
if($response === false) {
// Boolean false result generates a 404
$response = $this->response(404);
} elseif(is_int($response)) {
// Assume int response is desired HTTP status code
$response = $this->response($response);
} else {
// Convert response to Bullet\Response object if not one already
if(!($response instanceof \Bullet\Response)) {
$response = $this->response(200, $response);
}
}

// Apply user defined response handlers
foreach($this->_responseHandlers as $handler) {
if(null === $handler['condition'] || call_user_func($handler['condition'], $response)) {
call_user_func($handler['handler'], $response);
}
}

return $response;
}
}
56 changes: 48 additions & 8 deletions tests/Bullet/Tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -944,21 +944,21 @@ public function testResponseWithNoContentConverterIsUnchanged()
$this->assertEquals('text/html', $result->contentType());
}

public function testResponseWithSpecificClassGetsConverted()
public function testResponseOfSpecificClassGetsConverted()
{
$app = new Bullet\App();
$app->path('/', function($request) use($app) {
return new TestHelper();
});

$app->registerContentConverter(
function($value) {
return $value instanceof TestHelper;
$app->registerResponseHandler(
function($response) {
return $response->content() instanceof TestHelper;
},
function($value) {
return $value->something();
},
'text/plain'
function($response) {
$response->contentType('text/plain');
$response->content($response->content()->something());
}
);

$request = new \Bullet\Request('GET', '/');
Expand All @@ -968,6 +968,46 @@ function($value) {
$this->assertEquals('text/plain', $result->contentType());
}

public function testThatAllApplicableResponseHandlersAreApplied()
{
$app = new Bullet\App();
$app->path('/', function($request) use($app) {
return 'a';
});

// Always extend my response
$app->registerResponseHandler(
null,
function($response) {
$response->content($response->content() . 'b');
}
);

// Further extend the response as condition returns true
$app->registerResponseHandler(
function($response) {
return true;
},
function($response) {
$response->content($response->content() . 'c');
}
);

// Condition returns false so handler should not be applied
$app->registerResponseHandler(
function($response) {
return false;
},
function($response) {
$response->content($response->content() . 'd');
}
);

$request = new \Bullet\Request('GET', '/');
$result = $app->run($request);

$this->assertEquals('abc', $result->content());
}
}

class TestHelper
Expand Down

0 comments on commit f1f3c21

Please sign in to comment.