Completed
Branch master (9645b9)
by Neomerx
02:19
created

IdentifierAndResource::getRelationships()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
nc 7
nop 0
dl 0
loc 53
ccs 36
cts 36
cp 1
crap 7
rs 8.0921
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Neomerx\JsonApi\Parser;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Neomerx\JsonApi\Contracts\Factories\FactoryInterface;
22
use Neomerx\JsonApi\Contracts\Parser\ParserInterface;
23
use Neomerx\JsonApi\Contracts\Parser\PositionInterface;
24
use Neomerx\JsonApi\Contracts\Parser\ResourceInterface;
25
use Neomerx\JsonApi\Contracts\Schema\LinkInterface;
26
use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface;
27
use Neomerx\JsonApi\Contracts\Schema\SchemaInterface;
28
use Neomerx\JsonApi\Parser\RelationshipData\ParseRelationshipDataTrait;
29
use Neomerx\JsonApi\Parser\RelationshipData\ParseRelationshipLinksTrait;
30
31
/**
32
 * @package Neomerx\JsonApi
33
 */
34
class IdentifierAndResource implements ResourceInterface
35
{
36
    use ParseRelationshipDataTrait, ParseRelationshipLinksTrait;
37
38
    /** @var string */
39
    public const MSG_NO_SCHEMA_FOUND = 'No Schema found for resource `%s` at path `%s`.';
40
41
    /** @var string */
42
    public const MSG_INVALID_OPERATION = 'Invalid operation.';
43
44
    /**
45
     * @var PositionInterface
46
     */
47
    private $position;
48
49
    /**
50
     * @var FactoryInterface
51
     */
52
    private $factory;
53
54
    /**
55
     * @var SchemaContainerInterface
56
     */
57
    private $schemaContainer;
58
59
    /**
60
     * @var SchemaInterface
61
     */
62
    private $schema;
63
64
    /**
65
     * @var mixed
66
     */
67
    private $data;
68
69
    /**
70
     * @var string
71
     */
72
    private $index;
73
74
    /**
75
     * @var string
76
     */
77
    private $type;
78
79
    /**
80
     * @var null|array
81
     */
82
    private $links = null;
83
84
    /**
85
     * @var null|array
86
     */
87
    private $relationshipsCache = null;
88
89
    /**
90
     * @param PositionInterface        $position
91
     * @param FactoryInterface         $factory
92
     * @param SchemaContainerInterface $container
93
     * @param mixed                    $data
94
     */
95 60
    public function __construct(
96
        PositionInterface $position,
97
        FactoryInterface $factory,
98
        SchemaContainerInterface $container,
99
        $data
100
    ) {
101 60
        $schema = $container->getSchema($data);
102
        $this
103 60
            ->setPosition($position)
104 60
            ->setFactory($factory)
105 60
            ->setSchemaContainer($container)
106 60
            ->setSchema($schema)
107 60
            ->setData($data);
108 60
    }
109
110
    /**
111
     * @inheritdoc
112
     */
113 60
    public function getPosition(): PositionInterface
114
    {
115 60
        return $this->position;
116
    }
117
118
    /**
119
     * @inheritdoc
120
     */
121 60
    public function getId(): ?string
122
    {
123 60
        return $this->index;
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129 60
    public function getType(): string
130
    {
131 60
        return $this->type;
132
    }
133
134
    /**
135
     * @inheritdoc
136
     */
137 31
    public function hasIdentifierMeta(): bool
138
    {
139 31
        return $this->getSchema()->hasIdentifierMeta($this->getData());
140
    }
141
142
    /**
143
     * @inheritdoc
144
     */
145 2
    public function getIdentifierMeta()
146
    {
147 2
        return $this->getSchema()->getIdentifierMeta($this->getData());
148
    }
149
150
    /**
151
     * @inheritdoc
152
     */
153 57
    public function getAttributes(): iterable
154
    {
155 57
        return $this->getSchema()->getAttributes($this->getData());
156
    }
157
158
    /**
159
     * @inheritdoc
160
     */
161 60
    public function getRelationships(): iterable
162
    {
163 60
        if ($this->relationshipsCache !== null) {
164 57
            yield from $this->relationshipsCache;
165
166 56
            return;
167
        }
168
169 60
        $this->relationshipsCache = [];
170
171 60
        $currentPath    = $this->getPosition()->getPath();
172 60
        $nextLevel      = $this->getPosition()->getLevel() + 1;
173 60
        $nextPathPrefix = empty($currentPath) === true ? '' : $currentPath . PositionInterface::PATH_SEPARATOR;
174 60
        foreach ($this->getSchema()->getRelationships($this->getData()) as $name => $description) {
175 45
            assert($this->assertRelationshipNameAndDescription($name, $description) === true);
176
177 45
            [$hasData, $relationshipData, $nextPosition] = $this->parseRelationshipData(
0 ignored issues
show
Bug introduced by
The variable $hasData does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $relationshipData does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $nextPosition does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
178 45
                $this->getFactory(),
179 45
                $this->getSchemaContainer(),
180 45
                $this->getType(),
181 45
                $name,
182 45
                $description,
183 45
                $nextLevel,
184 45
                $nextPathPrefix
185
            );
186
187
            [$hasLinks, $links] =
0 ignored issues
show
Bug introduced by
The variable $hasLinks does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $links does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
188 45
                $this->parseRelationshipLinks($this->getSchema(), $this->getData(), $name, $description);
189
190 45
            $hasMeta = array_key_exists(SchemaInterface::RELATIONSHIP_META, $description);
191 45
            $meta    = $hasMeta === true ? $description[SchemaInterface::RELATIONSHIP_META] : null;
192
193 45
            assert(
194 45
                $hasData || $hasMeta || $hasLinks,
195 45
                "Relationship `$name` for type `" . $this->getType() .
196 45
                '` MUST contain at least one of the following: links, data or meta.'
197
            );
198
199 45
            $relationship = $this->getFactory()->createRelationship(
200 45
                $nextPosition,
201 45
                $hasData,
202 45
                $relationshipData,
203 45
                $hasLinks,
204 45
                $links,
205 45
                $hasMeta,
206 45
                $meta
207
            );
208
209 45
            $this->relationshipsCache[$name] = $relationship;
210
211 45
            yield $name => $relationship;
212
        }
213 60
    }
214
215
    /**
216
     * @inheritdoc
217
     */
218 57
    public function hasLinks(): bool
219
    {
220 57
        $this->cacheLinks();
221
222 57
        return empty($this->links) === false;
223
    }
224
225
    /**
226
     * @inheritdoc
227
     */
228 56
    public function getLinks(): iterable
229
    {
230 56
        $this->cacheLinks();
231
232 56
        return $this->links;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->links; of type null|array adds the type array to the return on line 232 which is incompatible with the return type declared by the interface Neomerx\JsonApi\Contract...urceInterface::getLinks of type Neomerx\JsonApi\Contracts\Parser\iterable.
Loading history...
233
    }
234
235
    /**
236
     * @inheritdoc
237
     */
238 57
    public function hasResourceMeta(): bool
239
    {
240 57
        return $this->getSchema()->hasResourceMeta($this->getData());
241
    }
242
243
    /**
244
     * @inheritdoc
245
     */
246 1
    public function getResourceMeta()
247
    {
248 1
        return $this->getSchema()->getResourceMeta($this->getData());
249
    }
250
251
    /**
252
     * @inheritdoc
253
     */
254 60
    protected function setPosition(PositionInterface $position): self
255
    {
256 60
        assert($position->getLevel() >= ParserInterface::ROOT_LEVEL);
257
258 60
        $this->position = $position;
259
260 60
        return $this;
261
    }
262
263
    /**
264
     * @return FactoryInterface
265
     */
266 45
    protected function getFactory(): FactoryInterface
267
    {
268 45
        return $this->factory;
269
    }
270
271
    /**
272
     * @param FactoryInterface $factory
273
     *
274
     * @return self
275
     */
276 60
    protected function setFactory(FactoryInterface $factory): self
277
    {
278 60
        $this->factory = $factory;
279
280 60
        return $this;
281
    }
282
283
    /**
284
     * @return SchemaContainerInterface
285
     */
286 45
    protected function getSchemaContainer(): SchemaContainerInterface
287
    {
288 45
        return $this->schemaContainer;
289
    }
290
291
    /**
292
     * @param SchemaContainerInterface $container
293
     *
294
     * @return self
295
     */
296 60
    protected function setSchemaContainer(SchemaContainerInterface $container): self
297
    {
298 60
        $this->schemaContainer = $container;
299
300 60
        return $this;
301
    }
302
303
    /**
304
     * @return SchemaInterface
305
     */
306 60
    protected function getSchema(): SchemaInterface
307
    {
308 60
        return $this->schema;
309
    }
310
311
    /**
312
     * @param SchemaInterface $schema
313
     *
314
     * @return self
315
     */
316 60
    protected function setSchema(SchemaInterface $schema): self
317
    {
318 60
        $this->schema = $schema;
319
320 60
        return $this;
321
    }
322
323
    /**
324
     * @return mixed
325
     */
326 60
    protected function getData()
327
    {
328 60
        return $this->data;
329
    }
330
331
    /**
332
     * @param mixed $data
333
     *
334
     * @return self
335
     */
336 60
    protected function setData($data): self
337
    {
338 60
        $this->data  = $data;
339 60
        $this->index = $this->getSchema()->getId($data);
340 60
        $this->type  = $this->getSchema()->getType();
341
342 60
        return $this;
343
    }
344
345
    /**
346
     * Read and parse links from schema.
347
     */
348 57
    private function cacheLinks(): void
349
    {
350 57
        if ($this->links === null) {
351 57
            $this->links = [];
352 57
            foreach ($this->getSchema()->getLinks($this->getData()) as $name => $link) {
353 56
                assert(is_string($name) === true && empty($name) === false);
354 56
                assert($link instanceof LinkInterface);
355 56
                $this->links[$name] = $link;
356
            }
357
        }
358 57
    }
359
360
    /**
361
     * @param string $name
362
     * @param array  $description
363
     *
364
     * @return bool
365
     */
366 45
    private function assertRelationshipNameAndDescription(string $name, array $description): bool
367
    {
368 45
        assert(
369 45
            is_string($name) === true && empty($name) === false,
370 45
            "Relationship names for type `" . $this->getType() . '` should be non-empty strings.'
371
        );
372 45
        assert(
373 45
            is_array($description) === true && empty($description) === false,
374 45
            "Relationship `$name` for type `" . $this->getType() . '` should be a non-empty array.'
375
        );
376
377 45
        return true;
378
    }
379
}
380