Completed
Push — master ( 4bee86...913926 )
by Denis
04:17
created

ResponseParser::parse()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 35
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 21
nc 8
nop 1
1
<?php
2
3
namespace PhpJsonRpc\Client;
4
5
use PhpJsonRpc\Core\Result\ResultError;
6
use PhpJsonRpc\Core\Result\ResultUnit;
7
use PhpJsonRpc\Core\ResultSpecifier;
8
use PhpJsonRpc\Error\ServerErrorException;
9
use PhpJsonRpc\Error\ParseErrorException;
10
use PhpJsonRpc\Error\InvalidResponseException;
11
12
class ResponseParser
13
{
14
    /**
15
     * @param string $payload
16
     *
17
     * @return ResultSpecifier
18
     */
19
    public function parse(string $payload): ResultSpecifier
20
    {
21
        $data = @json_decode($payload, true);
22
23
        if (!is_array($data)) {
24
            throw new ParseErrorException();
25
        }
26
27
        $units = [];
28
29
        if ($this->isSingleResponse($data)) {
30
            if ($this->isValidResult($data)) {
31
                $units[] = new ResultUnit($data['id'], $data['result']);
32
            } elseif ($this->isValidError($data)) {
33
                $units[] = new ResultError($data['id'], new ServerErrorException());
34
            } else {
35
                throw new InvalidResponseException();
36
            }
37
38
            return new ResultSpecifier($units, true);
39
        }
40
41
        /** @var array $data */
42
        foreach ($data as $response) {
43
            if ($this->isValidResult($response)) {
44
                $units[] = new ResultUnit($response['id'], $response['result']);
45
            } elseif ($this->isValidError($response)) {
46
                $units[] = new ResultError($response['id'], new ServerErrorException($response['error']['message'], $response['error']['code']));
47
            } else {
48
                throw new InvalidResponseException();
49
            }
50
        }
51
52
        return new ResultSpecifier($units, false);
53
    }
54
55
    /**
56
     * @param array $response
57
     * @return bool
58
     */
59
    private function isSingleResponse(array $response): bool
60
    {
61
        return array_keys($response) !== range(0, count($response) - 1);
62
    }
63
64
    /**
65
     * @param array $payload
66
     * @return bool
67
     */
68
    private function isValidResult($payload): bool
69
    {
70
        if (!is_array($payload)) {
71
            return false;
72
        }
73
74
        $headerValid = array_key_exists('jsonrpc', $payload) && $payload['jsonrpc'] === '2.0';
75
        $resultValid = array_key_exists('result', $payload);
76
        $idValid     = array_key_exists('id', $payload);
77
78
        return $headerValid && $resultValid && $idValid;
79
    }
80
81
    /**
82
     * @param array $payload
83
     * @return bool
84
     */
85
    private function isValidError($payload): bool
86
    {
87
        if (!is_array($payload)) {
88
            return false;
89
        }
90
91
        $headerValid = array_key_exists('jsonrpc', $payload) && $payload['jsonrpc'] === '2.0';
92
        $errorValid  = array_key_exists('error', $payload) && is_array($payload['error'])
93
                       && array_key_exists('code', $payload['error']) && is_int($payload['error']['code'])
94
                       && array_key_exists('message', $payload['error']) && is_string($payload['error']['message']);
95
        $idValid     = array_key_exists('id', $payload);
96
97
        return $headerValid && $errorValid && $idValid;
98
    }
99
}
100