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
Pull Request — develop ( #41 )
by
unknown
14:09
created

ApiOneCollectionPlugin::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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