Completed
Pull Request — master (#71)
by Eric
33:30
created

ApiContext::setField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Lug package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source statusCode.
10
 */
11
12
namespace Lug\Component\Behat\Extension\Api\Context;
13
14
use Behat\Gherkin\Node\PyStringNode;
15
use Coduo\PHPMatcher\Matcher;
16
use Http\Client\Exception\HttpException;
17
use Http\Client\HttpClient;
18
use Http\Message\MultipartStream\MultipartStreamBuilder;
19
use Http\Message\RequestFactory;
20
use Http\Message\StreamFactory;
21
use Lug\Component\Behat\Extension\Api\Matcher\MatcherFactory;
22
use Psr\Http\Message\RequestInterface;
23
use Psr\Http\Message\ResponseInterface;
24
25
/**
26
 * @author GeLo <[email protected]>
27
 */
28
class ApiContext implements ApiContextInterface
29
{
30
    /**
31
     * @var HttpClient
32
     */
33
    private $client;
34
35
    /**
36
     * @var RequestFactory
37
     */
38
    private $requestFactory;
39
40
    /**
41
     * @var StreamFactory
42
     */
43
    private $streamFactory;
44
45
    /**
46
     * @var MultipartStreamBuilder|null
47
     */
48
    private $multipartStreamBuilder;
49
50
    /**
51
     * @var string
52
     */
53
    private $baseUrl;
54
55
    /**
56
     * @var string[][]
57
     */
58
    private $headers = [];
59
60
    /**
61
     * @var RequestInterface|null
62
     */
63
    private $request;
64
65
    /**
66
     * @var ResponseInterface|null
67
     */
68
    private $response;
69
70
    /**
71
     * @var Matcher
72
     */
73
    private $matcher;
74
75
    public function __construct()
76
    {
77
        $this->matcher = (new MatcherFactory())->createMatcher();
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public function setClient(HttpClient $client)
84
    {
85
        $this->client = $client;
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function setRequestFactory(RequestFactory $requestFactory)
92
    {
93
        $this->requestFactory = $requestFactory;
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function setStreamFactory(StreamFactory $streamFactory)
100
    {
101
        $this->streamFactory = $streamFactory;
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107
    public function setBaseUrl($baseUrl)
108
    {
109
        if (strrpos($baseUrl, '/') === strlen($baseUrl) - 1) {
110
            $baseUrl = substr($baseUrl, 0, -1);
111
        }
112
113
        $this->baseUrl = $baseUrl;
114
    }
115
116
    /**
117
     * @BeforeScenario
118
     */
119
    public function reset()
120
    {
121
        $this->headers = [];
122
        $this->request = null;
123
        $this->response = null;
124
        $this->multipartStreamBuilder = null;
125
    }
126
127
    /**
128
     * @param string $header
129
     * @param string $value
130
     *
131
     * @Given I set the header ":header" with value ":value"
132
     */
133
    public function setHeader($header, $value)
134
    {
135
        $this->headers[$header] = [$value];
136
    }
137
138
    /**
139
     * @param string $header
140
     * @param string $value
141
     *
142
     * @Given I add the header ":header" with value ":value"
143
     */
144
    public function addHeader($header, $value)
145
    {
146
        $this->headers[$header][] = $value;
147
    }
148
149
    /**
150
     * @param string $header
151
     *
152
     * @Given I remove the header ":header"
153
     */
154
    public function removeHeader($header)
155
    {
156
        unset($this->headers[$header]);
157
    }
158
159
    /**
160
     * @param string $name
161
     * @param string $value
162
     *
163
     * @Given I set the field ":name" with value ":value"
164
     */
165
    public function setField($name, $value)
166
    {
167
        $this->getMultipartStreamBuilder()->addResource($name, $value);
168
    }
169
170
    /**
171
     * @param string $method
172
     * @param string $url
173
     *
174
     * @When I send a ":method" request to ":url"
175
     */
176
    public function send($method, $url)
177
    {
178
        $this->request = $this->requestFactory->createRequest($method, $this->prepareUrl($url), $this->headers);
179
180
        $this->sendRequest();
181
    }
182
183
    /**
184
     * @param string       $method
185
     * @param string       $url
186
     * @param PyStringNode $string
187
     *
188
     * @When I send a ":method" request to ":url" with body:
189
     */
190
    public function sendWith($method, $url, PyStringNode $string)
191
    {
192
        $this->request = $this->requestFactory->createRequest(
193
            $method,
194
            $this->prepareUrl($url),
195
            $this->headers,
196
            trim($string->getRaw())
197
        );
198
199
        $this->sendRequest();
200
    }
201
202
    /**
203
     * @param string $statusCode
204
     *
205
     * @Then the response status code should be ":statusCode"
206
     */
207
    public function assertResponseStatusCode($statusCode)
208
    {
209
        \PHPUnit_Framework_Assert::assertSame((int) $statusCode, $this->getResponse()->getStatusCode());
210
    }
211
212
    /**
213
     * @param PyStringNode $json
214
     *
215
     * @Then the response should contain:
216
     */
217
    public function assertResponseContains(PyStringNode $json)
218
    {
219
        $this->matcher->match((string) $this->response->getBody(), $json->getRaw());
220
221
        \PHPUnit_Framework_Assert::assertNull($this->matcher->getError());
222
    }
223
224
    /**
225
     * @Then the response should be empty
226
     */
227
    public function assertResponseEmpty()
228
    {
229
        \PHPUnit_Framework_Assert::assertEmpty((string) $this->getResponse()->getBody());
230
    }
231
232
    /**
233
     * @Then I print the response
234
     */
235
    public function printResponse()
236
    {
237
        echo sprintf(
238
            "%s %s => %d:\n%s",
239
            $this->getRequest()->getMethod(),
240
            (string) $this->getRequest()->getUri(),
241
            $this->getResponse()->getStatusCode(),
242
            (string) $this->getResponse()->getBody()
243
        );
244
    }
245
246
    /**
247
     * @return RequestInterface
248
     */
249
    public function getRequest()
250
    {
251
        if ($this->request === null) {
252
            throw new \RuntimeException('You should create a request before using it.');
253
        }
254
255
        return $this->request;
256
    }
257
258
    /**
259
     * @return ResponseInterface
260
     */
261
    public function getResponse()
262
    {
263
        if ($this->response === null) {
264
            throw new \RuntimeException('You should send a request before using the response.');
265
        }
266
267
        return $this->response;
268
    }
269
270
    /**
271
     * @return MultipartStreamBuilder
272
     */
273
    private function getMultipartStreamBuilder()
274
    {
275
        if ($this->multipartStreamBuilder === null) {
276
            $this->multipartStreamBuilder = new MultipartStreamBuilder($this->streamFactory);
277
        }
278
279
        return $this->multipartStreamBuilder;
280
    }
281
282
    /**
283
     * @param string $url
284
     *
285
     * @return string
286
     */
287
    private function prepareUrl($url)
288
    {
289
        return $this->baseUrl.$url;
290
    }
291
292
    private function sendRequest()
293
    {
294
        $request = $this->getRequest();
295
296
        if ($this->multipartStreamBuilder !== null) {
297
            $request = $request->withBody($this->multipartStreamBuilder->build());
298
        }
299
300
        try {
301
            $this->response = $this->client->sendRequest($request);
302
        } catch (HttpException $e) {
303
            $this->response = $e->getResponse();
304
305
            if ($this->response === null) {
306
                throw $e;
307
            }
308
        }
309
    }
310
}
311