Passed
Pull Request — master (#50)
by Joao
02:13
created

AbstractRequester::handleRequest()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
c 0
b 0
f 0
nc 1
1
<?php
2
3
namespace ByJG\ApiTools;
4
5
use ByJG\ApiTools\Base\Schema;
6
use ByJG\ApiTools\Exception\NotMatchedException;
7
use ByJG\ApiTools\Exception\StatusCodeNotMatchedException;
8
use ByJG\Util\Psr7\MessageException;
9
use ByJG\Util\Psr7\Request;
10
use ByJG\Util\Uri;
11
use MintWare\Streams\MemoryStream;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * Abstract baseclass for request handlers.
17
 *
18
 * The baseclass provides processing and verification of request and response.
19
 * It only delegates the actual message exchange to the derived class. For the
20
 * messages, it uses the PSR-7 implementation from Guzzle.
21
 *
22
 * This is an implementation of the Template Method Patttern
23
 * (https://en.wikipedia.org/wiki/Template_method_pattern).
24
 */
25
abstract class AbstractRequester
26
{
27
    protected $method = 'get';
28
    protected $path = '/';
29
    protected $requestHeader = [];
30
    protected $query = [];
31
    protected $requestBody = null;
32
    /**
33
     * @var Schema
34
     */
35
    protected $schema = null;
36
37
    protected $statusExpected = 200;
38
    protected $assertHeader = [];
39
    protected $assertBody = null;
40
41
    /**
42
     * abstract function to be implemented by derived classes
43
     *
44
     * This function must be implemented by derived classes. It should process
45
     * the given request and return an according response.
46
     *
47
     * @param RequestInterface $request
48
     * @return ResponseInterface
49
     */
50
    abstract protected function handleRequest(RequestInterface $request);
51
52
    /**
53
     * @param Schema $schema
54
     * @return $this
55
     */
56
    public function withSchema($schema)
57
    {
58
        $this->schema = $schema;
59
60
        return $this;
61
    }
62
63
    /**
64
     * @return bool
65
     */
66
    public function hasSchema()
67
    {
68
        return !empty($this->schema);
69
    }
70
71
    /**
72
     * @param string $method
73
     * @return $this
74
     */
75
    public function withMethod($method)
76
    {
77
        $this->method = $method;
78
79
        return $this;
80
    }
81
82
    /**
83
     * @param string $path
84
     * @return $this
85
     */
86
    public function withPath($path)
87
    {
88
        $this->path = $path;
89
90
        return $this;
91
    }
92
93
    /**
94
     * @param array $requestHeader
95
     * @return $this
96
     */
97
    public function withRequestHeader($requestHeader)
98
    {
99
        if (is_null($requestHeader)) {
100
            $this->requestHeader = [];
101
            return $this;
102
        }
103
104
        $this->requestHeader = array_merge($this->requestHeader, $requestHeader);
105
106
        return $this;
107
    }
108
109
    /**
110
     * @param array $query
111
     * @return $this
112
     */
113
    public function withQuery($query = null)
114
    {
115
        if (is_null($query)) {
116
            $this->query = [];
117
            return $this;
118
        }
119
120
        $this->query = array_merge($this->query, $query);
121
122
        return $this;
123
    }
124
125
    /**
126
     * @param null $requestBody
127
     * @return $this
128
     */
129
    public function withRequestBody($requestBody)
130
    {
131
        $this->requestBody = $requestBody;
132
133
        return $this;
134
    }
135
136
    public function assertResponseCode($code)
137
    {
138
        $this->statusExpected = $code;
139
140
        return $this;
141
    }
142
143
    public function assertHeaderContains($header, $contains)
144
    {
145
        $this->assertHeader[$header] = $contains;
146
147
        return $this;
148
    }
149
150
    public function assertBodyContains($contains)
151
    {
152
        $this->assertBody = $contains;
153
154
        return $this;
155
    }
156
157
    /**
158
     * @return mixed
159
     * @throws Exception\DefinitionNotFoundException
160
     * @throws Exception\GenericSwaggerException
161
     * @throws Exception\HttpMethodNotFoundException
162
     * @throws Exception\InvalidDefinitionException
163
     * @throws Exception\PathNotFoundException
164
     * @throws NotMatchedException
165
     * @throws StatusCodeNotMatchedException
166
     * @throws MessageException
167
     */
168
    public function send()
169
    {
170
        // Preparing Parameters
171
        $paramInQuery = null;
172
        if (!empty($this->query)) {
173
            $paramInQuery = '?' . http_build_query($this->query);
174
        }
175
176
        // Preparing Header
177
        if (empty($this->requestHeader)) {
178
            $this->requestHeader = [];
179
        }
180
        $header = array_merge(
181
            [
182
                'Accept' => 'application/json'
183
            ],
184
            $this->requestHeader
185
        );
186
187
        // Defining Variables
188
        $serverUrl = $this->schema->getServerUrl();
189
        $basePath = $this->schema->getBasePath();
190
        $pathName = $this->path;
191
192
        // Check if the body is the expected before request
193
        $bodyRequestDef = $this->schema->getRequestParameters("$basePath$pathName", $this->method);
194
        $bodyRequestDef->match($this->requestBody);
195
196
        // Make the request
197
        $request = Request::getInstance(Uri::getInstanceFromString($serverUrl . $pathName . $paramInQuery))
198
            ->withMethod($this->method);
199
200
        if (!empty($this->requestBody)) {
201
            $request->withBody(new MemoryStream(json_encode($this->requestBody)));
202
        }
203
204
        foreach ($header as $key => $value) {
205
            $request->withHeader($key, $value);
206
        }
207
208
        $response = $this->handleRequest($request);
209
        $responseHeader = $response->getHeaders();
210
        $responseBodyStr = (string) $response->getBody();
211
        $responseBody = json_decode($responseBodyStr, true);
212
        $statusReturned = $response->getStatusCode();
213
214
        // Assert results
215
        if ($this->statusExpected != $statusReturned) {
216
            throw new StatusCodeNotMatchedException(
217
                "Status code not matched: Expected {$this->statusExpected}, got {$statusReturned}",
218
                $responseBody
219
            );
220
        }
221
222
        $bodyResponseDef = $this->schema->getResponseParameters(
223
            "$basePath$pathName",
224
            $this->method,
225
            $this->statusExpected
226
        );
227
        $bodyResponseDef->match($responseBody);
228
229
        foreach ($this->assertHeader as $key => $value) {
230
            if (!isset($responseHeader[$key]) || strpos($responseHeader[$key][0], $value) === false) {
231
                throw new NotMatchedException(
232
                    "Does not exists header '$key' with value '$value'",
233
                    $responseHeader
234
                );
235
            }
236
        }
237
238
        if (!empty($this->assertBody) && strpos($responseBodyStr, $this->assertBody) === false) {
239
            throw new NotMatchedException("Body does not contain '{$this->assertBody}'");
240
        }
241
242
        return $responseBody;
243
    }
244
}
245