Juggler::composeQueryString()   A
last analyzed

Complexity

Conditions 3
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 1
nop 2
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Meare\Juggler;
4
5
6
use Meare\Juggler\Exception\Client\ClientException;
7
use Meare\Juggler\Exception\Mountebank\MountebankException;
8
use Meare\Juggler\Exception\Mountebank\NoSuchResourceException;
9
use Meare\Juggler\HttpClient\GuzzleClient;
10
use Meare\Juggler\HttpClient\IHttpClient;
11
use Meare\Juggler\Imposter\Builder\AbstractImposterBuilder;
12
use Meare\Juggler\Imposter\HttpImposter;
13
use Meare\Juggler\Imposter\Imposter;
14
15
class Juggler
16
{
17
    const PARAM_REPLAYABLE = 'replayable';
18
    const PARAM_REMOVE_PROXIES = 'remove_proxies';
19
    const DEFAULT_PORT = 2525;
20
21
    /**
22
     * @var IHttpClient
23
     */
24
    private $httpClient;
25
26
    /**
27
     * @var AbstractImposterBuilder
28
     */
29
    private $abstractImposterBuilder;
30
31
    /**
32
     * @var string
33
     */
34
    private $host;
35
36
    /**
37
     * @var int
38
     */
39
    private $port;
40
41
    /**
42
     * Full URL to Juggler client
43
     *
44
     * @var string
45
     */
46
    private $url;
47
48
    /**
49
     * @param string      $host
50
     * @param int         $port
51
     * @param IHttpClient $httpClient
52
     */
53 16
    public function __construct($host, $port = self::DEFAULT_PORT, IHttpClient $httpClient = null)
54
    {
55 16
        $this->host = $host;
56 16
        $this->port = $port;
57 16
        $this->setUrl($host, $port);
58 16
        $this->httpClient = isset($httpClient) ? $httpClient : GuzzleClient::create();
59 16
        $this->httpClient->setHost($this->getUrl());
60 16
        $this->abstractImposterBuilder = new AbstractImposterBuilder;
61 16
    }
62
63
    /**
64
     * @param string $host
65
     * @param int    $port
66
     */
67 16
    private function setUrl($host, $port)
68
    {
69 16
        $this->url = 'http://' . $host . ':' . $port;
70 16
    }
71
72
    /**
73
     * @return string
74
     */
75 16
    public function getUrl()
76
    {
77 16
        return $this->url;
78
    }
79
80
    /**
81
     * @return string
82
     */
83 1
    public function getHost()
84
    {
85 1
        return $this->host;
86
    }
87
88
    /**
89
     * @return int
90
     */
91 1
    public function getPort()
92
    {
93 1
        return $this->port;
94
    }
95
96
    /**
97
     * @param string $path
98
     * @throws \InvalidArgumentException in case contract contents are not valid JSON
99
     * @throws \RuntimeException if save to filesystem failed
100
     * @return Imposter
101
     */
102 4
    public function createImposterFromFile($path)
103
    {
104 4
        return $this->abstractImposterBuilder->build(file_get_contents($path));
105
    }
106
107
    /**
108
     * @param string $path
109
     * @throws MountebankException
110
     * @throws \RuntimeException if file does not exist
111
     * @return int Imposter port
112
     */
113 1
    public function postImposterFromFile($path)
114
    {
115 1
        return $this->postImposterContract(file_get_contents($path));
116
    }
117
118
    /**
119
     * @param string $contract
120
     * @throws MountebankException
121
     * @return int Imposter port
122
     */
123 1
    public function postImposterContract($contract)
124
    {
125 1
        $received_contract = $this->httpClient->post('/imposters', $contract);
126
127 1
        return (int)\GuzzleHttp\json_decode($received_contract, true)['port'];
128
    }
129
130
    /**
131
     * @param int  $port
132
     * @param bool $replayable
133
     * @param bool $remove_proxies
134
     * @return HttpImposter
135
     * @throws ClientException in case imposter mountebank returns is not http imposter
136
     */
137
    public function getHttpImposter($port, $replayable = false, $remove_proxies = false)
138
    {
139
        $imposter = $this->getImposter($port, $replayable, $remove_proxies);
140
141
        if (!$imposter instanceof HttpImposter) {
142
            throw new ClientException(
143
                "Expected imposter on port $port to be http imposter; got {$imposter->getProtocol()} imposter"
144
            );
145
        }
146
147
        return $imposter;
148
    }
149
150
    /**
151
     * Retrieves contract and builds Imposter
152
     *
153
     * @param int  $port
154
     * @param bool $replayable
155
     * @param bool $remove_proxies
156
     * @throws MountebankException
157
     * @return Imposter
158
     */
159 1
    public function getImposter($port, $replayable = false, $remove_proxies = false)
160
    {
161 1
        return $this->abstractImposterBuilder->build($this->getImposterContract($port, $replayable, $remove_proxies));
162
    }
163
164
    /**
165
     * @param int  $port
166
     * @param bool $replayable
167
     * @param bool $remove_proxies
168
     * @throws MountebankException
169
     * @return string
170
     */
171 1
    public function getImposterContract($port, $replayable = false, $remove_proxies = false)
172
    {
173 1
        $query = $this->composeQueryString($replayable, $remove_proxies);
174
175 1
        return $this->httpClient->get("/imposters/$port?$query");
176
    }
177
178
    /**
179
     * @param Imposter $imposter
180
     * @return int Imposter port
181
     */
182
    public function replaceImposter(Imposter $imposter)
183
    {
184
        $this->deleteImposter($imposter);
185
        return $this->postImposter($imposter);
186
    }
187
188
    /**
189
     * @param int|Imposter $imposter Port or Imposter instance
190
     * @param bool         $replayable
191
     * @param bool         $remove_proxies
192
     *
193
     * @return string Imposter contract
194
     * @throws MountebankException
195
     */
196 5
    public function deleteImposter($imposter, $replayable = false, $remove_proxies = false)
197
    {
198 5
        $query = $this->composeQueryString($replayable, $remove_proxies);
199 5
        $port = $imposter instanceof Imposter ? $imposter->getPort() : $imposter;
200
201 5
        return $this->httpClient->delete("/imposters/$port?$query");
202
    }
203
204
    /**
205
     * @param int|Imposter $imposter
206
     * @param bool         $replayable
207
     * @param bool         $remove_proxies
208
     * @return string|null Imposter contract or null if there was no requested imposter
209
     */
210 2
    public function deleteImposterIfExists($imposter, $replayable = false, $remove_proxies = false)
211
    {
212
        try {
213 2
            return $this->deleteImposter($imposter, $replayable, $remove_proxies);
214 1
        } catch (NoSuchResourceException $e) {
215 1
            return null;
216
        }
217
    }
218
219
    /**
220
     * @param Imposter $imposter
221
     * @throws MountebankException
222
     * @return int Imposter port
223
     */
224 1
    public function postImposter(Imposter $imposter)
225
    {
226 1
        $port = $this->postImposterContract(json_encode($imposter));
227 1
        if (!$imposter->hasPort()) {
228 1
            $imposter->setPort($port);
229 1
        }
230
231 1
        return $port;
232
    }
233
234
    /**
235
     * @throws MountebankException
236
     */
237 1
    public function deleteImposters()
238
    {
239 1
        $this->httpClient->delete("/imposters");
240 1
    }
241
242
    /**
243
     * @param int $port
244
     * @throws MountebankException
245
     */
246 1
    public function removeProxies($port)
247
    {
248 1
        $query = $this->composeQueryString(false, true);
249 1
        $this->httpClient->get("/imposters/$port?$query");
250 1
    }
251
252
    /**
253
     * Retrieves imposter contract and saves it to a local filesystem
254
     *
255
     * @param int    $port
256
     * @param string $path
257
     * @throws \RuntimeException if save to filesystem failed
258
     */
259
    public function retrieveAndSaveContract($port, $path)
260
    {
261
        file_put_contents($path, $this->getImposterContract($port));
262
    }
263
264
    /**
265
     * Saves Imposter contract to local filesystem
266
     *
267
     * @param Imposter $imposter
268
     * @param string   $path
269
     * @throws \RuntimeException if save to filesystem failed
270
     */
271 2
    public function saveContract(Imposter $imposter, $path)
272
    {
273 2
        file_put_contents($path, \GuzzleHttp\json_encode($imposter));
274 1
    }
275
276
    /**
277
     * mountebank API only supports string 'true' as boolean param value
278
     *
279
     * @param bool $replayable
280
     * @param bool $remove_proxies
281
     *
282
     * @return string
283
     */
284 7
    private function composeQueryString($replayable, $remove_proxies)
285
    {
286 7
        return http_build_query(array_filter([
287 7
            self::PARAM_REPLAYABLE     => $replayable ? 'true' : null,
288 7
            self::PARAM_REMOVE_PROXIES => $remove_proxies ? 'true' : null,
289 7
        ]));
290
    }
291
}
292