Completed
Pull Request — master (#3)
by
unknown
03:38
created

Client::getErrorStringFromResponseBody()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 16
c 0
b 0
f 0
ccs 0
cts 13
cp 0
rs 9.4285
cc 3
eloc 9
nc 3
nop 1
crap 12
1
<?php declare(strict_types=1);
2
3
namespace PeeHaa\AsyncTwitter\Api;
4
5
use Amp\Artax\Response as HttpResponse;
6
use Amp\Promise;
7
use ExceptionalJSON\DecodeErrorException as JSONDecodeErrorException;
8
use PeeHaa\AsyncTwitter\Credentials\AccessToken;
9
use PeeHaa\AsyncTwitter\Credentials\Application;
10
use PeeHaa\AsyncTwitter\Http\Artax;
11
use PeeHaa\AsyncTwitter\Oauth\Header;
12
use PeeHaa\AsyncTwitter\Oauth\Parameters;
13
use PeeHaa\AsyncTwitter\Oauth\Signature\BaseString;
14
use PeeHaa\AsyncTwitter\Oauth\Signature\Key;
15
use PeeHaa\AsyncTwitter\Oauth\Signature\Signature;
16
use PeeHaa\AsyncTwitter\Request\Body;
17
use PeeHaa\AsyncTwitter\Request\Parameter;
18
use PeeHaa\AsyncTwitter\Request\Url;
19
use function Amp\resolve;
20
use function ExceptionalJSON\decode as json_try_decode;
21
22
class Client
23
{
24
    private $httpClient;
25
26
    private $applicationCredentials;
27
28
    private $accessToken;
29
30
    public function __construct(Artax $httpClient, Application $applicationCredentials, AccessToken $accessToken)
31
    {
32
        $this->httpClient             = $httpClient;
33
        $this->applicationCredentials = $applicationCredentials;
34
        $this->accessToken            = $accessToken;
35
    }
36
37
    public function request(Request $request): Promise
38
    {
39
        switch ($request->getMethod()) {
40
            case 'POST':
41
                return $this->post($request);
42
43
            case 'GET':
44
                return $this->get($request);
45
46
            default:
47
                throw new InvalidMethodException();
48
        }
49
    }
50
51
    private function getErrorStringFromResponseBody(array $body)
52
    {
53
        if (!isset($body['errors'])) {
54
            return ['Unknown error', -1, []];
55
        }
56
57
        $message = (string)($body['errors'][0]['message'] ?? 'Unknown error');
58
        $code = (int)($body['errors'][0]['code'] ?? -1);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
59
        $extra = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
60
61
        for ($i = 1; isset($body['errors'][$i]); $i++) {
62
            $extra[(int)($body['errors'][$i]['code'] ?? -1)] = (string)($body['errors'][$i]['message'] ?? 'Unknown error');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
63
        }
64
65
        return [$message, $code, $extra];
66
    }
67
68
    // https://dev.twitter.com/overview/api/response-codes
69
    private function throwFromErrorResponse(HttpResponse $response, array $body)
70
    {
71
        list($message, $code, $extra) = $this->getErrorStringFromResponseBody($body);
72
73
        switch ($response->getStatus()) {
74
            case 400: throw new BadRequestException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
75
            case 401: throw new UnauthorizedException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
76
            case 403: throw new ForbiddenException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
77
            case 404: throw new NotFoundException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
78
            case 406: throw new NotAcceptableException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
79
            case 410: throw new GoneException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
80
            case 420: throw new RateLimitTriggeredException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
81
            case 422: throw new UnprocessableEntityException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
82
            case 429: throw new RateLimitTriggeredException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
83
            case 500: throw new ServerErrorException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
84
            case 502: throw new BadGatewayException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
85
            case 503: throw new ServiceUnavailableException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
86
            case 504: throw new GatewayTimeoutException($message, $code, null, $extra);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
87
        }
88
    }
89
90
    private function handleResponse(Promise $responsePromise): Promise
91
    {
92
        return resolve(function() use($responsePromise) {
93
            /** @var HttpResponse $response */
94
            $response = yield $responsePromise;
95
96
            try {
97
                $decoded = json_try_decode($response->getBody(), true);
98
            } catch (JSONDecodeErrorException $e) {
99
                throw new RequestFailedException('Failed to decode response body as JSON', $e->getCode(), $e);
0 ignored issues
show
Documentation introduced by
$e is of type object<ExceptionalJSON\DecodeErrorException>, but the function expects a null|object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
100
            }
101
102
            $this->throwFromErrorResponse($response, $decoded);
103
104
            return $decoded;
105
        });
106
    }
107
108 View Code Duplication
    private function post(Request $request): Promise
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
    {
110
        $header = $this->getHeader('POST', $request->getEndpoint(), ...$request->getParameters());
111
112
        $response = $this->httpClient->post($request->getEndpoint(), $header, new Body(...$request->getParameters()));
113
        return $this->handleResponse($response);
114
    }
115
116 View Code Duplication
    private function get(Request $request): Promise
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
    {
118
        $header = $this->getHeader('GET', $request->getEndpoint(), ...$request->getParameters());
119
120
        $response = $this->httpClient->get($request->getEndpoint(), $header, ...$request->getParameters());
121
        return $this->handleResponse($response);
122
    }
123
124
    private function getHeader(string $method, Url $url, Parameter ...$parameters): Header
125
    {
126
        $oauthParameters     = new Parameters($this->applicationCredentials, $this->accessToken, $url, ...$parameters);
127
        $baseSignatureString = new BaseString($method, $url, $oauthParameters);
128
        $signingKey          = new Key($this->applicationCredentials, $this->accessToken);
129
        $signature           = new Signature($baseSignatureString, $signingKey);
130
131
        return new Header($oauthParameters, $signature);
132
    }
133
}
134