Completed
Branch master (195c43)
by
unknown
04:51
created

IdentifierAndResource::setData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
        \assert($position->getLevel() >= ParserInterface::ROOT_LEVEL);
102
103 60
        $schema = $container->getSchema($data);
104
105 60
        $this->position        = $position;
106 60
        $this->factory         = $factory;
107 60
        $this->schemaContainer = $container;
108 60
        $this->schema          = $schema;
109 60
        $this->data            = $data;
110 60
        $this->index           = $schema->getId($data);
111 60
        $this->type            = $schema->getType();
112 60
    }
113
114
    /**
115
     * @inheritdoc
116
     */
117 60
    public function getPosition(): PositionInterface
118
    {
119 60
        return $this->position;
120
    }
121
122
    /**
123
     * @inheritdoc
124
     */
125 60
    public function getId(): ?string
126
    {
127 60
        return $this->index;
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133 60
    public function getType(): string
134
    {
135 60
        return $this->type;
136
    }
137
138
    /**
139
     * @inheritdoc
140
     */
141 31
    public function hasIdentifierMeta(): bool
142
    {
143 31
        return $this->schema->hasIdentifierMeta($this->data);
144
    }
145
146
    /**
147
     * @inheritdoc
148
     */
149 2
    public function getIdentifierMeta()
150
    {
151 2
        return $this->schema->getIdentifierMeta($this->data);
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157 57
    public function getAttributes(): iterable
158
    {
159 57
        return $this->schema->getAttributes($this->data);
160
    }
161
162
    /**
163
     * @inheritdoc
164
     */
165 60
    public function getRelationships(): iterable
166
    {
167 60
        if ($this->relationshipsCache !== null) {
168 57
            yield from $this->relationshipsCache;
169
170 56
            return;
171
        }
172
173 60
        $this->relationshipsCache = [];
174
175 60
        $currentPath    = $this->position->getPath();
176 60
        $nextLevel      = $this->position->getLevel() + 1;
177 60
        $nextPathPrefix = empty($currentPath) === true ? '' : $currentPath . PositionInterface::PATH_SEPARATOR;
178 60
        foreach ($this->schema->getRelationships($this->data) as $name => $description) {
179 45
            \assert($this->assertRelationshipNameAndDescription($name, $description) === true);
180
181 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...
182 45
                $this->factory,
183 45
                $this->schemaContainer,
184 45
                $this->type,
185 45
                $name,
186 45
                $description,
187 45
                $nextLevel,
188 45
                $nextPathPrefix
189
            );
190
191
            [$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...
192 45
                $this->parseRelationshipLinks($this->schema, $this->data, $name, $description);
193
194 45
            $hasMeta = \array_key_exists(SchemaInterface::RELATIONSHIP_META, $description);
195 45
            $meta    = $hasMeta === true ? $description[SchemaInterface::RELATIONSHIP_META] : null;
196
197 45
            \assert(
198 45
                $hasData || $hasMeta || $hasLinks,
199 45
                "Relationship `$name` for type `" . $this->getType() .
200 45
                '` MUST contain at least one of the following: links, data or meta.'
201
            );
202
203 45
            $relationship = $this->factory->createRelationship(
204 45
                $nextPosition,
205 45
                $hasData,
206 45
                $relationshipData,
207 45
                $hasLinks,
208 45
                $links,
209 45
                $hasMeta,
210 45
                $meta
211
            );
212
213 45
            $this->relationshipsCache[$name] = $relationship;
214
215 45
            yield $name => $relationship;
216
        }
217 60
    }
218
219
    /**
220
     * @inheritdoc
221
     */
222 57
    public function hasLinks(): bool
223
    {
224 57
        $this->cacheLinks();
225
226 57
        return empty($this->links) === false;
227
    }
228
229
    /**
230
     * @inheritdoc
231
     */
232 56
    public function getLinks(): iterable
233
    {
234 56
        $this->cacheLinks();
235
236 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 236 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...
237
    }
238
239
    /**
240
     * @inheritdoc
241
     */
242 57
    public function hasResourceMeta(): bool
243
    {
244 57
        return $this->schema->hasResourceMeta($this->data);
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250 1
    public function getResourceMeta()
251
    {
252 1
        return $this->schema->getResourceMeta($this->data);
253
    }
254
255
    /**
256
     * Read and parse links from schema.
257
     */
258 57
    private function cacheLinks(): void
259
    {
260 57
        if ($this->links === null) {
261 57
            $this->links = [];
262 57
            foreach ($this->schema->getLinks($this->data) as $name => $link) {
263 56
                \assert(\is_string($name) === true && empty($name) === false);
264 56
                \assert($link instanceof LinkInterface);
265 56
                $this->links[$name] = $link;
266
            }
267
        }
268 57
    }
269
270
    /**
271
     * @param string $name
272
     * @param array  $description
273
     *
274
     * @return bool
275
     */
276 45
    private function assertRelationshipNameAndDescription(string $name, array $description): bool
277
    {
278 45
        \assert(
279 45
            \is_string($name) === true && empty($name) === false,
280 45
            "Relationship names for type `" . $this->getType() . '` should be non-empty strings.'
281
        );
282 45
        \assert(
283 45
            \is_array($description) === true && empty($description) === false,
284 45
            "Relationship `$name` for type `" . $this->getType() . '` should be a non-empty array.'
285
        );
286
287 45
        return true;
288
    }
289
}
290