Completed
Push — develop ( dcfc04...3d10a6 )
by Neomerx
04:33
created

Encoder::encodeIdentifiers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 5
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php namespace Limoncello\Flute\Encoder;
2
3
/**
4
 * Copyright 2015-2018 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Closure;
20
use Limoncello\Flute\Contracts\Encoder\EncoderInterface;
21
use Limoncello\Flute\Contracts\Models\PaginatedDataInterface;
22
use Limoncello\Flute\Contracts\Validation\JsonApiQueryParserInterface;
23
use Neomerx\JsonApi\Contracts\Http\Query\BaseQueryParserInterface;
24
use Neomerx\JsonApi\Contracts\Schema\DocumentInterface;
25
use Psr\Http\Message\UriInterface;
26
27
/**
28
 * @package Limoncello\Flute
29
 */
30
class Encoder extends \Neomerx\JsonApi\Encoder\Encoder implements EncoderInterface
31
{
32
    /**
33
     * @var UriInterface
34
     */
35
    private $originalUri;
36
37
    /**
38
     * @inheritdoc
39
     */
40
    public function forOriginalUri(UriInterface $uri): EncoderInterface
41
    {
42
        $this->originalUri = $uri;
43
44
        return $this;
45
    }
46
47
    /**
48
     * @inheritdoc
49
     */
50
    public function encodeData($data): string
51
    {
52
        $data = $this->handleRelationshipStorageAndPagingData($data);
53
54
        return parent::encodeData($data);
55
    }
56
57
    /**
58
     * @inheritdoc
59
     */
60
    public function encodeIdentifiers($data): string
61
    {
62
        $data = $this->handleRelationshipStorageAndPagingData($data);
63
64
        return parent::encodeIdentifiers($data);
65
    }
66
67
    /**
68
     * @return UriInterface
69
     */
70
    protected function getOriginalUri(): UriInterface
71
    {
72
        return $this->originalUri;
73
    }
74
75
    /**
76
     * @param mixed $data
77
     *
78
     * @return mixed
79
     */
80
    private function handleRelationshipStorageAndPagingData($data)
81
    {
82
        if ($data instanceof PaginatedDataInterface) {
83
            /** @var PaginatedDataInterface $data */
84
            $this->addPagingLinksIfNeeded($data);
85
            $data = $data->getData();
86
        }
87
88
        /** @var mixed $data */
89
90
        return $data;
91
    }
92
93
    /**
94
     * @param PaginatedDataInterface $data
95
     *
96
     * @return void
97
     */
98
    private function addPagingLinksIfNeeded(PaginatedDataInterface $data): void
99
    {
100
        if ($data->isCollection() === true &&
101
            (0 < $data->getOffset() || $data->hasMoreItems() === true) &&
102
            $this->getOriginalUri() !== null
103
        ) {
104
            $links       = [];
105
            $linkClosure = $this->createLinkClosure($data->getLimit());
106
107
            $prev = DocumentInterface::KEYWORD_PREV;
108
            $next = DocumentInterface::KEYWORD_NEXT;
109
            $data->getOffset() <= 0 ?: $links[$prev] = $linkClosure(max(0, $data->getOffset() - $data->getLimit()));
110
            $data->hasMoreItems() === false ?: $links[$next] = $linkClosure($data->getOffset() + $data->getLimit());
111
112
            $this->withLinks($links);
0 ignored issues
show
Documentation introduced by
$links is of type array, 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...
113
        }
114
    }
115
116
    /**
117
     * @param int $pageSize
118
     *
119
     * @return Closure
120
     */
121
    private function createLinkClosure(int $pageSize): Closure
122
    {
123
        assert($pageSize > 0);
124
125
        parse_str($this->getOriginalUri()->getQuery(), $queryParams);
126
127
        return function ($offset) use ($pageSize, $queryParams) {
128
            $paramsWithPaging = array_merge($queryParams, [
129
                BaseQueryParserInterface::PARAM_PAGE => [
130
                    JsonApiQueryParserInterface::PARAM_PAGING_OFFSET => $offset,
131
                    JsonApiQueryParserInterface::PARAM_PAGING_LIMIT  => $pageSize,
132
                ],
133
            ]);
134
            $newUri  = $this->getOriginalUri()->withQuery(http_build_query($paramsWithPaging));
135
            $fullUrl = (string)$newUri;
136
            $link    = $this->getFactory()->createLink(false, $fullUrl, false);
137
138
            return $link;
139
        };
140
    }
141
}
142