Notification Setup Error

We have detected an error in your notification set-up (Event-ID dab39dc24f564ec7bd4628d1305fd03c). Currently, we cannot inform you about inspection progress. Please check that the user 557058:bca11929-8c2d-43f2-8a82-c5416880d395 still has access to your repository or update the API account.

Completed
Push — develop ( a55da1...39a772 )
by
unknown
27:43 queued 12:35
created

ApiOneCollectionPlugin::getPaginationMeta()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 3
nc 4
nop 1
1
<?php
2
/**
3
 * This file is part of the bitbucket-api package.
4
 *
5
 * (c) Alexandru G. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace Bitbucket\API\Http\Plugin;
11
12
use Http\Client\Common\Plugin;
13
use Http\Discovery\MessageFactoryDiscovery;
14
use Http\Message\ResponseFactory;
15
use Psr\Http\Message\RequestInterface;
16
use Psr\Http\Message\ResponseInterface;
17
18
/**
19
 * Helper for `Pager`
20
 *
21
 * Inserts pagination metadata (_as is expected by `Pager`_),
22
 * in any response coming from v1 of the API which contains
23
 * a collection.
24
 *
25
 * @author Alexandru Guzinschi <[email protected]>
26
 */
27
class ApiOneCollectionPlugin implements Plugin
28
{
29
    use Plugin\VersionBridgePlugin;
30
31
    /** @var ResponseFactory */
32
    private $responseFactory;
33
34
    /** @var array */
35
    private $urlQueryComponents;
36
37
    /** @var string */
38
    private $resource;
39
40
    /** @var array */
41
    private $content;
42
43
    public function __construct(ResponseFactory $responseFactory = null)
44
    {
45
        $this->responseFactory = $responseFactory ?: MessageFactoryDiscovery::find();
46
    }
47
48
    protected function doHandleRequest(RequestInterface $request, callable $next, callable $first)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Unused Code introduced by
The parameter $first is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
49
    {
50
        return $next($request)->then(function (ResponseInterface $response) use ($request) {
51
            if ($this->isLegacyApiVersion($request)) {
52
                $this->parseRequest($request);
53
54
                if ($this->canPaginate($response)) {
55
                    $content = $this->insertPaginationMeta(
56
                        $this->getContent($response),
57
                        $this->getPaginationMeta($response),
58
                        $request
59
                    );
60
61
                    return $this->responseFactory->createResponse(
62
                        $response->getStatusCode(),
63
                        $response->getReasonPhrase(),
64
                        $response->getHeaders(),
65
                        json_encode($content),
66
                        $response->getProtocolVersion()
67
                    );
68
                }
69
            }
70
71
            return $response;
72
        });
73
    }
74
75
    /**
76
     * @access public
77
     * @param  RequestInterface $request
78
     * @return bool
79
     */
80
    private function isLegacyApiVersion(RequestInterface $request)
81
    {
82
        /** @var RequestInterface $request */
83
        return strpos($request->getUri()->getPath(), '/1.0/') !== false;
84
    }
85
86
    /**
87
     * @access public
88
     * @param  RequestInterface $request
89
     * @return void
90
     */
91
    private function parseRequest(RequestInterface $request)
92
    {
93
        if ($request->getUri()->getQuery()) {
94
            parse_str($request->getUri()->getQuery(), $this->urlQueryComponents);
95
        } else {
96
            $this->urlQueryComponents = [];
97
        }
98
99
        $this->urlQueryComponents['start'] = array_key_exists('start', $this->urlQueryComponents) ?
100
            (int)$this->urlQueryComponents['start'] :
101
            0
102
        ;
103
        $this->urlQueryComponents['limit'] = array_key_exists('limit', $this->urlQueryComponents) ?
104
            (int)$this->urlQueryComponents['limit'] :
105
            15
106
        ;
107
108
        $pcs = explode('/', $request->getUri()->getPath());
109
        $this->resource = strtolower(array_pop($pcs));
110
    }
111
112
    /**
113
     * @access public
114
     * @param  ResponseInterface $response
115
     * @return bool
116
     */
117
    private function canPaginate(ResponseInterface $response)
118
    {
119
        $content = $this->getContent($response);
120
121
        return array_key_exists('count', $content) && array_key_exists($this->resource, $content);
122
    }
123
124
    /**
125
     * @access private
126
     * @param  ResponseInterface $response
127
     * @return array
128
     */
129
    private function getContent(ResponseInterface $response)
130
    {
131
        if (null === $this->content) {
132
            $content = json_decode($response->getBody()->getContents(), true);
133
            $response->getBody()->rewind();
134
135
            if (is_array($content) && JSON_ERROR_NONE === json_last_error()) {
136
                $this->content = $content;
137
            } else {
138
                $this->content = [];
139
            }
140
        }
141
142
        return $this->content;
143
    }
144
145
    /**
146
     * @access private
147
     * @param  array $content
148
     * @param  array $pagination
149
     * @return array
150
     */
151
    private function insertPaginationMeta(array $content, array $pagination, RequestInterface $request)
152
    {
153
        // This is just a reference because duplicate data in response could create confusion between some users.
154
        $content['values']  = '.'.$this->resource;
155
        $content['size']    = $content['count'];
156
157
        // insert pagination links only if everything does not fit in a single page
158
        if ($content['count'] > count($content[$this->resource])) {
159
            if ($pagination['page'] > 1 || $pagination['page'] === $pagination['pages']) {
160
                $query = $this->urlQueryComponents;
161
                $query['start'] -= $this->urlQueryComponents['limit'];
162
163
                $content['previous'] = sprintf(
164
                    '%s://%s%s?%s',
165
                    $request->getUri()->getScheme(),
166
                    $request->getUri()->getHost(),
167
                    $request->getUri()->getPath(),
168
                    http_build_query($query)
169
                );
170
            }
171
172
            if ($pagination['page'] < $pagination['pages']) {
173
                $query = $this->urlQueryComponents;
174
                $query['start'] += $this->urlQueryComponents['limit'];
175
176
                $content['next'] = sprintf(
177
                    '%s://%s%s?%s',
178
                    $request->getUri()->getScheme(),
179
                    $request->getUri()->getHost(),
180
                    $request->getUri()->getPath(),
181
                    http_build_query($query)
182
                );
183
            }
184
        }
185
186
        return $content;
187
    }
188
189
    /**
190
     * @access private
191
     * @param  ResponseInterface $response
192
     * @return array
193
     */
194
    private function getPaginationMeta(ResponseInterface $response)
195
    {
196
        $meta = [];
197
198
        $content        = $this->getContent($response);
199
        $meta['total']  = $content['count'];
200
        $meta['pages']  = (int)ceil($meta['total'] / $this->urlQueryComponents['limit']);
201
        $meta['page']   = ($this->urlQueryComponents['start']/$this->urlQueryComponents['limit']) === 0 ?
202
            1 :
203
            ($this->urlQueryComponents['start']/$this->urlQueryComponents['limit'])+1
204
        ;
205
206
        if ($meta['page'] > $meta['pages']) {
207
            $meta['page'] = $meta['pages'];
208
        }
209
210
        return $meta;
211
    }
212
}
213