Completed
Push — develop ( 4b36a1...568a5c )
by Jaap
07:06
created

Application::configureLogger()   D

Complexity

Conditions 18
Paths 312

Size

Total Lines 68
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 19.7038

Importance

Changes 0
Metric Value
cc 18
eloc 48
nc 312
nop 3
dl 0
loc 68
ccs 38
cts 46
cp 0.8261
crap 19.7038
rs 4.2723
c 0
b 0
f 0

How to fix   Long Method    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
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor;
13
14
use Cilex\Application as Cilex;
15
use Cilex\Provider\JmsSerializerServiceProvider;
16
use Cilex\Provider\MonologServiceProvider;
17
use Cilex\Provider\ValidatorServiceProvider;
18
use Composer\Autoload\ClassLoader;
19
use Monolog\ErrorHandler;
20
use Monolog\Handler\NullHandler;
21
use Monolog\Handler\StreamHandler;
22
use Monolog\Logger;
23
use phpDocumentor\Command\Helper\ConfigurationHelper;
24
use phpDocumentor\Command\Helper\LoggerHelper;
25
use phpDocumentor\Console\Input\ArgvInput;
26
use Symfony\Component\Console\Application as ConsoleApplication;
27
use Symfony\Component\Console\Input\InputInterface;
28
use Symfony\Component\Console\Output\OutputInterface;
29
use Symfony\Component\Console\Shell;
30
use Symfony\Component\Stopwatch\Stopwatch;
31
32
/**
33
 * Application class for phpDocumentor.
34
 *
35
 * Can be used as bootstrap when the run method is not invoked.
36
 */
37
class Application extends Cilex
0 ignored issues
show
Complexity introduced by
The class Application has a coupling between objects value of 27. Consider to reduce the number of dependencies under 13.
Loading history...
38
{
39
    /** @var string $VERSION represents the version of phpDocumentor as stored in /VERSION */
40
    public static $VERSION;
41
42
    /**
43
     * Initializes all components used by phpDocumentor.
44
     *
45
     * @param ClassLoader $autoloader
46
     * @param array $values
47
     */
48 14
    public function __construct($autoloader = null, array $values = array())
49
    {
50 14
        $this->defineIniSettings();
51
52 14
        self::$VERSION = strpos('@package_version@', '@') === 0
53 14
            ? trim(file_get_contents(__DIR__ . '/../../VERSION'))
54 14
            : '@package_version@';
55
56 14
        parent::__construct('phpDocumentor', self::$VERSION, $values);
57
58 14
        $this['kernel.timer.start'] = time();
59 14
        $this['kernel.stopwatch'] = function () {
60 14
            return new Stopwatch();
61
        };
62
63 14
        $this['autoloader'] = $autoloader;
64
65 14
        $this->register(new JmsSerializerServiceProvider());
66 14
        $this->register(new Configuration\ServiceProvider());
67
68 14
        $this->addEventDispatcher();
0 ignored issues
show
Unused Code introduced by
The call to the method phpDocumentor\Application::addEventDispatcher() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
69 14
        $this->addLogging();
70
71 14
        $this->register(new Translator\ServiceProvider());
72 14
        $this->register(new Descriptor\ServiceProvider());
73 14
        $this->register(new Partials\ServiceProvider());
74 14
        $this->register(new Parser\ServiceProvider());
75 14
        $this->register(new Transformer\ServiceProvider());
76 14
        $this->register(new Plugin\ServiceProvider());
77
78 14
        $this->addCommandsForProjectNamespace();
79
80 14
        if (\Phar::running()) {
81
            $this->addCommandsForPharNamespace();
82
        }
83 14
    }
84
85
    /**
86
     * Removes all logging handlers and replaces them with handlers that can write to the given logPath and level.
87
     *
88
     * @param Logger  $logger       The logger instance that needs to be configured.
89
     * @param integer $level        The minimum level that will be written to the normal logfile; matches one of the
90
     *                              constants in {@see \Monolog\Logger}.
91
     * @param string  $logPath      The full path where the normal log file needs to be written.
92
     *
93
     * @return void
94
     */
95 11
    public function configureLogger($logger, $level, $logPath = null)
0 ignored issues
show
Complexity introduced by
This operation has 288 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
96
    {
97
        /** @var Logger $monolog */
98 11
        $monolog = $logger;
99
100
        switch ($level) {
101 11
            case 'emergency':
102 11
            case 'emerg':
103 2
                $level = Logger::EMERGENCY;
104 2
                break;
105 11
            case 'alert':
106 1
                $level = Logger::ALERT;
107 1
                break;
108 11
            case 'critical':
109 11
            case 'crit':
110 1
                $level = Logger::CRITICAL;
111 1
                break;
112 11
            case 'error':
113 6
            case 'err':
114 11
                $level = Logger::ERROR;
115 11
                break;
116 5
            case 'warning':
117 4
            case 'warn':
118 2
                $level = Logger::WARNING;
119 2
                break;
120 3
            case 'notice':
121 1
                $level = Logger::NOTICE;
122 1
                break;
123 2
            case 'info':
124 1
                $level = Logger::INFO;
125 1
                break;
126 1
            case 'debug':
127 1
                $level = Logger::DEBUG;
128 1
                break;
129
        }
130
131 11
        $this['monolog.level'] = $level;
132 11
        if ($logPath) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $logPath of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
133
            $logPath = str_replace(
134
                array('{APP_ROOT}', '{DATE}'),
135
                array(realpath(__DIR__ . '/../..'), $this['kernel.timer.start']),
136
                $logPath
137
            );
138
            $this['monolog.logfile'] = $logPath;
139
        }
140
141
        // remove all handlers from the stack
142
        try {
143 11
            while ($monolog->popHandler()) {
144
            }
145 11
        } catch (\LogicException $e) {
146
            // popHandler throws an exception when you try to pop the empty stack; to us this is not an
147
            // error but an indication that the handler stack is empty.
148
        }
149
150 11
        if ($level === 'quiet') {
151
            $monolog->pushHandler(new NullHandler());
152
153
            return;
154
        }
155
156
        // set our new handlers
157 11
        if ($logPath) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $logPath of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
158
            $monolog->pushHandler(new StreamHandler($logPath, $level));
159
        } else {
160 11
            $monolog->pushHandler(new StreamHandler('php://stdout', $level));
161
        }
162 11
    }
163
164
    /**
165
     * @param null|InputInterface $input
166
     * @param null|OutputInterface $output
167
     * @return mixed
168
     */
169
    public function run(InputInterface $input = null, OutputInterface $output = null)
170
    {
171
        /** @var ConsoleApplication $app */
172
        $app = $this['console'];
173
        $app->setAutoExit(false);
174
175
        if ($output === null) {
176
            $output = new Console\Output\Output();
177
            $output->setLogger($this['monolog']);
178
        }
179
180
        return parent::run(new ArgvInput(), $output);
181
    }
182
183
184
    /**
185
     * Adjust php.ini settings.
186
     *
187
     * @return void
188
     */
189 1
    protected function defineIniSettings()
190
    {
191 1
        $this->setTimezone();
192 1
        ini_set('memory_limit', -1);
193
194
        // this code cannot be tested because we cannot control the system settings in unit tests
195
        // @codeCoverageIgnoreStart
196
        if (extension_loaded('Zend OPcache') && ini_get('opcache.enable') && ini_get('opcache.enable_cli')) {
197
            if (ini_get('opcache.save_comments')) {
198
                ini_set('opcache.load_comments', 1);
199
            } else {
200
                ini_set('opcache.enable', 0);
201
            }
202
        }
203
204
        if (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.save_comments') == 0) {
205
            throw new \RuntimeException('Please enable zend_optimizerplus.save_comments in php.ini.');
206
        }
207
        // @codeCoverageIgnoreEnd
208 1
    }
209
210
    /**
211
     * If the timezone is not set anywhere, set it to UTC.
212
     *
213
     * This is done to prevent any warnings being outputted in relation to using
214
     * date/time functions. What is checked is php.ini, and if the PHP version
215
     * is prior to 5.4, the TZ environment variable.
216
     *
217
     * @link http://php.net/manual/en/function.date-default-timezone-get.php for more information how PHP determines the
218
     *     default timezone.
219
     *
220
     * @codeCoverageIgnore this method is very hard, if not impossible, to unit test and not critical.
221
     *
222
     * @return void
223
     */
224
    protected function setTimezone()
225
    {
226
        if (false == ini_get('date.timezone')
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('date.timezone') of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
227
            || (version_compare(phpversion(), '5.4.0', '<') && false === getenv('TZ'))
228
        ) {
229
            date_default_timezone_set('UTC');
230
        }
231
    }
232
233
    /**
234
     * Adds a logging provider to the container of phpDocumentor.
235
     *
236
     * @return void
237
     */
238
    protected function addLogging()
239
    {
240
        $this->register(
241
            new MonologServiceProvider(),
242
            array(
243
                'monolog.name'      => 'phpDocumentor',
244
                'monolog.logfile'   => sys_get_temp_dir() . '/phpdoc.log',
245
                'monolog.debugfile' => sys_get_temp_dir() . '/phpdoc.debug.log',
246
                'monolog.level'     => Logger::INFO,
247
            )
248
        );
249
250
        $app = $this;
251
        /** @var Configuration $configuration */
252
        $configuration = $this['config'];
253
        $this['monolog.configure'] = $this->protect(
254
            function ($log) use ($app, $configuration) {
255
                $paths    = $configuration->getLogging()->getPaths();
256
                $logLevel = $configuration->getLogging()->getLevel();
257
258
                $app->configureLogger($log, $logLevel, $paths['default'], $paths['errors']);
0 ignored issues
show
Unused Code introduced by
The call to Application::configureLogger() has too many arguments starting with $paths['errors'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
259
            }
260
        );
261
262
        $this->extend(
263
            'console',
264
            function (ConsoleApplication $console) use ($configuration) {
265
                $console->getHelperSet()->set(new LoggerHelper());
266
                $console->getHelperSet()->set(new ConfigurationHelper($configuration));
267
268
                return $console;
269
            }
270
        );
271
272
        ErrorHandler::register($this['monolog']);
273
    }
274
275
    /**
276
     * Adds the event dispatcher to phpDocumentor's container.
277
     *
278
     * @return void
279
     */
280
    protected function addEventDispatcher()
281
    {
282 1
        $this['event_dispatcher'] = function () {
283 1
            return Event\Dispatcher::getInstance();
284
        };
285 1
    }
286
287
    /**
288
     * Adds the command to phpDocumentor that belong to the Project namespace.
289
     *
290
     * @return void
291
     */
292 1
    protected function addCommandsForProjectNamespace()
293
    {
294 1
        $this->command(new Command\Project\RunCommand());
295 1
    }
296
297
    /**
298
     * Adds the command to phpDocumentor that belong to the Phar namespace.
299
     *
300
     * @return void
301
     */
302
    protected function addCommandsForPharNamespace()
303
    {
304
        $this->command(new Command\Phar\UpdateCommand());
305
    }
306
}
307