Changeset View
Changeset View
Standalone View
Standalone View
src/aphront/configuration/AphrontApplicationConfiguration.php
<?php | <?php | ||||
/** | /** | ||||
* @task routing URI Routing | * @task routing URI Routing | ||||
* @task response Response Handling | |||||
*/ | */ | ||||
abstract class AphrontApplicationConfiguration extends Phobject { | abstract class AphrontApplicationConfiguration extends Phobject { | ||||
private $request; | private $request; | ||||
private $host; | private $host; | ||||
private $path; | private $path; | ||||
private $console; | private $console; | ||||
▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | try { | ||||
'P' => $request->getUser()->getPHID(), | 'P' => $request->getUser()->getPHID(), | ||||
)); | )); | ||||
$multimeter->setEventViewer('user.'.$request->getUser()->getPHID()); | $multimeter->setEventViewer('user.'.$request->getUser()->getPHID()); | ||||
} | } | ||||
if (!$response) { | if (!$response) { | ||||
$controller->willProcessRequest($uri_data); | $controller->willProcessRequest($uri_data); | ||||
$response = $controller->handleRequest($request); | $response = $controller->handleRequest($request); | ||||
$this->validateControllerResponse($controller, $response); | |||||
} | } | ||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
$original_exception = $ex; | $original_exception = $ex; | ||||
$response = $this->handleException($ex); | $response = $this->handleException($ex); | ||||
} | } | ||||
try { | try { | ||||
$response = $controller->didProcessRequest($response); | $response = $this->produceResponse($request, $response); | ||||
$response = $this->willSendResponse($response, $controller); | $response = $controller->willSendResponse($response); | ||||
$response->setRequest($request); | $response->setRequest($request); | ||||
$unexpected_output = PhabricatorStartup::endOutputCapture(); | $unexpected_output = PhabricatorStartup::endOutputCapture(); | ||||
if ($unexpected_output) { | if ($unexpected_output) { | ||||
$unexpected_output = pht( | $unexpected_output = pht( | ||||
"Unexpected output:\n\n%s", | "Unexpected output:\n\n%s", | ||||
$unexpected_output); | $unexpected_output); | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | if (!$site) { | ||||
$host)); | $host)); | ||||
} | } | ||||
$request->setSite($site); | $request->setSite($site); | ||||
return $site; | return $site; | ||||
} | } | ||||
/* -( Response Handling )-------------------------------------------------- */ | |||||
/** | |||||
* Tests if a response is of a valid type. | |||||
* | |||||
* @param wild Supposedly valid response. | |||||
* @return bool True if the object is of a valid type. | |||||
* @task response | |||||
*/ | |||||
private function isValidResponseObject($response) { | |||||
if ($response instanceof AphrontResponse) { | |||||
return true; | |||||
} | |||||
if ($response instanceof AphrontResponseProducerInterface) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Verifies that the return value from an @{class:AphrontController} is | |||||
* of an allowed type. | |||||
* | |||||
* @param AphrontController Controller which returned the response. | |||||
* @param wild Supposedly valid response. | |||||
* @return void | |||||
* @task response | |||||
*/ | |||||
private function validateControllerResponse( | |||||
AphrontController $controller, | |||||
$response) { | |||||
if ($this->isValidResponseObject($response)) { | |||||
return; | |||||
} | |||||
throw new Exception( | |||||
pht( | |||||
'Controller "%s" returned an invalid response from call to "%s". '. | |||||
'This method must return an object of class "%s", or an object '. | |||||
'which implements the "%s" interface.', | |||||
get_class($controller), | |||||
'handleRequest()', | |||||
'AphrontResponse', | |||||
'AphrontResponseProducerInterface')); | |||||
} | |||||
/** | |||||
* Verifies that the erturn value from an | |||||
joshuaspence: Opyt | |||||
* @{class:AphrontResponseProducerInterface} is of an allowed type. | |||||
* | |||||
* @param AphrontResponseProducerInterface Object which produced | |||||
* this response. | |||||
* @param wild Supposedly valid response. | |||||
* @return void | |||||
* @task response | |||||
*/ | |||||
private function validateProducerResponse( | |||||
AphrontResponseProducerInterface $producer, | |||||
$response) { | |||||
if ($this->isValidResponseObject($response)) { | |||||
return; | |||||
} | |||||
throw new Exception( | |||||
pht( | |||||
'Producer "%s" returned an invalid response from call to "%s". '. | |||||
'This method must return an object of class "%s", or an object '. | |||||
'which implements the "%s" interface.', | |||||
get_class($producer), | |||||
'produceAphrontResponse()', | |||||
'AphrontResponse', | |||||
'AphrontResponseProducerInterface')); | |||||
} | |||||
/** | |||||
* Resolves a response object into an @{class:AphrontResponse}. | |||||
* | |||||
* Controllers are permitted to return actual responses of class | |||||
* @{class:AphrontResponse}, or other objects which implement | |||||
* @{interface:AphrontResponseProducerInterface} and can produce a response. | |||||
* | |||||
* If a controller returns a response producer, invoke it now and produce | |||||
* the real response. | |||||
* | |||||
* @param AphrontRequest Request being handled. | |||||
* @param AphrontResponse|AphrontResponseProducerInterface Response, or | |||||
* response producer. | |||||
* @return AphrontResponse Response after any required production. | |||||
* @task response | |||||
*/ | |||||
private function produceResponse(AphrontRequest $request, $response) { | |||||
$original = $response; | |||||
// Detect cycles on the exact same objects. It's still possible to produce | |||||
// infinite responses as long as they're all unique, but we can only | |||||
// reasonably detect cycles, not guarantee that response production halts. | |||||
$seen = array(); | |||||
while (true) { | |||||
// NOTE: It is permissible for an object to be both a response and a | |||||
// response producer. If so, being a producer is "stronger". This is | |||||
// used by AphrontProxyResponse. | |||||
// If this response is a valid response, hand over the request first. | |||||
if ($response instanceof AphrontResponse) { | |||||
$response->setRequest($request); | |||||
} | |||||
// If this isn't a producer, we're all done. | |||||
if (!($response instanceof AphrontResponseProducerInterface)) { | |||||
break; | |||||
} | |||||
$hash = spl_object_hash($response); | |||||
if (isset($seen[$hash])) { | |||||
throw new Exception( | |||||
pht( | |||||
'Failure while producing response for object of class "%s": '. | |||||
'encountered production cycle (identical object, of class "%s", '. | |||||
'was produced twice).', | |||||
get_class($original), | |||||
get_class($response))); | |||||
} | |||||
$seen[$hash] = true; | |||||
$new_response = $response->produceAphrontResponse(); | |||||
$this->validateProducerResponse($response, $new_response); | |||||
$response = $new_response; | |||||
} | |||||
return $response; | |||||
} | |||||
} | } |
Opyt