Passed
Push — master ( d02a30...c2fe95 )
by Andrejs
02:08
created

Juggler::composeQueryString()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 1
nop 2
dl 0
loc 7
ccs 4
cts 4
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\Mountebank\MountebankException;
7
use Meare\Juggler\HttpClient\GuzzleClient;
8
use Meare\Juggler\HttpClient\IHttpClient;
9
use Meare\Juggler\Imposter\Builder\AbstractImposterBuilder;
10
use Meare\Juggler\Imposter\HttpImposter;
11
use Meare\Juggler\Imposter\Imposter;
12
13
class Juggler
14
{
15
    const PARAM_REPLAYABLE = 'replayable';
16
    const PARAM_REMOVE_PROXIES = 'remove_proxies';
17
    const DEFAULT_PORT = 2525;
18
19
    /**
20
     * @var IHttpClient
21
     */
22
    private $httpClient;
23
24
    /**
25
     * @var AbstractImposterBuilder
26
     */
27
    private $abstractImposterBuilder;
28
29
    /**
30
     * @var string
31
     */
32
    private $host;
33
34
    /**
35
     * @var int
36
     */
37
    private $port;
38
39
    /**
40
     * Full URL to Juggler client
41
     *
42
     * @var string
43
     */
44
    private $url;
45
46
    /**
47
     * @param string      $host
48
     * @param int         $port
49
     * @param IHttpClient $httpClient
50
     */
51 8
    public function __construct(string $host, int $port = self::DEFAULT_PORT, IHttpClient $httpClient = null)
52
    {
53 8
        $this->host = $host;
54 8
        $this->port = $port;
55 8
        $this->setUrl($host, $port);
56 8
        $this->httpClient = $httpClient ?? GuzzleClient::create();
0 ignored issues
show
Documentation Bug introduced by
It seems like $httpClient ?? \Meare\Ju...\GuzzleClient::create() can also be of type object<self>. However, the property $httpClient is declared as type object<Meare\Juggler\HttpClient\IHttpClient>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
57 8
        $this->httpClient->setHost($this->getUrl());
58 8
        $this->abstractImposterBuilder = new AbstractImposterBuilder;
59 8
    }
60
61
    /**
62
     * @param string $host
63
     * @param int    $port
64
     */
65 8
    private function setUrl(string $host, int $port)
66
    {
67 8
        $this->url = 'http://' . $host . ':' . $port;
68 8
    }
69
70
    /**
71
     * @return string
72
     */
73 8
    public function getUrl() : string
74
    {
75 8
        return $this->url;
76
    }
77
78
    /**
79
     * @return string
80
     */
81 1
    public function getHost() : string
82
    {
83 1
        return $this->host;
84
    }
85
86
    /**
87
     * @return int
88
     */
89 1
    public function getPort() : int
90
    {
91 1
        return $this->port;
92
    }
93
94
    /**
95
     * @param string $path
96
     * @return Imposter
97
     */
98 1
    public function createImposterFromFile(string $path) : Imposter
99
    {
100 1
        return $this->abstractImposterBuilder->build(file_get_contents($path));
101
    }
102
103
    /**
104
     * @param string $path
105
     * @throws MountebankException
106
     * @throws \RuntimeException if file does not exist
107
     * @return int Imposter port
108
     */
109
    public function postImposterFromFile(string $path)
110
    {
111
        return $this->postImposterContract(file_get_contents($path));
112
    }
113
114
    /**
115
     * @param string $contract
116
     * @throws MountebankException
117
     * @return int Imposter port
118
     */
119 1
    public function postImposterContract(string $contract)
120
    {
121 1
        $received_contract = $this->httpClient->post('/imposters', $contract);
122
123 1
        return (int)\GuzzleHttp\json_decode($received_contract, true)['port'];
124
    }
125
126
    /**
127
     * @param int  $port
128
     * @param bool $replayable
129
     * @param bool $remove_proxies
130
     * @return HttpImposter
131
     */
132
    public function getHttpImposter(int $port, bool $replayable = false, bool $remove_proxies = false) : HttpImposter
133
    {
134
        return $this->getImposter($port, $replayable, $remove_proxies);
135
    }
136
137
    /**
138
     * Retrieves contract and builds Imposter
139
     *
140
     * @param int  $port
141
     * @param bool $replayable
142
     * @param bool $remove_proxies
143
     * @throws MountebankException
144
     * @return Imposter
145
     */
146 1
    public function getImposter(int $port, bool $replayable = false, bool $remove_proxies = false) : Imposter
147
    {
148 1
        return $this->abstractImposterBuilder->build($this->getImposterContract($port, $replayable, $remove_proxies));
149
    }
150
151
    /**
152
     * @param int  $port
153
     * @param bool $replayable
154
     * @param bool $remove_proxies
155
     * @throws MountebankException
156
     * @return string
157
     */
158 1
    public function getImposterContract(int $port, bool $replayable = false, bool $remove_proxies = false) : string
159
    {
160 1
        $query = $this->composeQueryString($replayable, $remove_proxies);
161
162 1
        return $this->httpClient->get("/imposters/$port?$query");
163
    }
164
165
    /**
166
     * @param Imposter $imposter
167
     */
168
    public function replaceImposter(Imposter $imposter)
169
    {
170
        $this->deleteImposter($imposter);
171
        $this->postImposter($imposter);
172
    }
173
174
    /**
175
     * @param int|Imposter $imposter Port or Imposter instance
176
     * @param bool         $replayable
177
     * @param bool         $remove_proxies
178
     *
179
     * @return string Imposter contract
180
     * @throws MountebankException
181
     */
182 3
    public function deleteImposter($imposter, bool $replayable = false, bool $remove_proxies = false)
183
    {
184 3
        $query = $this->composeQueryString($replayable, $remove_proxies);
185 3
        $port = $imposter instanceof Imposter ? $imposter->getPort() : $imposter;
186
187 3
        return $this->httpClient->delete("/imposters/$port?$query");
188
    }
189
190
    /**
191
     * @param Imposter $imposter
192
     * @throws MountebankException
193
     * @return int Imposter port
194
     */
195 1
    public function postImposter(Imposter $imposter) : int
196
    {
197 1
        $port = $this->postImposterContract(json_encode($imposter));
198 1
        if (!$imposter->hasPort()) {
199 1
            $imposter->setPort($port);
200
        }
201
202 1
        return $port;
203
    }
204
205
    /**
206
     * @throws MountebankException
207
     */
208 1
    public function deleteImposters()
209
    {
210 1
        $this->httpClient->delete("/imposters");
211 1
    }
212
213
    /**
214
     * @param int $port
215
     * @throws MountebankException
216
     */
217 1
    public function removeProxies(int $port)
218
    {
219 1
        $query = $this->composeQueryString(false, true);
220 1
        $this->httpClient->get("/imposters/$port?$query");
221 1
    }
222
223
    /**
224
     * Retrieves imposter contract and saves to a local filesystem
225
     *
226
     * @param int|Imposter $imposter
227
     * @param string       $path
228
     */
229
    public function saveContract($imposter, string $path)
230
    {
231
        $port = $imposter instanceof Imposter ? $imposter->getPort() : $imposter;
232
        file_put_contents($path, $this->getImposterContract($port));
233
    }
234
235
    /**
236
     * mountebank API only supports string 'true' as boolean param value
237
     *
238
     * @param bool $replayable
239
     * @param bool $remove_proxies
240
     *
241
     * @return string
242
     */
243 5
    private function composeQueryString(bool $replayable, bool $remove_proxies) : string
244
    {
245 5
        return http_build_query(array_filter([
246 5
            self::PARAM_REPLAYABLE     => $replayable ? 'true' : null,
247 5
            self::PARAM_REMOVE_PROXIES => $remove_proxies ? 'true' : null,
248
        ]));
249
    }
250
}
251