Passed
Pull Request — master (#33)
by Joao
08:26
created

AbstractRequester::withRequestBody()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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