Passed
Push — master ( 533d72...51822b )
by Timothy
02:23
created

MonologServiceFactory::createProcessor()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 8
cts 8
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 14
nc 8
nop 2
crap 7
1
<?php
2
/**
3
 * @author Evgeny Shpilevsky <[email protected]>
4
 */
5
6
namespace EnliteMonolog\Service;
7
8
9
use Closure;
10
use Exception;
11
use Interop\Container\ContainerInterface;
12
use Monolog\Handler\HandlerInterface;
13
use Monolog\Logger;
14
use Monolog\Formatter\FormatterInterface;
15
use RuntimeException;
16
use Zend\ServiceManager\FactoryInterface;
17
use Zend\ServiceManager\ServiceLocatorInterface;
18
19
class MonologServiceFactory implements FactoryInterface
0 ignored issues
show
Deprecated Code introduced by
The interface Zend\ServiceManager\FactoryInterface has been deprecated with message: Use Zend\ServiceManager\Factory\FactoryInterface instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
20
{
21
22
    /**
23
     * {@inheritdoc}
24
     * @throws \Interop\Container\Exception\ContainerException
25
     * @throws \RuntimeException
26
     * @throws \Interop\Container\Exception\NotFoundException
27
     */
28
    public function createService(ServiceLocatorInterface $serviceLocator)
29 2
    {
30
        /** @var MonologOptions $options */
31
        $options = $serviceLocator->get('EnliteMonologOptions');
32 2
        return $this->createLogger($serviceLocator, $options);
33 2
    }
34
35
    /**
36
     * {@inheritdoc}
37
     * @throws \Interop\Container\Exception\NotFoundException
38
     * @throws \RuntimeException
39
     */
40
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
41
    {
42
        /** @var MonologOptions $options */
43
        $options = $container->get('EnliteMonologOptions');
44
        return $this->createLogger($container, $options);
45
    }
46
47
    /**
48
     * @param ServiceLocatorInterface|ContainerInterface $container
49
     * @param MonologOptions $options
50
     * @return Logger
51
     * @throws \Interop\Container\Exception\NotFoundException
52
     * @throws \RuntimeException
53
     * @throws \Interop\Container\Exception\ContainerException
54
     */
55
    public function createLogger($container, MonologOptions $options)
56 3
    {
57
        $logger = new Logger($options->getName());
58 3
59
        $handlers = array_reverse($options->getHandlers());
60 3
        foreach ($handlers as $handler) {
61 3
            $logger->pushHandler($this->createHandler($container, $options, $handler));
62 2
        }
63
64
        foreach ($options->getProcessors() as $processor) {
65 3
            $logger->pushProcessor($this->createProcessor($container, $processor));
66 1
        }
67
68
        return $logger;
69 3
    }
70
71
    /**
72
     * @param ServiceLocatorInterface|ContainerInterface $container
73
     * @param MonologOptions $options
74
     * @param string|array $handler
75
     * @throws \RuntimeException
76
     * @return HandlerInterface
77
     * @throws \Interop\Container\Exception\NotFoundException
78
     * @throws \Interop\Container\Exception\ContainerException
79
     *
80
     */
81
    public function createHandler($container, MonologOptions $options, $handler)
82 12
    {
83
        if (is_string($handler) && $container->has($handler)) {
84 12
            return $container->get($handler);
85 2
        }
86
87 11
88 1
        if (!isset($handler['name'])) {
89
            throw new RuntimeException('Cannot create logger handler');
90
        }
91 10
92 1
        $handlerClassName = $handler['name'];
93
94
        if (!class_exists($handlerClassName)) {
95 9
            throw new RuntimeException('Cannot create logger handler (' . $handlerClassName . ')');
96 4
        }
97 1
98
        $arguments = array_key_exists('args', $handler) ? $handler['args'] : array();
99
100 3
        if (!is_array($arguments)) {
101
            throw new RuntimeException('Arguments of handler(' . $handlerClassName . ') must be array');
102 3
        }
103
104
        if (isset($arguments['handler'])) {
105
            foreach ($options->getHandlers() as $key => $option) {
106
                if ($arguments['handler'] == $key) {
107
                    $arguments['handler'] = $this->createHandler($container, $options, $option);
108
                    break;
109
                }
110
            }
111 3
        }
112 3
113
        try {
114 3
            /** @var HandlerInterface $instance */
115
            $instance = $this->createInstanceFromArguments($handlerClassName, $arguments);
116 3
        } catch (\InvalidArgumentException $exception) {
117
            throw new RuntimeException(sprintf(
118
                'Handler(%s) has an invalid argument configuration',
119
                $handlerClassName
120 3
            ), 0, $exception);
121 3
        }
122 1
123 2
        if (isset($handler['formatter'])) {
124 2
            $formatter = $this->createFormatter($container, $handler['formatter']);
125 2
            $instance->setFormatter($formatter);
126
        }
127 2
128
        return $instance;
129 3
    }
130
131
    /**
132
     * @param ServiceLocatorInterface|ContainerInterface $container
133 3
     * @param string|array $formatter
134
     * @return FormatterInterface
135 6
     * @throws \Interop\Container\Exception\NotFoundException
136
     * @throws \Interop\Container\Exception\ContainerException
137
     * @throws RuntimeException
138 6
     */
139
	public function createFormatter($container, $formatter)
140
	{
141 8
		if (is_string($formatter) && $container->has($formatter)) {
142 1
			return $container->get($formatter);
143 1
		}
144
145
        if (!isset($formatter['name'])) {
146 8
            throw new RuntimeException('Cannot create logger formatter');
147
        }
148
149
        $formatterClassName = $formatter['name'];
150
151
        if (!class_exists($formatter['name'])) {
152
            throw new RuntimeException('Cannot create logger formatter (' . $formatterClassName . ')');
153
        }
154
155
        $arguments = array_key_exists('args', $formatter) ? $formatter['args'] : array();
156
157
        if (!is_array($arguments)) {
158 7
            throw new RuntimeException('Arguments of formatter(' . $formatterClassName . ') must be array');
159
        }
160 7
161 1
        try {
162
            /** @var FormatterInterface $instance */
163 6
            $instance = $this->createInstanceFromArguments($formatterClassName, $arguments);
164 1
        } catch (\InvalidArgumentException $exception) {
165
            throw new RuntimeException(sprintf(
166
                'Formatter(%s) has an invalid argument configuration',
167 5
                $formatterClassName
168 1
            ), 0, $exception);
169
        }
170
171 4
        return $instance;
172 2
	}
173 1
174
    /**
175
     * @param ServiceLocatorInterface|ContainerInterface $container
176 1
     * @param $processor
177
     * @return Closure
178 1
     * @throws \Interop\Container\Exception\NotFoundException
179
     * @throws \Interop\Container\Exception\ContainerException
180
     * @throws RuntimeException
181 2
     */
182
    public function createProcessor($container, $processor)
183 2
    {
184
        if ($processor instanceof Closure) {
185
            return $processor;
186
        }
187
188
        if (is_string($processor)) {
189
            try {
190
                $instance = $container->get($processor);
191
            } catch (Exception $ex) {
192
                $instance = null;
193
            }
194
195 5
            if ($instance && is_callable($instance)) {
196
                return $instance;
197 5
            }
198 1
199
            $processor = new $processor();
200
201 4
            if (is_callable($processor)) {
202
                return $processor;
203 4
            }
204 3
        }
205 3
206
        throw new RuntimeException('Unknown processor type, must be a Closure or the FQCN of an invokable class');
207
    }
208 4
209 1
    /**
210
     * Handles the constructor arguments and if they're named, just sort them to fit constructor ordering.
211
     *
212 3
     * @param string $className
213
     * @param array  $arguments
214 3
     *
215 2
     * @return object
216
     * @throws \InvalidArgumentException If given arguments are not valid for provided className constructor.
217
     */
218
    private function createInstanceFromArguments($className, array $arguments)
219 1
    {
220
        $reflection = new \ReflectionClass($className);
221
        $constructor = $reflection->getConstructor();
222
223
        // There is no or at least a non-accessible constructor for provided class name,
224
        // therefore there is no need to handle arguments anyway
225
        if ($constructor === null) {
226
            return $reflection->newInstanceArgs($arguments);
227
        }
228
229
        if (!$constructor->isPublic()) {
230
            throw new \InvalidArgumentException(sprintf(
231
                '%s::__construct is not accessible',
232
                $className
233
            ));
234
        }
235
236
        $requiredArgsCount = $constructor->getNumberOfRequiredParameters();
237
        $argumentCount = count($arguments);
238
239
        if ($requiredArgsCount > $argumentCount) {
240
            throw new \InvalidArgumentException(sprintf(
241
                '%s::__construct() requires at least %d arguments; %d given',
242
                $className,
243
                $requiredArgsCount,
244
                $argumentCount
245
            ));
246
        }
247
248
        // Arguments supposed to be ordered
249
        if (isset($arguments[0])) {
250
            return $reflection->newInstanceArgs($arguments);
251
        }
252
253
        $parameters = array();
254
255
        foreach($constructor->getParameters() as $parameter) {
256
            $parameterName = $parameter->getName();
257
258
            if (array_key_exists($parameterName, $arguments)) {
259
                $parameters[$parameter->getPosition()] = $arguments[$parameterName];
260
                continue;
261
            }
262
263
            if (!$parameter->isOptional()) {
264
                throw new \InvalidArgumentException(sprintf(
265
                    'Missing at least one required parameters `%s`',
266
                    $parameterName
267
                ));
268
            }
269
270
            $parameters[$parameter->getPosition()] = $parameter->getDefaultValue();
271
        }
272
273
        return $reflection->newInstanceArgs($parameters);
274
    }
275
}
276