Passed
Pull Request — master (#23)
by Timothy
03:22
created

MonologServiceFactory::createHandler()   C

Complexity

Conditions 12
Paths 29

Size

Total Lines 49
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 16.7185

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 17
cts 25
cp 0.68
rs 5.1474
c 0
b 0
f 0
cc 12
eloc 27
nc 29
nop 3
crap 16.7185

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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