Completed
Push — master ( 7f67d6...f80470 )
by Gareth
03:46
created

HttpPlayback::getRecordFilePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
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 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->arrayToResponses($recordings));
88 26
            $handler = HandlerStack::create($mockHandler);
89 26
        }
90
91 26
        $this->registerShutdown();
92 26
        $this->client = new Client(['handler' => $handler]);
93
94 26
        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 27
    public function getRecordLocation()
111
    {
112 27
        if (!$this->recordLocation) {
113 26
            $dir = __DIR__;
114 26
            $dirPos = strrpos($dir, "src/API");
115 26
            $dir = substr($dir, 0, $dirPos);
116
117 26
            $this->recordLocation = $dir.'Resources/recordings/';
118 26
        }
119
120 27
        return $this->recordLocation;
121
    }
122
123 27
    public function getRecordFilePath()
124
    {
125 27
        $path = $this->getRecordLocation() . $this->recordFileName;
126 27
        $path = str_replace("\\", "/", $path);
127
128 27
        return $path;
129
    }
130
131 26
    public function getRecordings()
132
    {
133 26
        $saveLocation = $this->getRecordFilePath();
134 26
        $records = json_decode(file_get_contents($saveLocation), true);
135
136 26
        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 1
        }
152
153 1
        file_put_contents($saveLocation, json_encode($saveList));
154 1
    }
155
156 26
    protected function registerShutdown()
157
    {
158 26
        if (!$this->shutdownRegistered) {
159 26
            register_shutdown_function(array($this, 'endRecord'));
160 26
            $this->shutdownRegistered = true;
161 26
        }
162 26
    }
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
            $array[] = $save;
196 1
        }
197
198 1
        return $array;
199
    }
200
201
    /**
202
     * @param $items
203
     * @return Response[]
204
     */
205 26
    protected function arrayToResponses($items)
206
    {
207 26
        $mockedResponses = [];
208 26
        foreach ($items as $item) {
209 26
            if (!$item['error']) {
210 25
                $mockedResponses[] = new Response($item['statusCode'], $item['headers'], $item['body']);
211 25
            } 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 2
                );
219 2
                $mockedResponses[] = new $errorClass($item['errorMessage'], $request);
220
            }
221 26
        }
222
223 26
        return $mockedResponses;
224
    }
225
}
226