Completed
Push — master ( 378d82...2ee294 )
by Arthur
05:41 queued 03:47
created

Response::getErrorDescription()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Pushok package.
5
 *
6
 * (c) Arthur Edamov <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Pushok;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * Class Response
17
 * @package Pushok
18
 *
19
 * @see http://bit.ly/communicating-with-apns
20
 */
21
class Response
22
{
23
    const REQUEST_ERROR = 0;
24
    const APNS_SUCCESS = 200;
25
    const APNS_BAD_REQUEST = 400;
26
    const APNS_AUTH_PROVIDER_ERROR = 403;
27
    const APNS_METHOD_NOT_ALLOWED = 405;
28
    const APNS_NOT_ACTIVE_DEVICE_TOKEN_ = 410;
29
    const APNS_PAYLOAD_TOO_LARGE = 413;
30
    const APNS_TOO_MANY_REQUESTS = 429;
31
    const APNS_SERVER_ERROR = 500;
32
    const APNS_SERVER_UNAVAILABLE = 503;
33
34
    /**
35
     * Reason phrases by status code.
36
     *
37
     * @var array
38
     */
39
    private static $reasonPhrases = [
40
        0 => 'Request error.',
41
        200 => 'Success.',
42
        400 => 'Bad request.',
43
        403 => 'There was an error with the certificate or with the provider authentication token.',
44
        405 => 'The request used a bad :method value. Only POST requests are supported.',
45
        410 => 'The device token is no longer active for the topic.',
46
        413 => 'The notification payload was too large.',
47
        429 => 'The server received too many requests for the same device token.',
48
        500 => 'Internal server error.',
49
        503 => 'The server is shutting down and unavailable.',
50
    ];
51
52
    /**
53
     * Error reasons by status code.
54
     *
55
     * @var array
56
     */
57
    private static $errorReasons = [
58
        400 => [
59
            'BadCollapseId' => 'The collapse identifier exceeds the maximum allowed size',
60
            'BadDeviceToken' => 'The specified device token was bad.' .
61
                ' Verify that the request contains a valid token and that the token matches the environment',
62
            'BadExpirationDate' => 'The apns-expiration value is bad',
63
            'BadMessageId' => 'The apns-id value is bad',
64
            'BadPriority' => 'The apns-priority value is bad',
65
            'BadTopic' => 'The apns-topic was invalid',
66
            'DeviceTokenNotForTopic' => 'The device token does not match the specified topic',
67
            'DuplicateHeaders' => 'One or more headers were repeated',
68
            'IdleTimeout' => 'Idle time out',
69
            'MissingDeviceToken' => 'The device token is not specified in the request :path.' .
70
                ' Verify that the :path header contains the device token',
71
            'MissingTopic' => 'The apns-topic header of the request was not specified and was required.' .
72
                ' The apns-topic header is mandatory' .
73
                ' when the client is connected using a certificate that supports multiple topics',
74
            'PayloadEmpty' => 'The message payload was empty',
75
            'TopicDisallowed' => 'Pushing to this topic is not allowed',
76
        ],
77
        403 => [
78
            'BadCertificate' => 'The certificate was bad',
79
            'BadCertificateEnvironment' => 'The client certificate was for the wrong environment',
80
            'ExpiredProviderToken' => 'The provider token is stale and a new token should be generated',
81
            'Forbidden' => 'The specified action is not allowed',
82
            'InvalidProviderToken' => 'The provider token is not valid or the token signature could not be verified',
83
            'MissingProviderToken' => 'No provider certificate was used to connect to APNs' .
84
                ' and Authorization header was missing or no provider token was specified',
85
        ],
86
        404 => [
87
            'BadPath' => 'The request contained a bad :path value'
88
        ],
89
        405 => [
90
            'MethodNotAllowed' => 'The specified :method was not POST'
91
        ],
92
        410 => [
93
            'Unregistered' => 'The device token is inactive for the specified topic.'
94
        ],
95
        413 => [
96
            'PayloadTooLarge' => 'The message payload was too large.' .
97
                ' See The Remote Notification Payload for details on maximum payload size'
98
        ],
99
        429 => [
100
            'TooManyRequests' => 'Too many requests were made consecutively to the same device token'
101
        ],
102
        500 => [
103
            'InternalServerError' => 'An internal server error occurred'
104
        ],
105
        503 => [
106
            'ServiceUnavailable' => 'The service is unavailable',
107
            'Shutdown' => 'The server is shutting down',
108
        ],
109
    ];
110
111
    /**
112
     * APNs Id.
113
     *
114
     * @var string|null
115
     */
116
    private $apnsId;
117
118
    /**
119
     * Response status code.
120
     *
121
     * @var int
122
     */
123
    private $statusCode;
124
125
    /**
126
     * Error reason.
127
     *
128
     * @var string
129
     */
130
    private $errorReason;
131
132
    /**
133
     * Response constructor.
134
     *
135
     * @param int $statusCode
136
     * @param string|null $apnsId
137
     * @param string $errorReason
138
     */
139
    public function __construct(int $statusCode, $apnsId, string $errorReason)
140
    {
141
        $this->statusCode = $statusCode;
142
        $this->apnsId = $apnsId;
143
        $this->errorReason = $errorReason;
144
    }
145
146
    /**
147
     * Create APNs response from PSR7 interface.
148
     *
149
     * @param ResponseInterface $response
150
     * @return static
151
     */
152
    public static function createFromPsrInterface(ResponseInterface $response)
153
    {
154
        $statusCode = $response->getStatusCode();
155
        $apnsId = $response->getHeader('apns-id')[0];
156
        $errorReason = self::fetchErrorReason($response->getBody()->getContents());
157
158
        return new static($statusCode, $apnsId, $errorReason);
159
    }
160
161
    /**
162
     * Fetch error reason from response body.
163
     *
164
     * @param string $body
165
     * @return string
166
     */
167
    private static function fetchErrorReason(string $body): string
168
    {
169
        return json_decode($body, true)['reason'] ?: '';
170
    }
171
172
    /**
173
     * Get APNs Id
174
     *
175
     * @return string
176
     */
177
    public function getApnsId()
178
    {
179
        return $this->apnsId;
180
    }
181
182
    /**
183
     * Get status code.
184
     *
185
     * @return int
186
     */
187
    public function getStatusCode(): int
188
    {
189
        return $this->statusCode;
190
    }
191
192
    /**
193
     * Get reason phrase.
194
     *
195
     * @return string
196
     */
197
    public function getReasonPhrase(): string
198
    {
199
        return self::$reasonPhrases[$this->statusCode] ?: '';
200
    }
201
202
    /**
203
     * Get error reason.
204
     *
205
     * @return string
206
     */
207
    public function getErrorReason(): string
208
    {
209
        return $this->errorReason;
210
    }
211
212
    /**
213
     * Get error description.
214
     *
215
     * @return string
216
     */
217
    public function getErrorDescription(): string
218
    {
219
        if (isset(self::$errorReasons[$this->statusCode][$this->errorReason])) {
220
            return self::$errorReasons[$this->statusCode][$this->errorReason];
221
        }
222
223
        return '';
224
    }
225
}
226