Completed
Push — develop ( 722f70...af048b )
by Jaap
15:12 queued 05:04
created

Application::configureLogger()   D

Complexity

Conditions 18
Paths 312

Size

Total Lines 68
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
eloc 48
nc 312
nop 3
dl 0
loc 68
ccs 0
cts 12
cp 0
crap 342
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\Shell;
28
use Symfony\Component\Stopwatch\Stopwatch;
29
30
/**
31
 * Application class for phpDocumentor.
32
 *
33
 * Can be used as bootstrap when the run method is not invoked.
34
 */
35
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...
36
{
37
    /** @var string $VERSION represents the version of phpDocumentor as stored in /VERSION */
38
    public static $VERSION;
39
40
    /**
41
     * Initializes all components used by phpDocumentor.
42
     *
43
     * @param ClassLoader $autoloader
44
     * @param array       $values
45
     */
46
    public function __construct($autoloader = null, array $values = array())
47
    {
48
        $this->defineIniSettings();
49
        
50
        self::$VERSION = strpos('@package_version@', '@') === 0
51
            ? trim(file_get_contents(__DIR__ . '/../../VERSION'))
52
            : '@package_version@';
53
54
        parent::__construct('phpDocumentor', self::$VERSION, $values);
55
56
        $this['kernel.timer.start'] = time();
57
        $this['kernel.stopwatch'] = function () {
58
            return new Stopwatch();
59
        };
60
61
        $this['autoloader'] = $autoloader;
62
63
        $this->register(new JmsSerializerServiceProvider());
64
        $this->register(new Configuration\ServiceProvider());
65
66
        $this->addEventDispatcher();
67
        $this->addLogging();
68
69
        $this->register(new ValidatorServiceProvider());
70
        $this->register(new Translator\ServiceProvider());
71
        $this->register(new Descriptor\ServiceProvider());
72
        $this->register(new Parser\ServiceProvider());
73
        $this->register(new Partials\ServiceProvider());
74
        $this->register(new Transformer\ServiceProvider());
75
        $this->register(new Plugin\ServiceProvider());
76
77
        $this->addCommandsForProjectNamespace();
78
79
        if (\Phar::running()) {
80
            $this->addCommandsForPharNamespace();
81
        }
82
    }
83
84
    /**
85
     * Removes all logging handlers and replaces them with handlers that can write to the given logPath and level.
86
     *
87
     * @param Logger  $logger       The logger instance that needs to be configured.
88
     * @param integer $level        The minimum level that will be written to the normal logfile; matches one of the
89
     *                              constants in {@see \Monolog\Logger}.
90
     * @param string  $logPath      The full path where the normal log file needs to be written.
91
     *
92
     * @return void
93
     */
94
    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...
95
    {
96
        /** @var Logger $monolog */
97
        $monolog = $logger;
98
99
        switch ($level) {
100
            case 'emergency':
101
            case 'emerg':
102
                $level = Logger::EMERGENCY;
103
                break;
104
            case 'alert':
105
                $level = Logger::ALERT;
106
                break;
107
            case 'critical':
108
            case 'crit':
109
                $level = Logger::CRITICAL;
110
                break;
111
            case 'error':
112
            case 'err':
113
                $level = Logger::ERROR;
114
                break;
115
            case 'warning':
116
            case 'warn':
117
                $level = Logger::WARNING;
118
                break;
119
            case 'notice':
120
                $level = Logger::NOTICE;
121
                break;
122
            case 'info':
123
                $level = Logger::INFO;
124
                break;
125
            case 'debug':
126
                $level = Logger::DEBUG;
127
                break;
128
        }
129
130
        $this['monolog.level']   = $level;
131
        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...
132
            $logPath = str_replace(
133
                array('{APP_ROOT}', '{DATE}'),
134
                array(realpath(__DIR__.'/../..'), $this['kernel.timer.start']),
135
                $logPath
136
            );
137
            $this['monolog.logfile'] = $logPath;
138
        }
139
140
        // remove all handlers from the stack
141
        try {
142
            while ($monolog->popHandler()) {
143
            }
144
        } catch (\LogicException $e) {
145
            // popHandler throws an exception when you try to pop the empty stack; to us this is not an
146
            // error but an indication that the handler stack is empty.
147
        }
148
149
        if ($level === 'quiet') {
150
            $monolog->pushHandler(new NullHandler());
151
152
            return;
153
        }
154
155
        // set our new handlers
156
        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...
157
            $monolog->pushHandler(new StreamHandler($logPath, $level));
158
        } else {
159
            $monolog->pushHandler(new StreamHandler('php://stdout', $level));
160
        }
161
    }
162
163
    /**
164
     * Run the application and if no command is provided, use project:run.
165
     *
166
     * @param bool $interactive Whether to run in interactive mode.
167
     *
168
     * @return void
169
     */
170
    public function run($interactive = false)
171
    {
172
        /** @var ConsoleApplication $app  */
173
        $app = $this['console'];
174
        $app->setAutoExit(false);
175
176
        if ($interactive) {
177
            $app = new Shell($app);
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Console\Shell has been deprecated with message: since version 2.8, to be removed in 3.0.

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...
178
        }
179
180
        $output = new Console\Output\Output();
181
        $output->setLogger($this['monolog']);
182
183
        $app->run(new ArgvInput(), $output);
0 ignored issues
show
Unused Code introduced by
The call to Shell::run() has too many arguments starting with new \phpDocumentor\Console\Input\ArgvInput().

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...
184
    }
185
186
    /**
187
     * Adjust php.ini settings.
188
     *
189
     * @return void
190
     */
191
    protected function defineIniSettings()
192
    {
193
        $this->setTimezone();
194
        ini_set('memory_limit', -1);
195
196
        // this code cannot be tested because we cannot control the system settings in unit tests
197
        // @codeCoverageIgnoreStart
198
        if (extension_loaded('Zend OPcache') && ini_get('opcache.enable') && ini_get('opcache.enable_cli')) {
199
            if (ini_get('opcache.save_comments')) {
200
                ini_set('opcache.load_comments', 1);
201
            } else {
202
                ini_set('opcache.enable', 0);
203
            }
204
        }
205
206
        if (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.save_comments') == 0) {
207
            throw new \RuntimeException('Please enable zend_optimizerplus.save_comments in php.ini.');
208
        }
209
        // @codeCoverageIgnoreEnd
210
    }
211
212
    /**
213
     * If the timezone is not set anywhere, set it to UTC.
214
     *
215
     * This is done to prevent any warnings being outputted in relation to using
216
     * date/time functions. What is checked is php.ini, and if the PHP version
217
     * is prior to 5.4, the TZ environment variable.
218
     *
219
     * @link http://php.net/manual/en/function.date-default-timezone-get.php for more information how PHP determines the
220
     *     default timezone.
221
     *
222
     * @codeCoverageIgnore this method is very hard, if not impossible, to unit test and not critical.
223
     *
224
     * @return void
225
     */
226
    protected function setTimezone()
227
    {
228
        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...
229
            || (version_compare(phpversion(), '5.4.0', '<') && false === getenv('TZ'))
230
        ) {
231
            date_default_timezone_set('UTC');
232
        }
233
    }
234
235
    /**
236
     * Adds a logging provider to the container of phpDocumentor.
237
     *
238
     * @return void
239
     */
240
    protected function addLogging()
241
    {
242
        $this->register(
243
            new MonologServiceProvider(),
244
            array(
245
                'monolog.name'      => 'phpDocumentor',
246
                'monolog.logfile'   => sys_get_temp_dir() . '/phpdoc.log',
247
                'monolog.debugfile' => sys_get_temp_dir() . '/phpdoc.debug.log',
248
                'monolog.level'     => Logger::INFO,
249
            )
250
        );
251
252
        $app = $this;
253
        /** @var Configuration $configuration */
254
        $configuration = $this['config'];
255
        $this['monolog.configure'] = $this->protect(
256
            function ($log) use ($app, $configuration) {
257
                $paths    = $configuration->getLogging()->getPaths();
258
                $logLevel = $configuration->getLogging()->getLevel();
259
260
                $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...
261
            }
262
        );
263
264
        $this->extend(
265
            'console',
266
            function (ConsoleApplication $console) use ($configuration) {
267
                $console->getHelperSet()->set(new LoggerHelper());
268
                $console->getHelperSet()->set(new ConfigurationHelper($configuration));
269
270
                return $console;
271
            }
272
        );
273
274
        ErrorHandler::register($this['monolog']);
275
    }
276
277
    /**
278
     * Adds the event dispatcher to phpDocumentor's container.
279
     *
280
     * @return void
281
     */
282
    protected function addEventDispatcher()
283
    {
284
        $this['event_dispatcher'] = $this->share(
285
            function () {
286
                return Event\Dispatcher::getInstance();
287
            }
288
        );
289
    }
290
291
    /**
292
     * Adds the command to phpDocumentor that belong to the Project namespace.
293
     *
294
     * @return void
295
     */
296
    protected function addCommandsForProjectNamespace()
297
    {
298
        $this->command(new Command\Project\RunCommand());
299
    }
300
301
    /**
302
     * Adds the command to phpDocumentor that belong to the Phar namespace.
303
     *
304
     * @return void
305
     */
306
    protected function addCommandsForPharNamespace()
307
    {
308
        $this->command(new Command\Phar\UpdateCommand());
309
    }
310
}
311