Completed
Push — master ( 63506d...7f80a6 )
by Carlos
04:33 queued 01:56
created

Config::getChannel()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 0
cts 16
cp 0
rs 9.0534
c 0
b 0
f 0
cc 4
eloc 11
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
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
        $handlers = $this->channels[$name]['handlers'];
70
        $processors = $this->channels[$name]['processors'];
71
72
        unset($this->channels[$name]['handlers'], $this->channels[$name]['processors']);
73
74
        foreach ($handlers as $handlerId) {
75
            $this->channels[$name]['handlers'][$handlerId] = $this->resolveHandler($handlerId);
76
        }
77
78
        foreach ($processors as $processorId) {
79
            $this->channels[$name]['processors'][$processorId] = $this->resolveProcessor($processorId);
80
        }
81
82
        return $this->channels[$name];
83
    }
84
85
    /**
86
     * @return array
87
     */
88
    public function getFormatters()
89
    {
90
        return $this->formatters;
91
    }
92
93
    /**
94
     * @return array
95
     */
96
    public function getHandlers()
97
    {
98
        return $this->handlers;
99
    }
100
101
    /**
102
     * @return array
103
     */
104
    public function getProcessors()
105
    {
106
        return $this->processors;
107
    }
108
109
    /**
110
     * @return array
111
     */
112
    public function getChannels()
113
    {
114
        return $this->channels;
115
    }
116
117
    /**
118
     * @param string $formatterId
119
     *
120
     * @return \Monolog\Formatter\FormatterInterface
121
     */
122
    protected function resolveFormatter(string $formatterId)
123
    {
124
        if (!$this->formatters[$formatterId] instanceof FormatterInterface) {
125
            $this->formatters[$formatterId] = $this->makeInstance($this->formatters[$formatterId], 'formatter');
126
        }
127
128
        return $this->formatters[$formatterId];
129
    }
130
131
    /**
132
     * @param string $handlerId
133
     *
134
     * @return \Monolog\Handler\HandlerInterface
135
     */
136
    protected function resolveHandler(string $handlerId)
137
    {
138
        if ($this->handlers[$handlerId] instanceof HandlerInterface) {
139
            return $this->handlers[$handlerId];
140
        }
141
142 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...
143
            $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...
144
        }
145
146 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...
147
            $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...
148
        }
149
150
        return $this->handlers[$handlerId] = $this->makeInstance($this->handlers[$handlerId], 'handler');
151
    }
152
153
    /**
154
     * @param string $processorId
155
     *
156
     * @return \Monolog\Handler\HandlerInterface
157
     */
158
    protected function resolveProcessor(string $processorId)
159
    {
160
        if (!is_callable($this->processors[$processorId])) {
161
            $this->processors[$processorId] = $this->makeInstance($this->processors[$processorId], 'processor');
162
        }
163
164
        return $this->processors[$processorId];
165
    }
166
167
    /**
168
     * @param string $option
169
     * @param string $name
170
     *
171
     * @return object
172
     */
173
    protected function makeInstance($option, $name)
174
    {
175
        return (new ReflectionClass($option[$name]))
176
            ->newInstanceArgs($option['args']);
177
    }
178
179
    /**
180
     * @param array $config
181
     */
182
    protected function parse(array $config): void
183
    {
184
        $config = array_merge([
185
            'handlers' => [],
186
            'formatters' => [],
187
            'processors' => [],
188
            'channels' => [],
189
        ], $config);
190
191
        $this->formatters = $this->formatFormatters($config['formatters']);
192
        $this->handlers = $this->formatHandlers($config['handlers']);
193
        $this->processors = $this->formatProcessors($config['processors']);
194
        $this->channels = $this->formatChannels($config['channels']);
195
    }
196
197
    /**
198
     * @param array $formatters
199
     *
200
     * @return array
201
     */
202
    protected function formatFormatters(array $formatters = [])
203
    {
204
        foreach ($formatters as $id => $option) {
205
            $class = $option['formatter'] ?? LineFormatter::class;
206
            unset($option['formatter']);
207
208
            $formatters[$id] = [
209
                'formatter' => $class,
210
                'args' => $option,
211
            ];
212
        }
213
214
        return $formatters;
215
    }
216
217
    /**
218
     * @param array $handlers
219
     *
220
     * @return array
221
     */
222
    protected function formatHandlers(array $handlers = [])
223
    {
224
        foreach ($handlers as $id => $option) {
225
            if (isset($option['formatter']) && !isset($this->formatters[$option['formatter']])) {
226
                throw new InvalidArgumentException(sprintf('Formatter %s not configured.', $option['formatter']));
227
            }
228
229 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...
230
                foreach ($option['processors'] as $processorId) {
231
                    if (!isset($this->processors[$processorId])) {
232
                        throw new InvalidArgumentException(sprintf('Processor %s not configured.', $processorId));
233
                    }
234
                }
235
            }
236
237
            $class = $option['handler'] ?? StreamHandler::class;
238
            unset($option['handler']);
239
240
            $handlers[$id] = [
241
                'handler' => $class,
242
                'args' => $option,
243
            ];
244
        }
245
246
        return $handlers;
247
    }
248
249
    /**
250
     * @param array $processors
251
     *
252
     * @return array
253
     */
254
    protected function formatProcessors(array $processors = [])
255
    {
256
        foreach ($processors as $id => $option) {
257
            if (empty($option['processor'])) {
258
                continue;
259
            }
260
261
            $class = $option['processor'];
262
            unset($option['processor']);
263
264
            $processors[$id] = [
265
                'processor' => $class,
266
                'args' => $option,
267
            ];
268
        }
269
270
        return $processors;
271
    }
272
273
    /**
274
     * @param array $channels
275
     *
276
     * @return array
277
     */
278
    protected function formatChannels(array $channels = [])
279
    {
280
        foreach ($channels as $id => $option) {
281 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...
282
                foreach ($option['processors'] as $processorId) {
283
                    if (!isset($this->processors[$processorId])) {
284
                        throw new InvalidArgumentException(sprintf('Processor %s not configured.', $processorId));
285
                    }
286
                }
287
            }
288
289 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...
290
                foreach ($option['handlers'] as $handlerId) {
291
                    if (!isset($this->handlers[$handlerId])) {
292
                        throw new InvalidArgumentException(sprintf('Handler %s not configured.', $handlerId));
293
                    }
294
                }
295
            }
296
            $channels[$id] = array_merge(['handlers' => [], 'processors' => []], $option);
297
        }
298
299
        return $channels;
300
    }
301
}
302