Completed
Push — develop ( de7f4b...5c2193 )
by Neomerx
09:05
created

Encoder::encodeData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 2
1
<?php namespace Limoncello\Flute\Encoder;
2
3
/**
4
 * Copyright 2015-2017 [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\JsonApiQueryValidatingParserInterface;
23
use Neomerx\JsonApi\Contracts\Document\DocumentInterface;
24
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;
25
use Neomerx\JsonApi\Contracts\Http\Query\BaseQueryParserInterface;
26
use Psr\Http\Message\UriInterface;
27
28
/**
29
 * @package Limoncello\Flute
30
 */
31
class Encoder extends \Neomerx\JsonApi\Encoder\Encoder implements EncoderInterface
32
{
33
    /**
34
     * @var UriInterface
35
     */
36
    private $originalUri;
37
38
    /**
39
     * @inheritdoc
40
     */
41 4
    public function forOriginalUri(UriInterface $uri): EncoderInterface
42
    {
43 4
        $this->originalUri = $uri;
44
45 4
        return $this;
46
    }
47
48
    /**
49
     * @inheritdoc
50
     */
51
    public function encodeData($data, EncodingParametersInterface $parameters = null): string
52
    {
53
        $data = $this->handleRelationshipStorageAndPagingData($data);
54
55
        return parent::encodeData($data, $parameters);
56
    }
57
58
    /**
59
     * @inheritdoc
60
     */
61
    public function encodeIdentifiers($data, EncodingParametersInterface $parameters = null): string
62
    {
63
        $data = $this->handleRelationshipStorageAndPagingData($data);
64
65
        return parent::encodeIdentifiers($data, $parameters);
66
    }
67
68
    /**
69
     * @return UriInterface
70
     */
71
    protected function getOriginalUri(): UriInterface
72
    {
73
        return $this->originalUri;
74
    }
75
76
    /**
77
     * @param mixed $data
78
     *
79
     * @return mixed
80
     */
81
    private function handleRelationshipStorageAndPagingData($data)
82
    {
83
        if ($data instanceof PaginatedDataInterface) {
84
            /** @var PaginatedDataInterface $data */
85
            $this->addPagingLinksIfNeeded($data);
86
            $data = $data->getData();
87
        }
88
89
        /** @var mixed $data */
90
91
        return $data;
92
    }
93
94
    /**
95
     * @param PaginatedDataInterface $data
96
     *
97
     * @return void
98
     */
99
    private function addPagingLinksIfNeeded(PaginatedDataInterface $data): void
100
    {
101
        if ($data->isCollection() === true &&
102
            (0 < $data->getOffset() || $data->hasMoreItems() === true) &&
103
            $this->getOriginalUri() !== null
104
        ) {
105
            $links       = [];
106
            $linkClosure = $this->createLinkClosure($data->getLimit());
107
108
            $prev = DocumentInterface::KEYWORD_PREV;
109
            $next = DocumentInterface::KEYWORD_NEXT;
110
            $data->getOffset() <= 0 ?: $links[$prev] = $linkClosure(max(0, $data->getOffset() - $data->getLimit()));
111
            $data->hasMoreItems() === false ?: $links[$next] = $linkClosure($data->getOffset() + $data->getLimit());
112
113
            $this->withLinks($links);
114
        }
115
    }
116
117
    /**
118
     * @param int $pageSize
119
     *
120
     * @return Closure
121
     */
122
    private function createLinkClosure(int $pageSize): Closure
123
    {
124
        assert($pageSize > 0);
125
126
        parse_str($this->getOriginalUri()->getQuery(), $queryParams);
127
128
        return function ($offset) use ($pageSize, $queryParams) {
129
            $paramsWithPaging = array_merge($queryParams, [
130
                BaseQueryParserInterface::PARAM_PAGE => [
131
                    JsonApiQueryValidatingParserInterface::PARAM_PAGING_OFFSET => $offset,
132
                    JsonApiQueryValidatingParserInterface::PARAM_PAGING_LIMIT  => $pageSize,
133
                ],
134
            ]);
135
            $newUri           = $this->getOriginalUri()->withQuery(http_build_query($paramsWithPaging));
136
            $fullUrl          = (string)$newUri;
137
            $link             = $this->getFactory()->createLink($fullUrl, null, true);
138
139
            return $link;
140
        };
141
    }
142
}
143