GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 7d19bc...4801e6 )
by ignace
21:06
created

JSend::validateErrorMessage()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 8.8571
cc 5
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace Carpediem\JSend;
4
5
use InvalidArgumentException;
6
use JsonSerializable;
7
use UnexpectedValueException;
8
9
/**
10
 * A Immutable Value Object Class to represent a JSend object
11
 */
12
class JSend implements JsonSerializable
13
{
14
    const STATUS_SUCCESS = 'success';
15
16
    const STATUS_ERROR = 'error';
17
18
    const STATUS_FAIL = 'fail';
19
20
    /**
21
     * JSend status
22
     *
23
     * @var string
24
     */
25
    protected $status;
26
27
    /**
28
     * JSend Data
29
     *
30
     * @var array
31
     */
32
    protected $data;
33
34
    /**
35
     * JSend Error Message
36
     *
37
     * @var string
38
     */
39
    protected $errorMessage;
40
41
    /**
42
     * JSend Error Code
43
     * @var int|null
44
     */
45
    protected $errorCode;
46
47
    /**
48
     * New Instance
49
     *
50
     * @param string $status
51
     * @param array  $data
52
     * @param string $errorMessage
53
     * @param int    $errorCode
54
     */
55
    public function __construct($status, array $data = null, $errorMessage = null, $errorCode = null)
56
    {
57
        $this->status = $this->filterStatus($status);
58
        $this->data = $data ?: [];
59
        $this->filterError($errorMessage, $errorCode);
60
    }
61
62
    /**
63
     * Filter and Validate the JSend Status
64
     *
65
     * @param string $status
66
     *
67
     * @throws UnexpectedValueException If the status value does not conform to JSend Spec.
68
     *
69
     * @return string
70
     */
71
    protected function filterStatus($status)
72
    {
73
        $res = [self::STATUS_SUCCESS => 1, self::STATUS_ERROR => 1, self::STATUS_FAIL => 1];
74
        if (isset($res[$status])) {
75
            return $status;
76
        }
77
78
        throw new UnexpectedValueException('The given status does not conform to Jsend specification');
79
    }
80
81
    /**
82
     * Filter and Validate the JSend Error properties
83
     *
84
     * @param string $errorMessage
85
     * @param int    $errorCode
86
     */
87
    protected function filterError($errorMessage, $errorCode)
88
    {
89
        if (self::STATUS_ERROR !== $this->status) {
90
            return;
91
        }
92
93
        $this->errorMessage = $this->validateErrorMessage($errorMessage);
94
        $this->errorCode = $this->validateErrorCode($errorCode);
95
    }
96
97
    /**
98
     * Validate a string
99
     *
100
     * @param mixed $str
101
     *
102
     * @throws UnexpectedValueException If the data value is not a empty string
103
     *
104
     * @return string
105
     */
106
    protected function validateErrorMessage($str)
107
    {
108
        if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
109
            $str = (string) $str;
110
            if ('' !== $str) {
111
                return $str;
112
            }
113
        }
114
115
        throw new UnexpectedValueException('The error message must be a non empty string');
116
    }
117
118
    /**
119
     * Validate a integer
120
     *
121
     * @param mixed $int
122
     *
123
     * @throws UnexpectedValueException If the data value is not an integer
124
     *
125
     * @return int
126
     */
127
    protected function validateErrorCode($int)
128
    {
129
        if (null === $int) {
130
            return $int;
131
        }
132
133
        if (false === ($res = filter_var($int, FILTER_VALIDATE_INT))) {
134
            throw new UnexpectedValueException('The error code must be a integer or null');
135
        }
136
137
        return $res;
138
    }
139
140
    /**
141
     * Returns the status
142
     *
143
     * @return string
144
     */
145
    public function getStatus()
146
    {
147
        return $this->status;
148
    }
149
150
    /**
151
     * Returns the data
152
     *
153
     * @return array
154
     */
155
    public function getData()
156
    {
157
        return $this->data;
158
    }
159
160
    /**
161
     * Returns the error message
162
     *
163
     * @return string
164
     */
165
    public function getErrorMessage()
166
    {
167
        return $this->errorMessage;
168
    }
169
170
    /**
171
     * Returns the error code
172
     *
173
     * @return int|null
174
     */
175
    public function getErrorCode()
176
    {
177
        return $this->errorCode;
178
    }
179
180
    /**
181
     * Returns whether the status is success
182
     *
183
     * @return bool
184
     */
185
    public function isSuccess()
186
    {
187
        return self::STATUS_SUCCESS === $this->status;
188
    }
189
190
    /**
191
     * Returns whether the status is fail
192
     *
193
     * @return bool
194
     */
195
    public function isFail()
196
    {
197
        return self::STATUS_FAIL === $this->status;
198
    }
199
200
    /**
201
     * Returns whether the status is error
202
     *
203
     * @return bool
204
     */
205
    public function isError()
206
    {
207
        return self::STATUS_ERROR === $this->status;
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213
    public function __toString()
214
    {
215
        return json_encode($this, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
216
    }
217
218
    /**
219
     * @inheritdoc
220
     */
221
    public function jsonSerialize()
222
    {
223
        return $this->toArray();
224
    }
225
226
    /**
227
     * Retuns the array representation
228
     *
229
     * @return array
230
     */
231
    public function toArray()
232
    {
233
        $arr = ['status' => $this->status, 'data' => $this->data ?: null];
234
        if (self::STATUS_ERROR !== $this->status) {
235
            return $arr;
236
        }
237
238
        $arr['message'] = (string) $this->errorMessage;
239
        if (null !== $this->errorCode) {
240
            $arr['code'] = $this->errorCode;
241
        }
242
243
        if (null === $arr['data']) {
244
            unset($arr['data']);
245
        }
246
247
        return $arr;
248
    }
249
250
    /**
251
     * @inheritdoc
252
     */
253
    public function __debugInfo()
254
    {
255
        return $this->toArray();
256
    }
257
258
    /**
259
     * Returns the generated HTTP Response
260
     *
261
     * @param array $headers Optional headers to add to the response
262
     *
263
     * @return string
264
     */
265
    public function send(array $headers = [])
266
    {
267
        $body = $this->__toString();
268
        $headers = $this->filterHeaders(array_merge([
269
            'Content-Type' => 'application/json;charset=utf-8',
270
            'Content-Length' => strlen($body),
271
        ], $headers));
272
        foreach ($headers as $header) {
273
            header($header);
274
        }
275
        echo $body;
276
    }
277
278
    /**
279
     * Filter Submitted Headers
280
     *
281
     * @param array $headers a Collection of key/value headers
282
     *
283
     * @return array
284
     */
285
    protected function filterHeaders(array $headers)
286
    {
287
        $formattedHeaders = [];
288
        foreach ($headers as $name => $value) {
289
            $formattedHeaders[] = $this->validateHeaderName($name).': '.$this->validateHeaderValue($value);
290
        }
291
292
        return $formattedHeaders;
293
    }
294
295
    /**
296
     * Validate Header name
297
     *
298
     * @param string $name
299
     *
300
     * @throws InvalidArgumentException if the header name is invalid
301
     *
302
     * @return string
303
     */
304
    protected function validateHeaderName($name)
305
    {
306
        if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
307
            throw new InvalidArgumentException('Invalid header name');
308
        }
309
310
        return $name;
311
    }
312
313
    /**
314
     * Validate Header value
315
     *
316
     * @param string $value
317
     *
318
     * @throws InvalidArgumentException if the header value is invalid
319
     *
320
     * @return string
321
     */
322
    protected function validateHeaderValue($value)
323
    {
324
        if (preg_match("#(?:(?:(?<!\r)\n)|(?:\r(?!\n))|(?:\r\n(?![ \t])))#", $value)
325
            || preg_match('/[^\x09\x0a\x0d\x20-\x7E\x80-\xFE]/', $value)
326
        ) {
327
            throw new InvalidArgumentException('Invalid header value');
328
        }
329
330
        return $value;
331
    }
332
333
    /**
334
     * Returns an instance with the specified status.
335
     *
336
     * This method MUST retain the state of the current instance, and return
337
     * an instance that contains the specified status.
338
     *
339
     * @param string $status The status to use with the new instance.
340
     *
341
     * @return static A new instance with the specified status.
342
     */
343
    public function withStatus($status)
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...
344
    {
345
        if ($status === $this->status) {
346
            return $this;
347
        }
348
349
        return new static($status, $this->data, $this->errorMessage, $this->errorCode);
350
    }
351
352
    /**
353
     * Returns an instance with the specified data.
354
     *
355
     * This method MUST retain the state of the current instance, and return
356
     * an instance that contains the specified data.
357
     *
358
     * @param array $data The data to use with the new instance.
359
     *
360
     * @return static A new instance with the specified data.
361
     */
362
    public function withData(array $data)
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...
363
    {
364
        if ($data === $this->data) {
365
            return $this;
366
        }
367
368
        return new static($this->status, $data, $this->errorMessage, $this->errorCode);
369
    }
370
371
    /**
372
     * Returns an instance with the specified error message and error code.
373
     *
374
     * This method MUST retain the state of the current instance, and return
375
     * an instance that contains the specified error message and error code.
376
     *
377
     * @param string   $errorMessage The error message to use with the new instance.
378
     * @param int|null $errorCode    The error code to use with the new instance.
379
     *
380
     * @return static A new instance with the specified status.
381
     */
382
    public function withError($errorMessage, $errorCode = null)
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...
383
    {
384
        if ($errorMessage === $this->errorMessage && $errorCode === $this->errorCode) {
385
            return $this;
386
        }
387
388
        return new static($this->status, $this->data, $errorMessage, $errorCode);
389
    }
390
391
    /**
392
     * Returns a successful JSend object with the specified data
393
     *
394
     * @param array $data The data to use with the new instance.
395
     *
396
     * @return static A new succesful instance with the specified data.
397
     */
398
    public static function success(array $data = [])
399
    {
400
        return new static(static::STATUS_SUCCESS, $data);
401
    }
402
403
    /**
404
     * Returns a failed JSend object with the specified data
405
     *
406
     * @param array $data The data to use with the new instance.
407
     *
408
     * @return static A new failed instance with the specified data.
409
     */
410
    public static function fail(array $data = [])
411
    {
412
        return new static(static::STATUS_FAIL, $data);
413
    }
414
415
    /**
416
     * Returns a error JSend object with the specified error message and error code.
417
     *
418
     * @param string   $errorMessage The error message to use with the new instance.
419
     * @param int|null $errorCode    The error code to use with the new instance.
420
     * @param array    $data         The optional data to use with the new instance.
421
     *
422
     * @return static A new failed instance with the specified data.
423
     */
424
    public static function error($errorMessage, $errorCode = null, $data = null)
425
    {
426
        return new static(static::STATUS_ERROR, $data, $errorMessage, $errorCode);
427
    }
428
429
    /**
430
     * Returns a new instance from a JSON string
431
     *
432
     * @param string $json    The string being decoded
433
     * @param int    $depth   User specified recursion depth.
434
     * @param int    $options Bitmask of JSON decode options
435
     *
436
     * @throws InvalidArgumentException If the string can not be decode
437
     *
438
     * @return static
439
     */
440
    public static function createFromString($json, $depth = 512, $options = 0)
441
    {
442
        $raw = json_decode($json, true, $depth, $options);
443
        if (JSON_ERROR_NONE !== json_last_error()) {
444
            throw new InvalidArgumentException(sprintf(
445
                'Unable to decode the submitted JSON string: %s',
446
                json_last_error_msg()
447
            ));
448
        }
449
450
        return static::createFromArray($raw);
451
    }
452
453
    /**
454
     * @inheritdoc
455
     */
456
    public static function __set_state(array $properties)
457
    {
458
        return static::createFromArray($properties);
459
    }
460
461
    /**
462
     * Returns a new instance from an array
463
     *
464
     * @param array $arr The array to build a new JSend object with
465
     *
466
     * @return static
467
     */
468
    public static function createFromArray(array $arr)
469
    {
470
        $defaultValues = ['status' => null, 'data' => null, 'message' => null, 'code' => null];
471
        $arr = array_replace($defaultValues, array_intersect_key($arr, $defaultValues));
472
473
        return new static($arr['status'], $arr['data'], $arr['message'], $arr['code']);
474
    }
475
}
476