Completed
Push — master ( f414e6...045dfa )
by Gareth
05:22
created

HttpPlayback::getHttpClient()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5.0342

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 26
ccs 16
cts 18
cp 0.8889
rs 8.439
cc 5
eloc 16
nc 7
nop 0
crap 5.0342
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 33
    public static function getInstance($options = [])
32
    {
33 33
        foreach (self::$instances as $instance) {
34 33
            if ($instance['options'] == $options) {
35 16
                return $instance['instance'];
36
            }
37 33
        }
38
39 29
        $instance = new static();
40 29
        $instance->setPlaybackOptions($options);
41 29
        self::$instances[] = [
42 29
            'instance' => $instance,
43
            'options' => $options
44 29
        ];
45
46 29
        return $instance;
47
    }
48
49 30
    public function setPlaybackOptions($options = [])
50
    {
51 30
        $options = array_replace_recursive(
52 30
            ['mode' => null, 'recordLocation' => null, 'recordFileName' => null],
53
            $options
54 30
        );
55
56 30
        if ($options['mode'] !== null) {
57 30
            $this->mode = $options['mode'];
58 30
        }
59
60 30
        if ($options['recordLocation'] !== null) {
61 1
            $this->recordLocation = $options['recordLocation'];
62 1
        }
63
64 30
        if ($options['recordFileName'] !== null) {
65 30
            $this->recordFileName = $options['recordFileName'];
66 30
        }
67 30
    }
68
69
    /**
70
     * Get the client for making calls
71
     *
72
     * @return Client
73
     */
74 26
    public function getHttpClient()
75
    {
76 26
        if ($this->client !== null) {
77 25
            return $this->client;
78
        }
79
80 26
        $handler = HandlerStack::create();
81
82 26
        if ($this->mode == 'record') {
83
            $history = Middleware::history($this->callList);
84
            $handler->push($history);
85 26
        } elseif ($this->mode == 'playback') {
86 26
            $recordings = $this->getRecordings();
87 26
            $mockHandler = new MockHandler($this->buildMockedResponses($recordings));
88 26
            $handler = HandlerStack::create($mockHandler);
89 26
        }
90
91 26
        $this->client = new Client(['handler' => $handler]);
92
93 26
        if (!$this->shutdownRegistered) {
94 26
            register_shutdown_function(array($this, 'endRecord'));
95 26
            $this->shutdownRegistered = true;
96 26
        }
97
98 26
        return $this->client;
99
    }
100
101 26
    protected function buildMockedResponses($items)
102
    {
103 26
        $mockedResponses = [];
104 26
        foreach ($items as $item) {
105 26
            if (!$item['error']) {
106 25
                $mockedResponses[] = new Response($item['statusCode'], $item['headers'], $item['body']);
107 25
            } else {
108 2
                $errorClass = $item['errorClass'];
109 2
                $request = new Request(
110 2
                    $item['request']['method'],
111 2
                    $item['request']['uri'],
112 2
                    $item['request']['headers'],
113 2
                    $item['request']['body']
114 2
                );
115 2
                $mockedResponses[] = new $errorClass($item['errorMessage'], $request);
116
            }
117 26
        }
118
119 26
        return $mockedResponses;
120
    }
121
122
    /**
123
     * Sets the client
124
     *
125
     * @param Client $client
126
     * @return $this
127
     */
128
    public function setHttpClient($client)
129
    {
130
        $this->client = $client;
131
132
        return $this;
133
    }
134
135 27
    public function getRecordLocation()
136
    {
137 27
        if (!$this->recordLocation) {
138 26
            $dir = __DIR__;
139 26
            $dirPos = strrpos($dir, "src/API");
140 26
            $dir = substr($dir, 0, $dirPos);
141
142 26
            $this->recordLocation = $dir.'Resources/recordings/';
143 26
        }
144
145 27
        return $this->recordLocation;
146
    }
147
148 27
    public function getRecordFilePath()
149
    {
150 27
        $path = $this->getRecordLocation().$this->recordFileName;
151 27
        $path = str_replace("\\", "/", $path);
152
153 27
        return $path;
154
    }
155
156 26
    public function getRecordings()
157
    {
158 26
        $saveLocation = $this->getRecordFilePath();
159 26
        $records = json_decode(file_get_contents($saveLocation), true);
160
161 26
        return $records;
162
    }
163
164 1
    public function endRecord()
165
    {
166 1
        if ($this->mode != 'record') {
167 1
            return;
168
        }
169
170 1
        $saveList = [];
171 1
        foreach ($this->callList 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
            $saveList[] = $save;
196 1
        }
197
198 1
        $saveLocation = $this->getRecordFilePath();
199 1
        $folder = pathinfo($saveLocation)['dirname'];
200 1
        if (!is_dir($folder)) {
201 1
            mkdir($folder, 0777, true);
202 1
        }
203
204 1
        file_put_contents($saveLocation, json_encode($saveList));
205 1
    }
206
}
207