Passed
Push — master ( ce891b...aad205 )
by Timothy
42s
created

createInstanceFromArguments()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 57
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 8

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 57
ccs 26
cts 26
cp 1
rs 7.2648
cc 8
eloc 31
nc 8
nop 2
crap 8

How to fix   Long Method   

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