Completed
Push — master ( 045dfa...29039c )
by Gareth
04:14
created

HttpPlayback::getRecordLocation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 7
nc 2
nop 0
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 33
    public static function getInstance($options = [])
32
    {
33 33
        foreach (self::$instances as $instance) {
34 33
            if ($instance['options'] == $options) {
35 33
                return $instance['instance'];
36
            }
37
        }
38
39 29
        $instance = new static();
40 29
        $instance->setPlaybackOptions($options);
41 29
        self::$instances[] = [
42 29
            'instance' => $instance,
43 29
            'options' => $options
44
        ];
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
        );
55
56 30
        if ($options['mode'] !== null) {
57 30
            $this->mode = $options['mode'];
58
        }
59
60 30
        if ($options['recordLocation'] !== null) {
61 1
            $this->recordLocation = $options['recordLocation'];
62
        }
63
64 30
        if ($options['recordFileName'] !== null) {
65 30
            $this->recordFileName = $options['recordFileName'];
66
        }
67
    }
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
        }
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
        }
97
98 26
        return $this->client;
99
    }
100
101
    /**
102
     * Sets the client
103
     *
104
     * @param Client $client
105
     * @return $this
106
     */
107
    public function setHttpClient($client)
108
    {
109
        $this->client = $client;
110
111
        return $this;
112
    }
113
114 27
    public function getRecordLocation()
115
    {
116 27
        if (!$this->recordLocation) {
117 26
            $dir = __DIR__;
118 26
            $dirPos = strrpos($dir, "src/API");
119 26
            $dir = substr($dir, 0, $dirPos);
120
121 26
            $this->recordLocation = $dir.'Resources/recordings/';
122
        }
123
124 27
        return $this->recordLocation;
125
    }
126
127 27
    public function getRecordFilePath()
128
    {
129 27
        $path = $this->getRecordLocation().$this->recordFileName;
130 27
        $path = str_replace("\\", "/", $path);
131
132 27
        return $path;
133
    }
134
135 26
    public function getRecordings()
136
    {
137 26
        $saveLocation = $this->getRecordFilePath();
138 26
        $records = json_decode(file_get_contents($saveLocation), true);
139
140 26
        return $records;
141
    }
142
143 1
    public function endRecord()
144
    {
145 1
        if ($this->mode != 'record') {
146 1
            return;
147
        }
148
149 1
        $saveList = $this->responsesToArray($this->callList);
150
151 1
        $saveLocation = $this->getRecordFilePath();
152 1
        $folder = pathinfo($saveLocation)['dirname'];
153 1
        if (!is_dir($folder)) {
154 1
            mkdir($folder, 0777, true);
155
        }
156
157 1
        file_put_contents($saveLocation, json_encode($saveList));
158
    }
159
160
    /**
161
     * @param $responses
162
     * @return array
163
     */
164 1
    protected function responsesToArray($responses)
165
    {
166 1
        $array = [];
167 1
        foreach ($responses as $item) {
168
            /** @var Response $response */
169
            $response = $item['response'];
170
171
            if (!isset($item['error'])) {
172
                $save = [
173
                    'error' => false,
174
                    'statusCode' => $response->getStatusCode(),
175
                    'headers' => $response->getHeaders(),
176
                    'body' => $response->getBody()->__toString()
177
                ];
178
            } else {
179
                $save = [
180
                    'error' => true,
181
                    'errorClass' => get_class($item['error']),
182
                    'errorMessage' => $item['error']->getMessage(),
183
                    'request' => [
184
                        'method' => $item['request']->getMethod(),
185
                        'uri' => $item['request']->getUri()->__toString(),
186
                        'headers' => $item['request']->getHeaders(),
187
                        'body' => $item['request']->getBody()->__toString()
188
                    ]
189
                ];
190
            }
191 1
            $array[] = $save;
192
        }
193
194 1
        return $array;
195
    }
196
197
    /**
198
     * @param $items
199
     * @return Response[]
200
     */
201 26
    protected function arrayToResponses($items)
202
    {
203 26
        $mockedResponses = [];
204 26
        foreach ($items as $item) {
205 26
            if (!$item['error']) {
206 25
                $mockedResponses[] = new Response($item['statusCode'], $item['headers'], $item['body']);
207
            } else {
208 2
                $errorClass = $item['errorClass'];
209 2
                $request = new Request(
210 2
                    $item['request']['method'],
211 2
                    $item['request']['uri'],
212 2
                    $item['request']['headers'],
213 2
                    $item['request']['body']
214
                );
215 26
                $mockedResponses[] = new $errorClass($item['errorMessage'], $request);
216
            }
217
        }
218
219 26
        return $mockedResponses;
220
    }
221
}
222