Passed
Push — master ( 5b31c8...ce99ce )
by AHMED JOHARI
02:52
created

Hook::implementWebHookConnector()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 18
ccs 10
cts 10
cp 1
rs 9.9666
cc 1
nc 1
nop 1
crap 1
1
<?php
2
namespace Joesama\Webhook\Web;
3
4
use Illuminate\Support\Arr;
5
use Illuminate\Support\Str;
6
use Joesama\Webhook\Web\Ping;
7
use GuzzleHttp\RequestOptions;
8
use Illuminate\Support\Facades\Log;
9
use Psr\Http\Message\RequestInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use GuzzleHttp\Exception\TransferException;
12
use Joesama\Webhook\Exceptions\WebHookException;
13
use Joesama\Webhook\Connectors\ConnectorContract;
14
15
class Hook extends Ping
16
{
17
    /**
18
     * WebHook request configuration.
19
     *
20
     * @var array
21
     */
22
    private $hooks;
23
24
    /**
25
     * Implementation of ConnectorContract.
26
     *
27
     * @var ConnectorContract
28
     */
29
    private $connector;
30
31
    /**
32
     * Connector id definition.
33
     *
34
     * @var string
35
     */
36
    private $connectorId;
37
38
    /**
39
     * WebHook constructor.
40
     *
41
     * @param ConnectorContract|array $config|string $config
42
     */
43 11
    public function __construct($config = [])
44
    {
45 11
        if ($config instanceof ConnectorContract) {
46 1
            $this->implementWebHookConnector($config);
47
        } else {
48 10
            $this->configs = $this->webHookConfigurable($config);
49
        }
50 11
    }
51
52
    /**
53
     * Set the request body parameter.
54
     *
55
     * @param array  $request
56
     * @param string $type
57
     * @return Hook
58
     */
59 5
    public function setRequestBody(array $request, string $type = 'json'): self
60
    {
61 5
        $this->mapContentType($type);
62
63 5
        $this->options[$type] = $request;
64
65 5
        return $this;
66
    }
67
68
    /**
69
     * Set request header parameter.
70
     *
71
     * @param array $headers
72
     * @return Hook
73
     */
74 1
    public function setRequestHeader(array $headers): self
75
    {
76 1
        $this->configs[RequestOptions::HEADERS] = array_merge(
77 1
            Arr::get($this->configs, RequestOptions::HEADERS, []),
78 1
            $headers
79
        );
80
81 1
        return $this;
82
    }
83
84
    /**
85
     * Attached configuration parameters.
86
     *
87
     * @param string|array $config
88
     * @return Hook
89
     */
90 1
    public function configurable($config): self
91
    {
92 1
        $this->configs = $this->webHookConfigurable($config);
93
94 1
        return $this;
95
    }
96
97
    /**
98
     * Get response from end point.
99
     *
100
     * @param string $url    Endpoint URL
101
     * @param string $method Request method
102
     * @return mixed
103
     */
104 1
    public function getResponse(string $url = null, string $method = 'POST')
105
    {
106 1
        $this->setUrlRequest($method, $url);
107
108 1
        return $this->responseHandler($this->dispatch(), $this->getPsr7RequestHeader());
109
    }
110
111
    /**
112
     * Prepare configuration parameter.
113
     *
114
     * @param array|string $config
115
     * @return array
116
     */
117 11
    private function webHookConfigurable($config): array
118
    {
119 11
        if (is_string($config)) {
120
            $hookConfig = new Config($config);
121
122
            $config = $hookConfig->configs;
123
124
            $this->hooks = $hookConfig->hooks;
125
        }
126
127 11
        return array_merge($config, $this->configs);
128
    }
129
130
    /**
131
     * Implement WebHookConnector definition.
132
     *
133
     * @param ConnectorContract $connector
134
     */
135 1
    private function implementWebHookConnector(ConnectorContract $connector): void
136
    {
137 1
        $this->connector = $connector;
138
139 1
        $connector->setConnectorId(class_basename($connector));
140
141 1
        $this->connectorId = $connector->getConnectorId();
142
143 1
        $this->configs = $this->webHookConfigurable($connector->webHookConfiguration());
144
145 1
        $this->mapContentType($connector->webHookContentType());
146
147 1
        $this->configs[RequestOptions::HEADERS] = array_merge(
148 1
            Arr::get($this->configs, RequestOptions::HEADERS, []),
149 1
            $connector->webHookHeader()
150
        );
151
152 1
        $this->options[$connector->webHookContentType()] = $connector->webHookContent();
153 1
    }
154
155
    /**
156
     * Map request content with header content type.
157
     *
158
     * @param string $type
159
     */
160 6
    private function mapContentType(string $type): void
161
    {
162
        $default = [
163 6
            RequestOptions::JSON => 'application/json',
164 6
            RequestOptions::MULTIPART => 'multipart/form-data',
165 6
            RequestOptions::FORM_PARAMS => 'application/x-www-form-urlencoded',
166
        ];
167
168 6
        if (($contentType = Arr::get($default, strtolower($type), null)) !== null) {
169 5
            $this->configs[RequestOptions::HEADERS]['Content-type'] = $contentType;
170
        }
171 6
    }
172
173
    /**
174
     * Set url & request method from webhook configurable.
175
     *
176
     * @param string $method
177
     * @param string|null $url
178
     */
179 1
    private function setUrlRequest(string $method, ?string $url): void
180
    {
181 1
        $this->method = $method;
182
183 1
        $this->pathUri = Str::contains($url, '/') ? $url : Arr::get($this->hooks, $url . '.' . $method, $url);
184 1
    }
185
186
    /**
187
     * WebHook HTTP response handler.
188
     *
189
     * @param ResponseInterface $response
190
     * @param RequestInterface  $request
191
     * @return mixed
192
     */
193
    private function responseHandler(ResponseInterface $response, RequestInterface $request)
194
    {
195
        if ($this->connector instanceof ConnectorContract) {
0 ignored issues
show
introduced by
$this->connector is always a sub-type of Joesama\Webhook\Connectors\ConnectorContract.
Loading history...
196
            return $this->connector->webHookResponse($response, $request);
197
        }
198
199
        return $response;
200
    }
201
202
    /**
203
     * WebHook HTTP request exception handler.
204
     *
205
     * @param TransferException $exception
206
     *
207
     * @return mixed
208
     * @throws WebHookException
209
     */
210 1
    protected function exceptionHandlers(TransferException $exception)
211
    {
212 1
        $this->logExceptionError($exception);
213
214 1
        if ($this->connector instanceof ConnectorContract) {
0 ignored issues
show
introduced by
$this->connector is always a sub-type of Joesama\Webhook\Connectors\ConnectorContract.
Loading history...
215
            return $this->connector->webHookException($exception, $this->getPsr7RequestHeader());
216
        }
217
 
218 1
        throw new WebHookException($exception->getMessage(), $exception->getCode(), $exception);
219
    }
220
221
    /**
222
     * Log error exception produce.
223
     *
224
     * @param TransferException $exception
225
     */
226 1
    private function logExceptionError(TransferException $exception): void
227
    {
228 1
        $logData = $this->logDataFormat();
229
230 1
        $logData['response'] = $exception->getMessage();
231
232 1
        if ($this->connector instanceof ConnectorContract) {
0 ignored issues
show
introduced by
$this->connector is always a sub-type of Joesama\Webhook\Connectors\ConnectorContract.
Loading history...
233
            //Need to notify system log error has occurs as the exception are handles.
234
            $this->notifyCriticalLog($exception, $logData);
235
        }
236
237 1
        $this->saveLogToDatabase($logData);
238 1
    }
239
240
    /**
241
     * Sent critical notification to application log.
242
     *
243
     * @param TransferException $exception
244
     * @param array             $logData
245
     */
246
    private function notifyCriticalLog(TransferException $exception, array $logData): void
247
    {
248
        Log::critical(
249
            $this->connectorId,
250
            [
251
                'line' => $exception->getLine(),
252
                'file' => $exception->getFile(),
253
                'code' => $exception->getCode(),
254
                'url' => $logData['endpoint'],
255
                'method' => $this->method
256
            ]
257
        );
258
    }
259
260
    /**
261
     * Save the log data to data base.
262
     *
263
     * @param array $logData
264
     */
265 1
    private function saveLogToDatabase(array $logData)
266
    {
267 1
        if ($this->connector instanceof ConnectorContract) {
0 ignored issues
show
introduced by
$this->connector is always a sub-type of Joesama\Webhook\Connectors\ConnectorContract.
Loading history...
268
            //Saving log to data storage or etc...
269
            $this->connector->webHookSavingData($logData);
270
        }
271 1
    }
272
273
    /**
274
     * Format the log data.
275
     *
276
     * @return array
277
     */
278 1
    private function logDataFormat(): array
279
    {
280 1
        $request = $this->getPsr7RequestHeader();
281
282
        return [
283 1
            'method' => $this->method,
284 1
            'endpoint' => Arr::first($request->getHeader('base_uri')) . $request->getUri()->getPath(),
285 1
            'request' => array_merge($this->configs, $this->options),
286
            'response' => null
287
        ];
288
    }
289
}
290