Issues (1)

src/HttpHandler.php (1 issue)

1
<?php
2
3
namespace Msschl\Monolog\Handler;
4
5
use Http\Client\HttpClient;
6
use Http\Discovery\HttpClientDiscovery;
7
use Http\Discovery\MessageFactoryDiscovery;
8
use Http\Message\MessageFactory;
9
use Monolog\Formatter\FormatterInterface;
10
use Monolog\Formatter\JsonFormatter;
11
use Monolog\Handler\AbstractProcessingHandler;
12
use Monolog\Logger;
13
14
/**
15
 * This file is part of the msschl\monolog-http-handler package.
16
 *
17
 * Copyright (c) 2018 Markus Schlotbohm
18
 *
19
 * For the full copyright and license information, please view the LICENSE.md
20
 * file that was distributed with this source code.
21
 */
22
class HttpHandler extends AbstractProcessingHandler
23
{
24
25
	/**
26
	 * The http client instance.
27
	 *
28
     * @var \Http\Client\HttpClient
29
     */
30
    protected $client;
31
32
    /**
33
     * The message factory instance.
34
     *
35
     * @var \Http\Message\MessageFactory
36
     */
37
    protected $messageFactory;
38
39
    /**
40
     * The options array.
41
     *
42
     * @var array
43
     */
44
    protected $options = [
45
    	'uri'             => null,
46
    	'method'          => 'GET',
47
    	'headers'         => [
48
    		'Content-Type' => 'application/json'
49
    	],
50
    	'protocolVersion' => '1.1'
51
    ];
52
53
    /**
54
     * Initializes a new instance of the {@see HttpHandler} class.
55
     *
56
     * @param  array                $options The array of options consisting of the uri, method, headers and protocol
57
     *                                       version.
58
     * @param  HttpClient|null      $client  An instance of a psr-7 http client implementation or null when the
59
     *                                       HttpClientDiscovery should be used to find an instance.
60
     * @param  MessageFactory|null  $factory An instance of a psr-7 message factory implementation or null when
61
     *                                       the MessageFactoryDiscovery should be used to find an instance.
62
     * @param  int                  $level   The minimum logging level at which this handler will be triggered.
63
     * @param  boolean              $bubble  Whether the messages that are handled can bubble up the stack or not.
64
     */
65
	public function __construct(
66
		array $options = [],
67
		HttpClient $client = null,
68
		MessageFactory $factory = null,
69
		$level = Logger::DEBUG,
70
		$bubble = true
71
	) {
72
		$this->client = $client ?: HttpClientDiscovery::find();
73
		$this->messageFactory = $factory ?: MessageFactoryDiscovery::find();
74
75
		$this->setOptions($options);
76
77
		parent::__construct($level, $bubble);
78
	}
79
80
	/**
81
	 * Sets the options for the monolog http handler.
82
	 *
83
	 * @param  array $options The array of options.
84
	 * @return self
85
	 */
86
	public function setOptions(array $options)
87
	{
88
		$this->options = array_merge($this->options, $options);
89
90
		return $this;
91
	}
92
93
	/**
94
	 * Gets the uri.
95
	 *
96
	 * @return string|null
97
	 */
98
	public function getUri()
99
	{
100
		return $this->options['uri'];
101
	}
102
103
	/**
104
	 * Sets the uri.
105
	 *
106
	 * @param  string|null $uri Sets the http server uri or null to disable the {@see HttpHandler}.
107
	 * @return self
108
	 */
109
	public function setUri(string $uri = null)
110
	{
111
		$this->options['uri'] = $uri;
112
113
		return $this;
114
	}
115
116
	/**
117
	 * Gets the http method.
118
	 *
119
	 * @return string
120
	 */
121
	public function getMethod() : string
122
	{
123
		return $this->options['method'] ?? 'GET';
124
	}
125
126
	/**
127
	 * Sets the http method.
128
	 *
129
	 * @param  string $method The http method e.g. 'GET'.
130
	 * @return self
131
	 */
132
	public function setMethod(string $method)
133
	{
134
		$this->options['method'] = $method;
135
136
		return $this;
137
	}
138
139
	/**
140
	 * Gets the headers.
141
	 *
142
	 * @return array
143
	 */
144
	public function getHeaders() : array
145
	{
146
		return $this->options['headers'] ?? [ 'Content-Type' => 'application/json' ];
147
	}
148
149
	/**
150
	 * Sets the headers array. Overrides all existing header key and value pairs.
151
	 *
152
	 * @param  array $headers The headers array.
153
	 * @return self
154
	 */
155
	public function setHeaders(array $headers)
156
	{
157
		$this->options['headers'] = $headers;
158
159
		return $this;
160
	}
161
162
	/**
163
	 * Gets a value for a specific header key.
164
	 *
165
	 * @param  string|null $key     The header key.
166
	 * @param  string|null $default A default value or null
167
	 * @return string|$default
0 ignored issues
show
Documentation Bug introduced by
The doc comment string|$default at position 2 could not be parsed: Unknown type name '$default' at position 2 in string|$default.
Loading history...
168
	 */
169
	public function getHeader(string $key = null, string $default = null)
170
	{
171
		return $this->getHeaders()[$key] ?? $default;
172
	}
173
174
	/**
175
	 * Returns whether a header exists or not.
176
	 *
177
	 * @param  string|null $key The header key.
178
	 * @return bool
179
	 */
180
	public function hasHeader(string $key = null) : bool
181
	{
182
		if ($key === null) {
183
			return false;
184
		}
185
186
		$array = $this->getHeaders();
187
		return isset($array[$key]) || array_key_exists($key, $array);
188
	}
189
190
	/**
191
	 * Pushes a header value onto the headers array.
192
	 *
193
	 * @param  string      $key   The header key.
194
	 * @param  string|null $value The header value.
195
	 * @return self
196
	 */
197
	public function pushHeader(string $key, string $value = null)
198
	{
199
		$headers = $this->getHeaders();
200
201
		$headers[$key] = $value;
202
203
		$this->setHeaders($headers);
204
205
		return $this;
206
	}
207
208
	/**
209
	 * Pops a header value from the headers array.
210
	 *
211
	 * @param  string|null $key The header key.
212
	 * @return string|null
213
	 */
214
	public function popHeader(string $key = null)
215
	{
216
		$value = $this->getHeader($key);
217
218
		if ($value !== null) {
219
			unset($this->options['headers'][$key]);
220
		}
221
222
		return $value;
223
	}
224
225
	/**
226
	 * Gets the http protocol version.
227
	 *
228
	 * @return string
229
	 */
230
	public function getProtocolVersion() : string
231
	{
232
		return $this->options['protocolVersion'] ?? '1.1';
233
	}
234
235
	/**
236
	 * Sets the http protocol version.
237
	 *
238
	 * @param  string $version The http protocol version.
239
	 * @return self
240
	 */
241
	public function setProtocolVersion(string $version = '1.1')
242
	{
243
		$this->options['protocolVersion'] = $version;
244
245
		return $this;
246
	}
247
248
	/**
249
	 * Handles a set of records at once.
250
	 *
251
	 * @param  array  $records The records to handle (an array of record arrays)
252
	 * @return bool
253
	 */
254
	public function handleBatch(array $records)
255
	{
256
		foreach ($records as $key => $record) {
257
	        if ($this->isHandling($record)) {
258
	        	$record = $this->processRecord($record);
259
	    		$records['records'][] = $record;
260
	    	}
261
262
			unset($records[$key]);
263
	    }
264
265
	    $records['formatted'] = $this->getFormatter()->formatBatch($records['records'] ?? []);
266
267
	    $this->write($records);
268
269
	    return false === $this->bubble;
270
	}
271
272
	/**
273
     * Gets the default formatter.
274
     *
275
     * @return \Monolog\Formatter\JsonFormatter
276
     */
277
    protected function getDefaultFormatter() : FormatterInterface
278
    {
279
        return new JsonFormatter();
280
    }
281
282
	/**
283
     * Returns the HTTP adapter.
284
     *
285
     * @return \Http\Client\HttpClient
286
     */
287
    protected function getHttpClient(): HttpClient
288
    {
289
        return $this->client;
290
    }
291
292
    /**
293
     * Returns the message factory.
294
     *
295
     * @return \Http\Message\MessageFactory
296
     */
297
    protected function getMessageFactory(): MessageFactory
298
    {
299
        return $this->messageFactory;
300
    }
301
302
    /**
303
     * Writes the record.
304
     *
305
     * @param  array $record
306
     * @return void
307
     */
308
    protected function write(array $record)
309
    {
310
    	$uri = $this->getUri();
311
312
    	if (empty($uri)) {
313
    		return;
314
    	}
315
316
    	$request = $this->getMessageFactory()->createRequest(
317
    		$this->getMethod(),
318
    		$this->getUri(),
319
    		$this->getHeaders(),
320
    		$record['formatted'],
321
    		$this->getProtocolVersion()
322
    	);
323
324
    	try {
325
    		$this->getHttpClient()->sendRequest($request);
326
    	/* istanbul ignore next */
327
    	} catch (\Exception $e) {
328
    		// QUESTION(msschl): How to handle the thrown exceptions???
329
    		/* istanbul ignore next */
330
    		return;
331
    	}
332
    }
333
}