Completed
Push — feature/app ( 3205d0...2d92a3 )
by Yo
02:41 queued 55s
created

RawRequestSerializer::deserialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Yoanm\JsonRpcServer\Infra\Serialization;
4
5
use Yoanm\JsonRpcServer\App\Serialization\RequestDenormalizer;
6
use Yoanm\JsonRpcServer\Domain\Exception\JsonRpcInvalidRequestException;
7
use Yoanm\JsonRpcServer\Domain\Exception\JsonRpcParseErrorException;
8
use Yoanm\JsonRpcServer\Infra\RawObject\JsonRpcRawRequest;
9
10
/**
11
 * Class RawRequestSerializer
12
 */
13
class RawRequestSerializer
14
{
15
    const KEY_JSON_RPC = 'json-rpc';
16
    const KEY_ID = 'id';
17
    const KEY_METHOD = 'method';
18
    const KEY_PARAM_LIST = 'params';
19
20
    /** @var RequestDenormalizer */
21
    private $requestDenormalizer;
22
23
    /**
24
     * @param RequestDenormalizer $requestDenormalizer
25
     */
26 28
    public function __construct(RequestDenormalizer $requestDenormalizer)
27
    {
28 28
        $this->requestDenormalizer = $requestDenormalizer;
29 28
    }
30
31
    /**
32
     * @param string $content
33
     *
34
     * @return JsonRpcRawRequest
35
     */
36 7
    public function deserialize(string $content) : JsonRpcRawRequest
37
    {
38 7
        return $this->denormalize(
39 7
            $this->decode($content)
40
        );
41
    }
42
43
    /**
44
     * @param string $requestContent
45
     *
46
     * @return array Decoded content
47
     *
48
     * @throws JsonRpcParseErrorException
49
     */
50 19
    public function decode(string $requestContent) : array
51
    {
52 19
        $decodedContent = json_decode($requestContent, true);
53
54
        // Check if parsing is ok => Parse error
55 19
        if (JSON_ERROR_NONE !== json_last_error()) {
56 1
            throw new JsonRpcParseErrorException(
57 1
                $requestContent,
58 1
                json_last_error(),
59 1
                json_last_error_msg()
60
            );
61
        }
62
63
        // Content must be either an array (normal request) or an array of array (batch request)
64
        //  => so must be an array
65 18
        if (!is_array($decodedContent)) {
66 4
            throw new JsonRpcInvalidRequestException($requestContent);
67
        }
68
69 14
        return $decodedContent;
70
    }
71
72
    /**
73
     * @param array $decodedContent
74
     *
75
     * @return JsonRpcRawRequest
76
     */
77 16
    public function denormalize(array $decodedContent) : JsonRpcRawRequest
78
    {
79 16
        $isBatch = $this->guessBatchOrNot($decodedContent);
80
81 16
        $rawRequest = new JsonRpcRawRequest($isBatch);
82
83 16
        $this->populateItem($rawRequest, $decodedContent);
84
85 16
        return $rawRequest;
86
    }
87
88
    /**
89
     * @param array $decodedContent
90
     *
91
     * @return bool
92
     */
93 16
    private function guessBatchOrNot(array $decodedContent)
94
    {
95 16
        $isBatch = true;
96
        // Loop over each items
97
        // -> In case it's a valid batch request -> all keys will have numeric type -> iterations = Number of requests
98
        // -> In case it's a valid normal request -> all keys will have string type -> iterations = 1 (stopped on #1)
99
        // => Better performance for normal request (Probably most of requests)
100 16
        foreach ($decodedContent as $key => $item) {
101
            // At least a key is a string (that do not contain an int)
102 16
            if (!is_int($key)) {
103 13
                $isBatch = false;
104 16
                break;
105
            }
106
        }
107
108 16
        return $isBatch;
109
    }
110
111
    /**
112
     * @param JsonRpcRawRequest $rawRequest
113
     * @param array $decodedContent
114
     */
115 16
    private function populateItem(JsonRpcRawRequest $rawRequest, array $decodedContent)
116
    {
117
        // convert to array in any cases for simpler use
118 16
        $itemList = $rawRequest->isBatch() ? $decodedContent : [$decodedContent];
119 16
        foreach ($itemList as $item) {
120
            // Safely denormalize items
121
            try {
122 16
                $rawRequest->addRequestItem(
123 16
                    $this->requestDenormalizer->denormalize($item)
124
                );
125 2
            } catch (\Exception $exception) {
126 16
                $rawRequest->addExceptionItem($exception);
127
            }
128
        }
129 16
    }
130
}
131