Completed
Push — master ( afc334...739936 )
by Carlos
02:35
created

Config::getChannel()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 17
cp 0
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 12
nc 5
nop 1
crap 20
1
<?php
2
3
/*
4
 * This file is part of the overtrue/cuttle.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Overtrue\Cuttle;
13
14
use InvalidArgumentException;
15
use Monolog\Formatter\FormatterInterface;
16
use Monolog\Formatter\LineFormatter;
17
use Monolog\Handler\HandlerInterface;
18
use Monolog\Handler\StreamHandler;
19
use ReflectionClass;
20
21
/**
22
 * Class Config.
23
 *
24
 * @author overtrue <[email protected]>
25
 */
26
class Config
27
{
28
    /**
29
     * @var array
30
     */
31
    protected $formatters = [];
32
33
    /**
34
     * @var array
35
     */
36
    protected $handlers = [];
37
38
    /**
39
     * @var array
40
     */
41
    protected $processors = [];
42
43
    /**
44
     * @var array
45
     */
46
    protected $channels = [];
47
48
    /**
49
     * Config constructor.
50
     *
51
     * @param array $config
52
     */
53
    public function __construct(array $config)
54
    {
55
        $this->parse($config);
56
    }
57
58
    /**
59
     * @param string $name
60
     *
61
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
62
     */
63
    public function getChannel(string $name)
64
    {
65
        if (empty($this->channels[$name])) {
66
            throw new InvalidArgumentException("No channel named '{$name}' found.");
67
        }
68
69
        $channel = $this->channels[$name];
70
        $channel['handlers'] = array_flip($channel['handlers']);
71
        $channel['processors'] = array_flip($channel['processors']);
72
73
        foreach (array_keys($channel['handlers']) as $handlerId) {
74
            $channel['handlers'][$handlerId] = $this->resolveHandler($handlerId);
75
        }
76
77
        foreach (array_keys($channel['processors']) as $processorId) {
78
            $channel['processors'][] = $this->resolveProcessor($processorId);
79
        }
80
81
        $this->channels[$name] = $channel;
82
83
        return $channel;
84
    }
85
86
    /**
87
     * @return array
88
     */
89
    public function getFormatters()
90
    {
91
        return $this->formatters;
92
    }
93
94
    /**
95
     * @return array
96
     */
97
    public function getHandlers()
98
    {
99
        return $this->handlers;
100
    }
101
102
    /**
103
     * @return array
104
     */
105
    public function getProcessors()
106
    {
107
        return $this->processors;
108
    }
109
110
    /**
111
     * @return array
112
     */
113
    public function getChannels()
114
    {
115
        return $this->channels;
116
    }
117
118
    /**
119
     * @param string $formatterId
120
     *
121
     * @return \Monolog\Formatter\FormatterInterface
122
     */
123
    protected function resolveFormatter(string $formatterId)
124
    {
125
        if (!$this->formatters[$formatterId] instanceof FormatterInterface) {
126
            $this->formatters[$formatterId] = $this->makeInstance($this->formatters[$formatterId], 'formatter');
127
        }
128
129
        return $this->formatters[$formatterId];
130
    }
131
132
    /**
133
     * @param string $handlerId
134
     *
135
     * @return \Monolog\Handler\HandlerInterface
136
     */
137
    protected function resolveHandler(string $handlerId)
138
    {
139
        if ($this->handlers[$handlerId] instanceof HandlerInterface) {
140
            return $this->handlers[$handlerId];
141
        }
142
143 View Code Duplication
        if (!empty($this->handlers[$handlerId]['formatter'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
144
            $this->handlers[$handlerId]['formatter'] = $this->resolveFormatter($this->handlers[$handlerId]['formatter']);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
145
        }
146
147 View Code Duplication
        if (!empty($this->handlers[$handlerId]['processors'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
            $this->handlers[$handlerId]['processors'] = $this->resolveFormatter($this->handlers[$handlerId]['processors']);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
149
        }
150
151
        return $this->handlers[$handlerId] = $this->makeInstance($this->handlers[$handlerId], 'handler');
152
    }
153
154
    /**
155
     * @param string $processorId
156
     *
157
     * @return \Monolog\Handler\HandlerInterface
158
     */
159
    protected function resolveProcessor(string $processorId)
160
    {
161
        if (!is_callable($this->processors[$processorId])) {
162
            $this->processors[$processorId] = $this->makeInstance($this->processors[$processorId], 'processor');
163
        }
164
165
        return $this->processors[$processorId];
166
    }
167
168
    /**
169
     * @param string $option
170
     * @param string $name
171
     *
172
     * @return object
173
     */
174
    protected function makeInstance($option, $name)
175
    {
176
        return (new ReflectionClass($option[$name]))
177
            ->newInstanceArgs($option['args']);
178
    }
179
180
    /**
181
     * @param array $config
182
     */
183
    protected function parse(array $config): void
184
    {
185
        $config = array_merge([
186
            'handlers' => [],
187
            'formatters' => [],
188
            'processors' => [],
189
            'channels' => [],
190
        ], $config);
191
192
        $this->formatters = $this->formatFormatters($config['formatters']);
193
        $this->handlers = $this->formatHandlers($config['handlers']);
194
        $this->processors = $this->formatProcessors($config['processors']);
195
        $this->channels = $this->formatChannels($config['channels']);
196
    }
197
198
    /**
199
     * @param array $formatters
200
     *
201
     * @return array
202
     */
203
    protected function formatFormatters(array $formatters = [])
204
    {
205
        foreach ($formatters as $id => $option) {
206
            $class = $option['formatter'] ?? LineFormatter::class;
207
            unset($option['formatter']);
208
209
            $formatters[$id] = [
210
                'formatter' => $class,
211
                'args' => $option,
212
            ];
213
        }
214
215
        return $formatters;
216
    }
217
218
    /**
219
     * @param array $handlers
220
     *
221
     * @return array
222
     */
223
    protected function formatHandlers(array $handlers = [])
224
    {
225
        foreach ($handlers as $id => $option) {
226
            if (isset($option['formatter']) && !isset($this->formatters[$option['formatter']])) {
227
                throw new InvalidArgumentException(sprintf('Formatter %s not configured.', $option['formatter']));
228
            }
229
230 View Code Duplication
            if (isset($option['processors'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
                foreach ($option['processors'] as $processorId) {
232
                    if (!isset($this->processors[$processorId])) {
233
                        throw new InvalidArgumentException(sprintf('Processor %s not configured.', $processorId));
234
                    }
235
                }
236
            }
237
238
            $class = $option['handler'] ?? StreamHandler::class;
239
            unset($option['handler']);
240
241
            $handlers[$id] = [
242
                'handler' => $class,
243
                'args' => $option,
244
            ];
245
        }
246
247
        return $handlers;
248
    }
249
250
    /**
251
     * @param array $processors
252
     *
253
     * @return array
254
     */
255
    protected function formatProcessors(array $processors = [])
256
    {
257
        foreach ($processors as $id => $option) {
258
            if (empty($option['processor'])) {
259
                continue;
260
            }
261
262
            $class = $option['processor'];
263
            unset($option['processor']);
264
265
            $processors[$id] = [
266
                'processor' => $class,
267
                'args' => $option,
268
            ];
269
        }
270
271
        return $processors;
272
    }
273
274
    /**
275
     * @param array $channels
276
     *
277
     * @return array
278
     */
279
    protected function formatChannels(array $channels = [])
280
    {
281
        foreach ($channels as $id => $option) {
282 View Code Duplication
            if (isset($option['processors'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
                foreach ($option['processors'] as $processorId) {
284
                    if (!isset($this->processors[$processorId])) {
285
                        throw new InvalidArgumentException(sprintf('Processor %s not configured.', $processorId));
286
                    }
287
                }
288
            }
289
290 View Code Duplication
            if (isset($option['handlers'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
                foreach ($option['handlers'] as $handlerId) {
292
                    if (!isset($this->handlers[$handlerId])) {
293
                        throw new InvalidArgumentException(sprintf('Handler %s not configured.', $handlerId));
294
                    }
295
                }
296
            }
297
            $channels[$id] = array_merge(['handlers' => [], 'processors' => []], $option);
298
        }
299
300
        return $channels;
301
    }
302
}
303