Created
April 30, 2014 17:02
-
-
Save jamiehannaford/0a085d4b1507308b0190 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace OpenStack\Common\Transport\Exception; | |
use GuzzleHttp\Message\RequestInterface; | |
use GuzzleHttp\Message\ResponseInterface; | |
use OpenStack\Common\Exception; | |
class RequestException extends Exception | |
{ | |
/** @var \GuzzleHttp\Message\RequestInterface */ | |
protected $request; | |
/** @var \GuzzleHttp\Message\ResponseInterface */ | |
protected $response; | |
/** | |
* Construct this exception like any other, but also inject Request and | |
* Response objects in case the user needs them for debugging. | |
* | |
* @param string $errorMessage Human-readable explanation of error | |
* @param RequestInterface $request The failed request | |
* @param ResponseInterface $response The API's response | |
*/ | |
public function __construct($errorMessage, RequestInterface $request, ResponseInterface $response) | |
{ | |
parent::__construct($errorMessage); | |
$this->request = $request; | |
$this->response = $response; | |
} | |
/** | |
* Factory method that creates an appropriate Exception object based on the | |
* Response's status code. The message is constructed here also. | |
* | |
* @param RequestInterface $request The failed request | |
* @param ResponseInterface $response The API's response | |
* @return self | |
*/ | |
public static function create(RequestInterface $request, ResponseInterface $response) | |
{ | |
$label = 'A HTTP error occurred'; | |
$status = $response->getStatusCode(); | |
switch ($status) { | |
case '401': | |
$class = self::prependNamespace('UnauthorizedException'); | |
break; | |
case '403': | |
$class = self::prependNamespace('ForbiddenException'); | |
break; | |
case '404': | |
$class = self::prependNamespace('ResourceNotFoundException'); | |
break; | |
case '405': | |
$class = self::prependNamespace('MethodNotAllowedException'); | |
break; | |
case '409': | |
$class = self::prependNamespace('ConflictException'); | |
break; | |
case '411': | |
$class = self::prependNamespace('LengthRequiredException'); | |
break; | |
case '422': | |
$class = self::prependNamespace('UnprocessableEntityException'); | |
break; | |
case '500': | |
$class = self::prependNamespace('ServerException'); | |
break; | |
} | |
$message = sprintf( | |
"%s\n[Status] %s (%s)\n[Message] %s", $label, | |
$status, $response->getReasonPhrase(), (string) $response->getBody() | |
); | |
// For all other errors, throw a generic Exception | |
if (!isset($class)) { | |
throw new Exception($message); | |
} | |
return new $class($message, $request, $response); | |
} | |
protected static function prependNamespace($class) | |
{ | |
return sprintf("%s\\%s", __NAMESPACE__, $class); | |
} | |
public function getResponse() | |
{ | |
return $this->response; | |
} | |
public function getRequest() | |
{ | |
return $this->request; | |
} | |
} |
I agree about the method name, I'll change it to self::prependNamespaceTo
.
Adding a default
block won't work because the generic exception class has different constructor args - so it needs to be instantiated in a different way. Another option might be:
return isset($class) ? new $class($message, $request, $response) : Exception($message);
I see what you mean about making the RequestException
abstract - but I'm not sure we'll need to do it. Say for example we encounter a HTTP 4xx
or 5xx
error that does not have its own concrete exception, we'd probably throw a generic RequestException
.
In that case, what about creating a default
case that returns new self($message, $request, $response);
?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I imagine each of the
*Exception
classes mentioned in the switch cases will extend thisRequestException
class. I also imagine you would want to disallow instantiation of theRequestException
class itself (that is, one of its subclasses must be instantiated instead). If so, consider making theRequestException
class abstract.