Completed
Push — master ( 23167a...7d206d )
by Eric
37:03 queued 25:30
created

ApiContext::sendRequest()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 3
nop 0
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\RequestFactory;
19
use Lug\Component\Behat\Extension\Api\Matcher\MatcherFactory;
20
use Psr\Http\Message\RequestInterface;
21
use Psr\Http\Message\ResponseInterface;
22
23
/**
24
 * @author GeLo <[email protected]>
25
 */
26
class ApiContext implements ApiContextInterface
27
{
28
    /**
29
     * @var HttpClient
30
     */
31
    private $client;
32
33
    /**
34
     * @var RequestFactory
35
     */
36
    private $requestFactory;
37
38
    /**
39
     * @var string
40
     */
41
    private $baseUrl;
42
43
    /**
44
     * @var string[][]
45
     */
46
    private $headers = [];
47
48
    /**
49
     * @var RequestInterface|null
50
     */
51
    private $request;
52
53
    /**
54
     * @var ResponseInterface|null
55
     */
56
    private $response;
57
58
    /**
59
     * @var Matcher
60
     */
61
    private $matcher;
62
63
    public function __construct()
64
    {
65
        $this->matcher = (new MatcherFactory())->createMatcher();
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function setClient(HttpClient $client)
72
    {
73
        $this->client = $client;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function setRequestFactory(RequestFactory $requestFactory)
80
    {
81
        $this->requestFactory = $requestFactory;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function setBaseUrl($baseUrl)
88
    {
89
        if (strrpos($baseUrl, '/') === strlen($baseUrl) - 1) {
90
            $baseUrl = substr($baseUrl, 0, -1);
91
        }
92
93
        $this->baseUrl = $baseUrl;
94
    }
95
96
    /**
97
     * @BeforeScenario
98
     */
99
    public function reset()
100
    {
101
        $this->headers = [];
102
        $this->request = null;
103
        $this->response = null;
104
    }
105
106
    /**
107
     * @param string $header
108
     * @param string $value
109
     *
110
     * @Given I set the header ":header" with value ":value"
111
     */
112
    public function setHeader($header, $value)
113
    {
114
        $this->headers[$header] = [$value];
115
    }
116
117
    /**
118
     * @param string $header
119
     * @param string $value
120
     *
121
     * @Given I add the header ":header" with value ":value"
122
     */
123
    public function addHeader($header, $value)
124
    {
125
        $this->headers[$header][] = $value;
126
    }
127
128
    /**
129
     * @param string $header
130
     *
131
     * @Given I remove the header ":header"
132
     */
133
    public function removeHeader($header)
134
    {
135
        unset($this->headers[$header]);
136
    }
137
138
    /**
139
     * @param string $method
140
     * @param string $url
141
     *
142
     * @When I send a ":method" request to ":url"
143
     */
144
    public function send($method, $url)
145
    {
146
        $this->request = $this->requestFactory->createRequest($method, $this->prepareUrl($url), $this->headers);
147
148
        $this->sendRequest();
149
    }
150
151
    /**
152
     * @param string       $method
153
     * @param string       $url
154
     * @param PyStringNode $string
155
     *
156
     * @When I send a ":method" request to ":url" with body:
157
     */
158
    public function sendWith($method, $url, PyStringNode $string)
159
    {
160
        $this->request = $this->requestFactory->createRequest(
161
            $method,
162
            $this->prepareUrl($url),
163
            $this->headers,
164
            trim($string->getRaw())
165
        );
166
167
        $this->sendRequest();
168
    }
169
170
    /**
171
     * @param string $statusCode
172
     *
173
     * @Then the response status code should be ":statusCode"
174
     */
175
    public function assertResponseStatusCode($statusCode)
176
    {
177
        \PHPUnit_Framework_Assert::assertSame((int) $statusCode, $this->getResponse()->getStatusCode());
178
    }
179
180
    /**
181
     * @param PyStringNode $json
182
     *
183
     * @Then the response should contain:
184
     */
185
    public function assertResponseContains(PyStringNode $json)
186
    {
187
        $this->matcher->match((string) $this->response->getBody(), $json->getRaw());
188
189
        \PHPUnit_Framework_Assert::assertNull($this->matcher->getError());
190
    }
191
192
    /**
193
     * @Then the response should be empty
194
     */
195
    public function assertResponseEmpty()
196
    {
197
        \PHPUnit_Framework_Assert::assertEmpty((string) $this->getResponse()->getBody());
198
    }
199
200
    /**
201
     * @Then I print the response
202
     */
203
    public function printResponse()
204
    {
205
        echo sprintf(
206
            "%s %s => %d:\n%s",
207
            $this->getRequest()->getMethod(),
208
            (string) $this->getRequest()->getUri(),
209
            $this->getResponse()->getStatusCode(),
210
            (string) $this->getResponse()->getBody()
211
        );
212
    }
213
214
    /**
215
     * @return RequestInterface
216
     */
217
    public function getRequest()
218
    {
219
        if ($this->request === null) {
220
            throw new \RuntimeException('You should create a request before using it.');
221
        }
222
223
        return $this->request;
224
    }
225
226
    /**
227
     * @return ResponseInterface
228
     */
229
    public function getResponse()
230
    {
231
        if ($this->response === null) {
232
            throw new \RuntimeException('You should send a request before using the response.');
233
        }
234
235
        return $this->response;
236
    }
237
238
    /**
239
     * @param string $url
240
     *
241
     * @return string
242
     */
243
    private function prepareUrl($url)
244
    {
245
        return $this->baseUrl.$url;
246
    }
247
248
    private function sendRequest()
249
    {
250
        try {
251
            $this->response = $this->client->sendRequest($this->getRequest());
252
        } catch (HttpException $e) {
253
            $this->response = $e->getResponse();
254
255
            if ($this->response === null) {
256
                throw $e;
257
            }
258
        }
259
    }
260
}
261