Completed
Push — master ( 933198...a7d441 )
by Gareth
03:19
created

Client::request()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 3
crap 1
1
<?php
2
3
namespace garethp\ews\HttpPlayback;
4
5
use GuzzleHttp\HandlerStack;
6
use GuzzleHttp\Middleware;
7
use GuzzleHttp\Handler\MockHandler;
8
use GuzzleHttp\Psr7\Request;
9
use GuzzleHttp\Psr7\Response;
10
use Psr\Http\Message\ResponseInterface;
11
use GuzzleHttp\Client as GuzzleClient;
12
13
/**
14
 * @method ResponseInterface get($uri, array $options = [])
15
 * @method ResponseInterface head($uri, array $options = [])
16
 * @method ResponseInterface put($uri, array $options = [])
17
 * @method ResponseInterface post($uri, array $options = [])
18
 * @method ResponseInterface patch($uri, array $options = [])
19
 * @method ResponseInterface delete($uri, array $options = [])
20
 * @method ResponseInterface getAsync($uri, array $options = [])
21
 * @method ResponseInterface headAsync($uri, array $options = [])
22
 * @method ResponseInterface putAsync($uri, array $options = [])
23
 * @method ResponseInterface postAsync($uri, array $options = [])
24
 * @method ResponseInterface patchAsync($uri, array $options = [])
25
 * @method ResponseInterface deleteAsync($uri, array $options = [])
26
 */
27
class Client
28
{
29
    protected $mode = 'live';
30
31
    protected $callList = [];
32
33
    protected $recordLocation;
34
35
    protected $recordFileName = 'saveState.json';
36
37
    private $shutdownRegistered = false;
38
39
    /**
40
     * @var GuzzleClient
41
     */
42
    private $client;
43
44 31
    public function __construct($options = [])
45
    {
46 31
        $options = array_replace_recursive(
47 31
            ['mode' => null, 'recordLocation' => null, 'recordFileName' => null],
48
            $options
49
        );
50
51 31
        if ($options['mode'] !== null) {
52 31
            $this->mode = $options['mode'];
53
        }
54
55 31
        if ($options['recordLocation'] !== null) {
56 1
            $this->recordLocation = $options['recordLocation'];
57
        }
58
59 31
        if ($options['recordFileName'] !== null) {
60 31
            $this->recordFileName = $options['recordFileName'];
61
        }
62
63 31
        $this->setupClient();
64
    }
65
66 28
    public function __call($method, $args)
67
    {
68 28
        if (count($args) < 1) {
69
            throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
70
        }
71
72 28
        $uri = $args[0];
73 28
        $opts = isset($args[1]) ? $args[1] : [];
74
75 28
        return substr($method, -5) === 'Async'
76
            ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
77 28
            : $this->request($method, $uri, $opts);
78
    }
79
80
    /**
81
     * @param $method
82
     * @param null $uri
83
     * @param array $options
84
     *
85
     * @return ResponseInterface
86
     */
87 28
    public function request($method, $uri = null, array $options = [])
88
    {
89 28
        return $this->client->request($method, $uri, $options);
90
    }
91
92
    /**
93
     * @param $method
94
     * @param null $uri
95
     * @param array $options
96
     *
97
     * @return ResponseInterface
98
     */
99
    public function requestAsync($method, $uri = null, array $options = [])
100
    {
101
        return $this->client->requestAsync($method, $uri, $options);
102
    }
103
104
    /**
105
     * Get the client for making calls
106
     *
107
     * @return Client
108
     */
109 31
    protected function setupClient()
110
    {
111 31
        if ($this->client !== null) {
112
            return $this->client;
113
        }
114
115 31
        $handler = HandlerStack::create();
116
117 31
        if ($this->mode == 'record') {
118 1
            $history = Middleware::history($this->callList);
119 1
            $handler->push($history);
120 31
        } elseif ($this->mode == 'playback') {
121 30
            $recordings = $this->getRecordings();
122 30
            $mockHandler = new MockHandler($this->arrayToResponses($recordings));
123 30
            $handler = HandlerStack::create($mockHandler);
124
        }
125
126 31
        $this->registerShutdown();
127 31
        $this->client = new GuzzleClient(['handler' => $handler]);
128
129 31
        return $this->client;
130
    }
131
132 31
    protected function getRecordLocation()
133
    {
134 31
        if (!$this->recordLocation) {
135 30
            $dir = __DIR__;
136 30
            $dirPos = strrpos($dir, "src/API");
137 30
            $dir = substr($dir, 0, $dirPos);
138
139 30
            $this->recordLocation = $dir.'Resources/recordings/';
140
        }
141
142 31
        return $this->recordLocation;
143
    }
144
145 31
    protected function getRecordFilePath()
146
    {
147 31
        $path = $this->getRecordLocation() . $this->recordFileName;
148 31
        $path = str_replace("\\", "/", $path);
149
150 31
        return $path;
151
    }
152
153 30
    protected function getRecordings()
154
    {
155 30
        $saveLocation = $this->getRecordFilePath();
156 30
        $records = json_decode(file_get_contents($saveLocation), true);
157
158 30
        return $records;
159
    }
160
161 1
    public function endRecord()
162
    {
163 1
        if ($this->mode != 'record') {
164 1
            return;
165
        }
166
167 1
        $saveList = $this->responsesToArray($this->callList);
168
169 1
        $saveLocation = $this->getRecordFilePath();
170 1
        $folder = pathinfo($saveLocation)['dirname'];
171 1
        if (!is_dir($folder)) {
172 1
            mkdir($folder, 0777, true);
173
        }
174
175 1
        file_put_contents($saveLocation, json_encode($saveList));
176
    }
177
178 31
    protected function registerShutdown()
179
    {
180 31
        if (!$this->shutdownRegistered) {
181 31
            register_shutdown_function(array($this, 'endRecord'));
182 31
            $this->shutdownRegistered = true;
183
        }
184
    }
185
186
    /**
187
     * @param $responses
188
     * @return array
189
     */
190 1
    protected function responsesToArray($responses)
191
    {
192 1
        $array = [];
193 1
        foreach ($responses as $item) {
194
            /** @var Response $response */
195
            $response = $item['response'];
196
197
            if (!isset($item['error'])) {
198
                $save = [
199
                    'error' => false,
200
                    'statusCode' => $response->getStatusCode(),
201
                    'headers' => $response->getHeaders(),
202
                    'body' => $response->getBody()->__toString()
203
                ];
204
            } else {
205
                $save = [
206
                    'error' => true,
207
                    'errorClass' => get_class($item['error']),
208
                    'errorMessage' => $item['error']->getMessage(),
209
                    'request' => [
210
                        'method' => $item['request']->getMethod(),
211
                        'uri' => $item['request']->getUri()->__toString(),
212
                        'headers' => $item['request']->getHeaders(),
213
                        'body' => $item['request']->getBody()->__toString()
214
                    ]
215
                ];
216
            }
217 1
            $array[] = $save;
218
        }
219
220 1
        return $array;
221
    }
222
223
    /**
224
     * @param $items
225
     * @return Response[]
226
     */
227 30
    protected function arrayToResponses($items)
228
    {
229 30
        $mockedResponses = [];
230 30
        foreach ($items as $item) {
231 28
            if (!$item['error']) {
232 28
                $mockedResponses[] = new Response($item['statusCode'], $item['headers'], $item['body']);
233
            } else {
234 2
                $errorClass = $item['errorClass'];
235 2
                $request = new Request(
236 2
                    $item['request']['method'],
237 2
                    $item['request']['uri'],
238 2
                    $item['request']['headers'],
239 2
                    $item['request']['body']
240
                );
241 30
                $mockedResponses[] = new $errorClass($item['errorMessage'], $request);
242
            }
243
        }
244
245 30
        return $mockedResponses;
246
    }
247
}
248