Passed
Pull Request — 1.x (#250)
by Akihito
03:26 queued 01:40
created

AbstractRequest::serialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource;
6
7
use ArrayAccess;
8
use ArrayIterator;
9
use BEAR\Resource\Exception\MethodException;
10
use BEAR\Resource\Exception\OutOfBoundsException;
11
use IteratorAggregate;
12
use JsonSerializable;
13
use LogicException;
14
use ReturnTypeWillChange;
15
use Throwable;
16
17
use function array_merge;
18
use function assert;
19
use function get_class;
20
use function in_array;
21
use function is_array;
22
use function md5;
23
use function serialize;
24
use function strtolower;
25
use function trigger_error;
26
27
use const E_USER_ERROR;
28
use const PHP_EOL;
29
30
/**
31
 * @property int    $code
32
 * @property array  $headers
33
 * @property mixed  $body
34
 * @property string $view
35
 * @phpstan-implements IteratorAggregate<string, mixed>
36
 * @phpstan-implements ArrayAccess<string, mixed>
37
 * @psalm-suppress PropertyNotSetInConstructor
38
 */
39
abstract class AbstractRequest implements RequestInterface, ArrayAccess, IteratorAggregate, JsonSerializable
40
{
41
    /**
42
     * URI
43
     *
44
     * @var string
45
     */
46
    public $uri;
47
48
    /**
49
     * Method
50
     *
51
     * @var string
52
     */
53
    public $method = '';
54
55
    /**
56
     * Query
57
     *
58
     * @var array<string, mixed>
59
     */
60
    public $query = [];
61
62
    /**
63
     * Options
64
     *
65
     * @var array<mixed>
66
     */
67
    public $options = [];
68
69
    /**
70
     * Request option (eager or lazy)
71
     *
72
     * @var 'eager'|'lazy'
0 ignored issues
show
Documentation Bug introduced by
The doc comment 'eager'|'lazy' at position 0 could not be parsed: Unknown type name ''eager'' at position 0 in 'eager'|'lazy'.
Loading history...
73
     */
74
    public $in = 'lazy'; // phpcs:ignore SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
75
76
    /**
77
     * Links
78
     *
79
     * @var LinkType[]
80
     */
81
    public $links = [];
82
83
    /** @var ResourceObject */
84
    public $resourceObject;
85
86
    /**
87
     * Request Result
88
     *
89
     * @var ?ResourceObject
90
     */
91
    protected $result;
92
93
    /** @var InvokerInterface */
94
    protected $invoker;
95
96
    /** @var ?LinkerInterface */
97
    private $linker;
98
99 91
    /**
100
     * @param array<string, mixed> $query
101
     * @param list<LinkType>       $links
0 ignored issues
show
Bug introduced by
The type BEAR\Resource\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
102
     *
103
     * @throws MethodException
104
     */
105
    public function __construct(
106
        InvokerInterface $invoker,
107 91
        ResourceObject $ro,
108 91
        string $method = Request::GET,
109 91
        array $query = [],
110 1
        array $links = [],
111
        ?LinkerInterface $linker = null
112 91
    ) {
113 91
        $this->invoker = $invoker;
114 91
        $this->resourceObject = $ro;
115 91
        if (! in_array(strtolower($method), ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'], true)) {
116 91
            throw new MethodException($method, 400);
117
        }
118 6
119
        $this->method = $method;
120
        $this->query = $query;
121 6
        $this->links = $links;
122
        $this->linker = $linker;
123 5
    }
124 1
125 1
    public function __toString(): string
126
    {
127 1
        try {
128
            $this->invoke();
129
130
            return (string) $this->result;
131
        } catch (Throwable $e) {
132
            trigger_error($e->getMessage() . PHP_EOL . $e->getTraceAsString(), E_USER_ERROR);
133
134 56
            return '';
135
        }
136 56
    }
137 15
138
    /**
139 56
     * {@inheritdoc}
140 56
     *
141 3
     * @param array<string, mixed> $query
142
     */
143
    public function __invoke(?array $query = null): ResourceObject
144 53
    {
145
        if (is_array($query)) {
146
            $this->query = array_merge($this->query, $query);
147
        }
148
149
        $this->resourceObject->uri->query = $this->query;
150 3
        if ($this->links && $this->linker instanceof LinkerInterface) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->links of type BEAR\Resource\LinkType[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
151
            return $this->linker->invoke($this);
152 3
        }
153
154 3
        return clone $this->invoker->invoke($this);
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     *
160
     * @return mixed
161
     */
162 1
    public function __get(string $name)
163
    {
164 1
        $this->result = $this->invoke();
165
166
        return $this->result->{$name};
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     *
172 1
     * @throws OutOfBoundsException
173
     */
174 1
    #[ReturnTypeWillChange]
175
    public function offsetSet($offset, $value)
176 1
    {
177
        throw new OutOfBoundsException(__METHOD__ . ' is unavailable.', 400);
178
    }
179
180
    /**
181
     * {@inheritdoc}
182 26
     *
183
     * @throws OutOfBoundsException
184 26
     */
185 19
    #[ReturnTypeWillChange]
186
    public function offsetUnset($offset)
187 17
    {
188
        unset($offset);
189
190 8
        throw new OutOfBoundsException(__METHOD__ . ' is unavailable.', 400);
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196
    public function request()
197
    {
198 2
        if ($this->in === 'eager') {
199
            $this->result = $this->invoke();
200 2
201 2
            return $this->result;
202 1
        }
203
204
        return $this;
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     *
210
     * @param string $offset
211
     *
212
     * @return mixed
213 2
     *
214
     * @throws OutOfBoundsException
215 2
     */
216
    #[ReturnTypeWillChange]
217
    public function offsetGet($offset)
218
    {
219
        $this->invoke();
220
        assert($this->result instanceof ResourceObject);
221
        if (! is_array($this->result->body) || ! isset($this->result->body[$offset])) {
222
            throw new OutOfBoundsException("[{$offset}] for object[" . get_class($this->result) . ']', 400);
223 1
        }
224 1
225
        return $this->result->body[$offset];
226 1
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    #[ReturnTypeWillChange]
232
    public function offsetExists($offset): bool
233
    {
234 5
        $this->invoke();
235
        assert($this->result instanceof ResourceObject);
236
237
        return isset($this->result->body[$offset]);
238
    }
239
240
    /**
241
     * Invoke resource request then return resource body iterator
242 1
     *
243
     * @psalm-return ArrayIterator
244
     * @phpstan-return ArrayIterator<string, mixed>
245
     */
246
    public function getIterator(): ArrayIterator
247
    {
248
        $this->invoke();
249
        assert($this->result instanceof ResourceObject);
250
251
        return is_array($this->result->body) ? new ArrayIterator($this->result->body) : new ArrayIterator([]);
252
    }
253
254
    /**
255 33
     * {@inheritdoc}
256
     */
257 32
    public function hash(): string
258
    {
259
        return md5(get_class($this->resourceObject) . $this->method . serialize($this->query) . serialize($this->links));
260 30
    }
261
262
    /**
263
     * {@inheritdoc}
264
     *
265
     * @return never
0 ignored issues
show
Bug introduced by
The type BEAR\Resource\never was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
266
     */
267
    public function __serialize()
268
    {
269
        throw new LogicException(__METHOD__ . ' not supported');
270
    }
271
272
    private function invoke(): ResourceObject
273
    {
274
        if ($this->result === null) {
275
            /* @noinspection ImplicitMagicMethodCallInspection */
276
            $this->result = ($this)();
277
        }
278
279
        return $this->result;
280
    }
281
282
    public function jsonSerialize(): ResourceObject
283
    {
284
        return $this->invoke();
285
    }
286
}
287