Completed
Push — master ( c7e42b...9e6269 )
by Gareth
03:51
created

HttpPlayback::setHttpClient()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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