Created
April 30, 2014 17:02
-
-
Save jamiehannaford/0a085d4b1507308b0190 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
*Exceptionclasses mentioned in the switch cases will extend thisRequestExceptionclass. I also imagine you would want to disallow instantiation of theRequestExceptionclass itself (that is, one of its subclasses must be instantiated instead). If so, consider making theRequestExceptionclass abstract.