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

EncoderPropertiesTrait::withIncludedPaths()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 1
nop 1
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 4
rs 9.6
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Neomerx\JsonApi\Encoder;
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\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 82
    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 82
        $this->links          = null;
121 82
        $this->profile        = null;
122 82
        $this->hasMeta        = false;
123 82
        $this->meta           = null;
124 82
        $this->jsonApiVersion = null;
125 82
        $this->jsonApiMeta    = null;
126 82
        $this->hasJsonApiMeta = false;
127
128
        $this
129 82
            ->withUrlPrefix($urlPrefix)
130 82
            ->withIncludedPaths($includePaths)
131 82
            ->withFieldSets($fieldSets)
132 82
            ->withEncodeOptions($encodeOptions)
133 82
            ->withEncodeDepth($encodeDepth);
134
135 82
        return $this;
136
    }
137
138
    /**
139
     * @return SchemaContainerInterface
140
     */
141 71
    protected function getSchemaContainer(): SchemaContainerInterface
142
    {
143 71
        return $this->container;
144
    }
145
146
    /**
147
     * @param SchemaContainerInterface $container
148
     *
149
     * @return self
150
     */
151 82
    public function setContainer(SchemaContainerInterface $container): self
152
    {
153 82
        $this->container = $container;
154
155 82
        return $this;
156
    }
157
158
    /**
159
     * @return FactoryInterface
160
     */
161 80
    protected function getFactory(): FactoryInterface
162
    {
163 80
        return $this->factory;
164
    }
165
166
    /**
167
     * @param FactoryInterface $factory
168
     *
169
     * @return self
170
     */
171 82
    public function setFactory(FactoryInterface $factory): self
172
    {
173 82
        $this->factory = $factory;
174
175 82
        return $this;
176
    }
177
178
    /**
179
     * @param string $prefix
180
     *
181
     * @return self|EncoderInterface
182
     */
183 82
    public function withUrlPrefix(string $prefix): EncoderInterface
184
    {
185 82
        $this->urlPrefix = $prefix;
186
187 82
        return $this;
188
    }
189
    /**
190
     * @return string
191
     */
192 80
    protected function getUrlPrefix(): string
193
    {
194 80
        return $this->urlPrefix;
195
    }
196
197
    /**
198
     * @param iterable $paths
199
     *
200
     * @return self|EncoderInterface
201
     */
202 82
    public function withIncludedPaths(iterable $paths): EncoderInterface
203
    {
204 82
        assert(
205 82
            call_user_func(
206
                function (array $paths): bool {
207 82
                    $pathsOk = true;
208 82
                    foreach ($paths as $path) {
209 22
                        $pathsOk = $pathsOk === true && is_string($path) === true && empty($path) === false;
210
                    }
211
212 82
                    return $pathsOk;
213 82
                },
214 82
                $paths
215
            )
216
        );
217
218 82
        $this->includePaths = $paths;
219
220 82
        return $this;
221
    }
222
223
    /**
224
     * @return array
225
     */
226 71
    protected function getIncludePaths(): array
227
    {
228 71
        return $this->includePaths;
229
    }
230
231
    /**
232
     * @param array $fieldSets
233
     *
234
     * @return self|EncoderInterface
235
     */
236 82
    public function withFieldSets(array $fieldSets): EncoderInterface
237
    {
238 82
        $this->fieldSets = $fieldSets;
239
240 82
        return $this;
241
    }
242
243
244
    /**
245
     * @return array
246
     */
247 71
    protected function getFieldSets(): array
248
    {
249 71
        return $this->fieldSets;
250
    }
251
252
    /**
253
     * @param int $options
254
     *
255
     * @return self|EncoderInterface
256
     */
257 82
    public function withEncodeOptions(int $options): EncoderInterface
258
    {
259 82
        $this->encodeOptions = $options;
260
261 82
        return $this;
262
    }
263
264
    /**
265
     * @return int
266
     */
267 74
    protected function getEncodeOptions(): int
268
    {
269 74
        return $this->encodeOptions;
270
    }
271
272
    /**
273
     * @param int $depth
274
     *
275
     * @return self|EncoderInterface
276
     */
277 82
    public function withEncodeDepth(int $depth): EncoderInterface
278
    {
279 82
        assert($depth > 0);
280
281 82
        $this->encodeDepth = $depth;
282
283 82
        return $this;
284
    }
285
286
    /**
287
     * @return int
288
     */
289 74
    protected function getEncodeDepth(): int
290
    {
291 74
        return $this->encodeDepth;
292
    }
293
294
    /**
295
     * @param iterable $links
296
     *
297
     * @return self|EncoderInterface
298
     */
299 5
    public function withLinks(iterable $links): EncoderInterface
300
    {
301 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...
302 5
            $links :
303 2
            $this->links = array_merge(
304 2
                $this->iterableToArray($this->getLinks()),
305 2
                $this->iterableToArray($links)
306
            );
307
308 5
        return $this;
309
    }
310
311
    /**
312
     * @return bool
313
     */
314 80
    protected function hasLinks(): bool
315
    {
316 80
        return $this->links !== null;
317
    }
318
319
    /**
320
     * @return iterable
321
     */
322 5
    protected function getLinks(): iterable
323
    {
324 5
        return $this->links;
325
    }
326
327
    /**
328
     * @param iterable $links
329
     *
330
     * @return self|EncoderInterface
331
     */
332 1
    public function withProfile(iterable $links): EncoderInterface
333
    {
334 1
        $this->profile = $links;
335
336 1
        return $this;
337
    }
338
339
    /**
340
     * @return bool
341
     */
342 80
    protected function hasProfile(): bool
343
    {
344 80
        return $this->profile !== null;
345
    }
346
347
    /**
348
     * @return iterable
349
     */
350 1
    protected function getProfile(): iterable
351
    {
352 1
        return $this->profile;
353
    }
354
355
    /**
356
     * @param mixed $meta
357
     *
358
     * @return self|EncoderInterface
359
     */
360 6
    public function withMeta($meta): EncoderInterface
361
    {
362 6
        $this->meta    = $meta;
363 6
        $this->hasMeta = true;
364
365 6
        return $this;
366
    }
367
368
    /**
369
     * @return bool
370
     */
371 80
    protected function hasMeta(): bool
372
    {
373 80
        return $this->hasMeta;
374
    }
375
376
    /**
377
     * @return mixed
378
     */
379 6
    public function getMeta()
380
    {
381 6
        return $this->meta;
382
    }
383
384
    /**
385
     * @param string $version
386
     *
387
     * @return self|EncoderInterface
388
     */
389 2
    public function withJsonApiVersion(string $version): EncoderInterface
390
    {
391 2
        $this->jsonApiVersion = $version;
392
393 2
        return $this;
394
    }
395
396
    /**
397
     * @return bool
398
     */
399 80
    protected function hasJsonApiVersion(): bool
400
    {
401 80
        return $this->jsonApiVersion !== null;
402
    }
403
404
    /**
405
     * @return string
406
     */
407 2
    protected function getJsonApiVersion(): string
408
    {
409 2
        return $this->jsonApiVersion;
410
    }
411
412
    /**
413
     * @param mixed $meta
414
     *
415
     * @return self|EncoderInterface
416
     */
417 2
    public function withJsonApiMeta($meta): EncoderInterface
418
    {
419 2
        $this->jsonApiMeta    = $meta;
420 2
        $this->hasJsonApiMeta = true;
421
422 2
        return $this;
423
    }
424
425
    /**
426
     * @return bool
427
     */
428 80
    protected function hasJsonApiMeta(): bool
429
    {
430 80
        return $this->hasJsonApiMeta;
431
    }
432
433
    /**
434
     * @return mixed
435
     */
436 2
    protected function getJsonApiMeta()
437
    {
438 2
        return $this->jsonApiMeta;
439
    }
440
441
    /**
442
     * @param mixed  $resource
443
     * @param string $relationshipName
444
     *
445
     * @return self|EncoderInterface
446
     */
447 1 View Code Duplication
    public function withRelationshipSelfLink($resource, string $relationshipName): EncoderInterface
448
    {
449
        $link = $this
450 1
            ->getSchemaContainer()->getSchema($resource)
451 1
            ->getRelationshipSelfLink($resource, $relationshipName);
452
453 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...
454 1
            LinkInterface::SELF => $link,
455
        ]);
456
    }
457
458
    /**
459
     * @param mixed  $resource
460
     * @param string $relationshipName
461
     *
462
     * @return self|EncoderInterface
463
     */
464 1 View Code Duplication
    public function withRelationshipRelatedLink($resource, string $relationshipName): EncoderInterface
465
    {
466
        $link = $this
467 1
            ->getSchemaContainer()->getSchema($resource)
468 1
            ->getRelationshipRelatedLink($resource, $relationshipName);
469
470 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...
471 1
            LinkInterface::RELATED => $link,
472
        ]);
473
    }
474
475
    /**
476
     * @param iterable $value
477
     *
478
     * @return array
479
     */
480 2
    private function iterableToArray(iterable $value): array
481
    {
482
        /** @var Traversable|array $value */
483 2
        return is_array($value) === true ? $value : iterator_to_array($value);
484
    }
485
}
486