EncoderPropertiesTrait::withLinks()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
c 0
b 0
f 0
cc 2
nc 2
nop 1
ccs 7
cts 7
cp 1
crap 2
rs 9.9
1
<?php declare(strict_types=1);
2
3
namespace Neomerx\JsonApi\Encoder;
4
5
/**
6
 * Copyright 2015-2020 [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\Encoder\EncoderInterface;
22
use Neomerx\JsonApi\Contracts\Factories\FactoryInterface;
23
use Neomerx\JsonApi\Contracts\Schema\LinkInterface;
24
use Neomerx\JsonApi\Contracts\Schema\SchemaContainerInterface;
25
use Traversable;
26
27
/**
28
 * @package Neomerx\JsonApi
29
 */
30
trait EncoderPropertiesTrait
31
{
32
    /**
33
     * @var SchemaContainerInterface
34
     */
35
    private $container;
36
37
    /**
38
     * @var FactoryInterface
39
     */
40
    private $factory;
41
42
    /**
43
     * @var string
44
     */
45
    private $urlPrefix;
46
47
    /**
48
     * @var array
49
     */
50
    private $includePaths;
51
52
    /**
53
     * @var array
54
     */
55
    private $fieldSets;
56
57
    /**
58
     * @var int
59
     */
60
    private $encodeOptions;
61
62
    /**
63
     * @var int
64
     */
65
    private $encodeDepth;
66
67
    /**
68
     * @var iterable
69
     */
70
    private $links;
71
72
    /**
73
     * @var iterable
74
     */
75
    private $profile;
76
77
    /**
78
     * @var bool
79
     */
80
    private $hasMeta;
81
82
    /**
83
     * @var mixed
84
     */
85
    private $meta;
86
87
    /**
88
     * @var string|null
89
     */
90
    private $jsonApiVersion;
91
92
    /**
93
     * @var mixed
94
     */
95
    private $jsonApiMeta;
96
97
    /**
98
     * @var bool
99
     */
100
    private $hasJsonApiMeta;
101
102
    /**
103
     * Reset to initial state.
104
     *
105
     * @param string   $urlPrefix
106
     * @param iterable $includePaths
107
     * @param array    $fieldSets
108
     * @param int      $encodeOptions
109
     * @param int      $encodeDepth
110
     *
111
     * @return self|EncoderInterface
112
     */
113 87
    public function reset(
114
        string $urlPrefix = Encoder::DEFAULT_URL_PREFIX,
115
        iterable $includePaths = Encoder::DEFAULT_INCLUDE_PATHS,
116
        array $fieldSets = Encoder::DEFAULT_FIELD_SET_FILTERS,
117
        int $encodeOptions = Encoder::DEFAULT_JSON_ENCODE_OPTIONS,
118
        int $encodeDepth = Encoder::DEFAULT_JSON_ENCODE_DEPTH
119
    ): EncoderInterface {
120 87
        $this->links          = null;
121 87
        $this->profile        = null;
122 87
        $this->hasMeta        = false;
123 87
        $this->meta           = null;
124 87
        $this->jsonApiVersion = null;
125 87
        $this->jsonApiMeta    = null;
126 87
        $this->hasJsonApiMeta = false;
127
128
        $this
129 87
            ->withUrlPrefix($urlPrefix)
130 87
            ->withIncludedPaths($includePaths)
131 87
            ->withFieldSets($fieldSets)
132 87
            ->withEncodeOptions($encodeOptions)
133 87
            ->withEncodeDepth($encodeDepth);
134
135 87
        return $this;
136
    }
137
138
    /**
139
     * @return SchemaContainerInterface
140
     */
141 76
    protected function getSchemaContainer(): SchemaContainerInterface
142
    {
143 76
        return $this->container;
144
    }
145
146
    /**
147
     * @param SchemaContainerInterface $container
148
     *
149
     * @return self
150
     */
151 87
    public function setContainer(SchemaContainerInterface $container): self
152
    {
153 87
        $this->container = $container;
154
155 87
        return $this;
156
    }
157
158
    /**
159
     * @return FactoryInterface
160
     */
161 85
    protected function getFactory(): FactoryInterface
162
    {
163 85
        return $this->factory;
164
    }
165
166
    /**
167
     * @param FactoryInterface $factory
168
     *
169
     * @return self
170
     */
171 87
    public function setFactory(FactoryInterface $factory): self
172
    {
173 87
        $this->factory = $factory;
174
175 87
        return $this;
176
    }
177
178
    /**
179
     * @param string $prefix
180
     *
181
     * @return self|EncoderInterface
182
     */
183 87
    public function withUrlPrefix(string $prefix): EncoderInterface
184
    {
185 87
        $this->urlPrefix = $prefix;
186
187 87
        return $this;
188
    }
189
    /**
190
     * @return string
191
     */
192 85
    protected function getUrlPrefix(): string
193
    {
194 85
        return $this->urlPrefix;
195
    }
196
197
    /**
198
     * @param iterable $paths
199
     *
200
     * @return self|EncoderInterface
201
     */
202 87
    public function withIncludedPaths(iterable $paths): EncoderInterface
203
    {
204 87
        $paths = $this->iterableToArray($paths);
205
206 87
        \assert(
207
            \call_user_func(
208
                function (array $paths): bool {
209 87
                    $pathsOk = true;
210 87
                    foreach ($paths as $path) {
211 27
                        $pathsOk = $pathsOk === true && \is_string($path) === true && empty($path) === false;
212
                    }
213
214 87
                    return $pathsOk;
215
                },
216 87
                $paths
217
            )
218
        );
219
220 87
        $this->includePaths = $paths;
221
222 87
        return $this;
223
    }
224
225
    /**
226
     * @return array
227
     */
228 76
    protected function getIncludePaths(): array
229
    {
230 76
        return $this->includePaths;
231
    }
232
233
    /**
234
     * @param array $fieldSets
235
     *
236
     * @return self|EncoderInterface
237
     */
238 87
    public function withFieldSets(array $fieldSets): EncoderInterface
239
    {
240 87
        $this->fieldSets = $fieldSets;
241
242 87
        return $this;
243
    }
244
245
246
    /**
247
     * @return array
248
     */
249 76
    protected function getFieldSets(): array
250
    {
251 76
        return $this->fieldSets;
252
    }
253
254
    /**
255
     * @param int $options
256
     *
257
     * @return self|EncoderInterface
258
     */
259 87
    public function withEncodeOptions(int $options): EncoderInterface
260
    {
261 87
        $this->encodeOptions = $options;
262
263 87
        return $this;
264
    }
265
266
    /**
267
     * @return int
268
     */
269 79
    protected function getEncodeOptions(): int
270
    {
271 79
        return $this->encodeOptions;
272
    }
273
274
    /**
275
     * @param int $depth
276
     *
277
     * @return self|EncoderInterface
278
     */
279 87
    public function withEncodeDepth(int $depth): EncoderInterface
280
    {
281 87
        \assert($depth > 0);
282
283 87
        $this->encodeDepth = $depth;
284
285 87
        return $this;
286
    }
287
288
    /**
289
     * @return int
290
     */
291 79
    protected function getEncodeDepth(): int
292
    {
293 79
        return $this->encodeDepth;
294
    }
295
296
    /**
297
     * @param iterable $links
298
     *
299
     * @return self|EncoderInterface
300
     */
301 5
    public function withLinks(iterable $links): EncoderInterface
302
    {
303 5
        $this->links = $this->hasLinks() === false ?
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->hasLinks() === fa...erableToArray($links))) can also be of type array. However, the property $links is declared as type object<Neomerx\JsonApi\Encoder\iterable>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
304 5
            $links :
305 2
            $this->links = \array_merge(
306 2
                $this->iterableToArray($this->getLinks()),
307 2
                $this->iterableToArray($links)
308
            );
309
310 5
        return $this;
311
    }
312
313
    /**
314
     * @return bool
315
     */
316 85
    protected function hasLinks(): bool
317
    {
318 85
        return $this->links !== null;
319
    }
320
321
    /**
322
     * @return iterable
323
     */
324 5
    protected function getLinks(): iterable
325
    {
326 5
        return $this->links;
327
    }
328
329
    /**
330
     * @param iterable $links
331
     *
332
     * @return self|EncoderInterface
333
     */
334 1
    public function withProfile(iterable $links): EncoderInterface
335
    {
336 1
        $this->profile = $links;
337
338 1
        return $this;
339
    }
340
341
    /**
342
     * @return bool
343
     */
344 85
    protected function hasProfile(): bool
345
    {
346 85
        return $this->profile !== null;
347
    }
348
349
    /**
350
     * @return iterable
351
     */
352 1
    protected function getProfile(): iterable
353
    {
354 1
        return $this->profile;
355
    }
356
357
    /**
358
     * @param mixed $meta
359
     *
360
     * @return self|EncoderInterface
361
     */
362 6
    public function withMeta($meta): EncoderInterface
363
    {
364 6
        $this->meta    = $meta;
365 6
        $this->hasMeta = true;
366
367 6
        return $this;
368
    }
369
370
    /**
371
     * @return bool
372
     */
373 85
    protected function hasMeta(): bool
374
    {
375 85
        return $this->hasMeta;
376
    }
377
378
    /**
379
     * @return mixed
380
     */
381 6
    public function getMeta()
382
    {
383 6
        return $this->meta;
384
    }
385
386
    /**
387
     * @param string $version
388
     *
389
     * @return self|EncoderInterface
390
     */
391 2
    public function withJsonApiVersion(string $version): EncoderInterface
392
    {
393 2
        $this->jsonApiVersion = $version;
394
395 2
        return $this;
396
    }
397
398
    /**
399
     * @return bool
400
     */
401 85
    protected function hasJsonApiVersion(): bool
402
    {
403 85
        return $this->jsonApiVersion !== null;
404
    }
405
406
    /**
407
     * @return string
408
     */
409 2
    protected function getJsonApiVersion(): string
410
    {
411 2
        return $this->jsonApiVersion;
412
    }
413
414
    /**
415
     * @param mixed $meta
416
     *
417
     * @return self|EncoderInterface
418
     */
419 2
    public function withJsonApiMeta($meta): EncoderInterface
420
    {
421 2
        $this->jsonApiMeta    = $meta;
422 2
        $this->hasJsonApiMeta = true;
423
424 2
        return $this;
425
    }
426
427
    /**
428
     * @return bool
429
     */
430 85
    protected function hasJsonApiMeta(): bool
431
    {
432 85
        return $this->hasJsonApiMeta;
433
    }
434
435
    /**
436
     * @return mixed
437
     */
438 2
    protected function getJsonApiMeta()
439
    {
440 2
        return $this->jsonApiMeta;
441
    }
442
443
    /**
444
     * @param mixed  $resource
445
     * @param string $relationshipName
446
     *
447
     * @return self|EncoderInterface
448
     */
449 1 View Code Duplication
    public function withRelationshipSelfLink($resource, string $relationshipName): EncoderInterface
450
    {
451
        $link = $this
452 1
            ->getSchemaContainer()->getSchema($resource)
453 1
            ->getRelationshipSelfLink($resource, $relationshipName);
454
455 1
        return $this->withLinks([
0 ignored issues
show
Documentation introduced by
array(\Neomerx\JsonApi\C...terface::SELF => $link) is of type array<string|integer,obj...\Schema\LinkInterface>>, but the function expects a object<Neomerx\JsonApi\Encoder\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
456 1
            LinkInterface::SELF => $link,
457
        ]);
458
    }
459
460
    /**
461
     * @param mixed  $resource
462
     * @param string $relationshipName
463
     *
464
     * @return self|EncoderInterface
465
     */
466 1 View Code Duplication
    public function withRelationshipRelatedLink($resource, string $relationshipName): EncoderInterface
467
    {
468
        $link = $this
469 1
            ->getSchemaContainer()->getSchema($resource)
470 1
            ->getRelationshipRelatedLink($resource, $relationshipName);
471
472 1
        return $this->withLinks([
0 ignored issues
show
Documentation introduced by
array(\Neomerx\JsonApi\C...face::RELATED => $link) is of type array<string|integer,obj...\Schema\LinkInterface>>, but the function expects a object<Neomerx\JsonApi\Encoder\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
473 1
            LinkInterface::RELATED => $link,
474
        ]);
475
    }
476
477
    /**
478
     * @param iterable $value
479
     *
480
     * @return array
481
     */
482 87
    private function iterableToArray(iterable $value): array
483
    {
484
        /** @var Traversable|array $value */
485 87
        return \is_array($value) === true ? $value : \iterator_to_array($value);
486
    }
487
}
488