Request::extractMethod()   A
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 10
cc 4
nc 2
nop 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Boomdraw\RpcCore;
6
7
use Boomdraw\RpcCore\Exceptions\InvalidRequestRpcException;
8
use Boomdraw\RpcCore\Exceptions\ParseErrorRpcException;
9
use Illuminate\Http\Request as BaseRequest;
10
use JsonException;
11
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
12
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
13
use Throwable;
14
15
class Request extends BaseRequest
16
{
17
    /** @var string called rpc method. */
18
    protected string $rpcMethod;
19
20
    /** @var ContextBag provided context. */
21
    protected ContextBag $context;
22
23
    /**
24
     * Request constructor.
25
     *
26
     * @param string $rpcMethod
27
     * @param array $request
28
     * @param array $server
29
     * @param string|resource|null $content
30
     * @param array $context
31
     */
32 26
    public function __construct(
33
        string $rpcMethod,
34
        array $request = [],
35
        array $server = [],
36
        $content = null,
37
        array $context = []
38
    ) {
39 26
        parent::__construct([], $request, [], [], [], $server, $content);
40
41 26
        $this->rpcMethod = $rpcMethod;
42 26
        $this->context = new ContextBag($context);
43 26
    }
44
45
    /**
46
     * Create an RPC request from a Symfony instance.
47
     *
48
     * @param SymfonyRequest $request
49
     * @return Request
50
     * @throws InvalidRequestRpcException
51
     * @throws ParseErrorRpcException|JsonException|BadRequestException
52
     */
53 32
    public static function createFromBase(SymfonyRequest $request): self
54
    {
55 32
        if ($request instanceof self) {
56 23
            return $request;
57
        }
58
59 32
        $input = self::getInput($request);
60 29
        $method = self::extractMethod($input);
61 26
        $params = data_get($input, 'params', []);
62 26
        $args = data_get($params, 'args', []);
63 26
        $context = (array) data_get($params, 'context', []);
64 26
        if (empty($args) && empty($context)) {
65 22
            $args = $params;
66
        }
67 26
        data_set($context, 'requestId', data_get($input, 'id'));
68
69 26
        return new self($method, (array) $args, self::getServer(), json_encode($args, JSON_THROW_ON_ERROR), $context);
70
    }
71
72
    /**
73
     * Return rpc method name.
74
     *
75
     * @return string
76
     */
77 26
    public function getRpcMethod(): string
78
    {
79 26
        return $this->rpcMethod;
80
    }
81
82
    /**
83
     * Retrieve a context item from the request.
84
     *
85
     * @param string|null $key
86
     * @param mixed $default
87
     * @return string|array|null
88
     */
89 21
    public function context(?string $key = null, $default = null)
90
    {
91 21
        return $this->retrieveItem('context', $key, $default);
92
    }
93
94
    /**
95
     * Determine if a context item is set on the request.
96
     *
97
     * @param string $key
98
     * @return bool
99
     */
100 1
    public function hasContext(string $key): bool
101
    {
102 1
        return ! is_null($this->context($key));
103
    }
104
105
    /**
106
     * Return request input.
107
     *
108
     * @param SymfonyRequest $request
109
     * @return object
110
     * @throws ParseErrorRpcException|BadRequestException
111
     */
112 32
    protected static function getInput(SymfonyRequest $request): object
113
    {
114 32
        $input = $request->request->all();
115 32
        if (! empty($input)) {
116 29
            return (object) $input;
117
        }
118
119
        try {
120 3
            $input = file_get_contents('php://input');
121
122 3
            return json_decode($input, false, 512, JSON_THROW_ON_ERROR);
123 3
        } catch (Throwable $exception) {
124 3
            throw new ParseErrorRpcException();
125
        }
126
    }
127
128
    /**
129
     * Extract JsonRPC method from input.
130
     *
131
     * @param object $input
132
     * @return string
133
     * @throws InvalidRequestRpcException
134
     */
135 29
    protected static function extractMethod(object $input): string
136
    {
137 29
        $jsonrpc = data_get($input, 'jsonrpc');
138 29
        $method = data_get($input, 'method');
139 29
        if (! $method || is_numeric($method[0]) || $jsonrpc !== '2.0') {
140 3
            throw new InvalidRequestRpcException();
141
        }
142
143 26
        return $method;
144
    }
145
146
    /**
147
     * Return $_SERVER variables with forced content type and accept headers.
148
     *
149
     * @return array
150
     */
151 26
    protected static function getServer(): array
152
    {
153 26
        $server = $_SERVER;
154 26
        $server['HTTP_CONTENT_TYPE'] = $server['CONTENT_TYPE'] = $server['HTTP_ACCEPT'] = 'application/json';
155
156 26
        return $server;
157
    }
158
}
159