AbstractCronCommand   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
eloc 65
c 3
b 1
f 1
dl 0
loc 189
rs 10
wmc 22

8 Methods

Rating   Name   Duplication   Size   Complexity  
A run() 0 23 4
A getMutexFile() 0 13 3
A doParentRun() 0 3 1
A setLogger() 0 22 4
A cleanup() 0 5 1
A exceptionHandler() 0 4 1
A errorHandler() 0 16 6
A endOfScript() 0 4 2
1
<?php
2
/**
3
 * @author Gerard van Helden <[email protected]>
4
 * @copyright Zicht Online <http://zicht.nl>
5
 */
6
namespace Zicht\Bundle\FrameworkExtraBundle\Command;
7
8
use Exception;
9
10
use Monolog\Logger;
0 ignored issues
show
Bug introduced by
The type Monolog\Logger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Monolog\Handler\StreamHandler;
0 ignored issues
show
Bug introduced by
The type Monolog\Handler\StreamHandler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Monolog\Processor\MemoryUsageProcessor;
0 ignored issues
show
Bug introduced by
The type Monolog\Processor\MemoryUsageProcessor was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Monolog\Processor\MemoryPeakUsageProcessor;
0 ignored issues
show
Bug introduced by
The type Monolog\Processor\MemoryPeakUsageProcessor was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
15
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Zicht\Util\Mutex;
19
use Zicht\Util\Str;
20
21
/**
22
 * Simple utility class for console applications. Uses Monolog for logging and error/exception reporting.
23
 * @deprecated Locking should be done by exonet and the logging can be done simpler using the GetStdLoggerTrait
24
 */
25
abstract class AbstractCronCommand extends ContainerAwareCommand
26
{
27
    /**
28
     * If the application was neatly cleaned up, this is set to true, and the endOfScript() method will not issue
29
     * an error
30
     *
31
     * @var bool
32
     */
33
    private $isFinishedCleanly = false;
34
35
    /**
36
     * Logger instance
37
     *
38
     * @var \Monolog\Logger
39
     */
40
    protected $logger;
41
42
    /**
43
     * Set this to a filename if a mutex should be used.
44
     *
45
     * @var bool
46
     */
47
    protected $mutex = false;
48
49
    /**
50
     * Initialize the logger and attach it to error/exception handling and the clean shutdown function.
51
     *
52
     * @param \Monolog\Logger $logger
53
     * @param int $verbosity
54
     * @param bool $paranoid Whether or not non-clean shutdown should be logged.
55
     * @return void
56
     */
57
    public function setLogger(Logger $logger, $verbosity = 0, $paranoid = true)
58
    {
59
        $this->logger = $logger;
60
        if ($paranoid) {
61
            register_shutdown_function(array($this, 'endOfScript'));
62
        }
63
        set_error_handler(array($this, 'errorHandler'));
64
        set_exception_handler(array($this, 'exceptionHandler'));
65
66
        if ($verbosity == OutputInterface::VERBOSITY_VERBOSE) {
67
            $logger->pushHandler(
68
                new StreamHandler(fopen('php://stdout', 'w'), Logger::DEBUG, false)
69
            );
70
            $logger->pushProcessor(new MemoryUsageProcessor);
71
            $logger->pushProcessor(new MemoryPeakUsageProcessor);
72
        }
73
        if ($verbosity == OutputInterface::VERBOSITY_NORMAL) {
74
            $logger->pushHandler(
75
                new StreamHandler(fopen('php://stdout', 'w'), Logger::INFO, false)
76
            );
77
        }
78
        $logger->pushHandler(new StreamHandler(fopen('php://stderr', 'w'), Logger::WARNING));
79
    }
80
81
82
    /**
83
     * Exception handler; will log the exception and exit the script.
84
     *
85
     * @param \Exception $exception
86
     * @return void
87
     */
88
    public function exceptionHandler(Exception $exception)
89
    {
90
        $this->logger->addError($exception->getMessage(), array($exception->getFile(), $exception->getLine()));
91
        exit(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
92
    }
93
94
95
    /**
96
     * Error handler; will log the error and exit the script.
97
     *
98
     * @param int $errno
99
     * @param string $errstr
100
     * @param string $file
101
     * @param int $line
102
     * @return void
103
     */
104
    public function errorHandler($errno, $errstr, $file, $line)
105
    {
106
        switch ($errno) {
107
            case E_USER_ERROR:
108
            case E_ERROR:
109
            case E_RECOVERABLE_ERROR:
110
                $this->logger->addError($errstr, array($file, $line));
111
                exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
112
                break;
113
            case E_WARNING:
114
            case E_USER_WARNING:
115
                $this->logger->addWarning($errstr, array($file, $line));
116
                break;
117
            default:
118
                $this->logger->addInfo($errstr, array($file, $line));
119
                break;
120
        }
121
    }
122
123
124
    /**
125
     * Triggered on shutddown of the script.
126
     *
127
     * @return void
128
     */
129
    public function endOfScript()
130
    {
131
        if (!$this->isFinishedCleanly) {
132
            $this->logger->addCritical('Unexpected end of script!');
133
        }
134
    }
135
136
137
    /**
138
     * Tells the app that the end was reached without trouble.
139
     *
140
     * @return void
141
     */
142
    public function cleanup()
143
    {
144
        $this->isFinishedCleanly = true;
145
        restore_error_handler();
146
        restore_exception_handler();
147
    }
148
149
150
    /**
151
     * Run the command.
152
     *
153
     * @param \Symfony\Component\Console\Input\InputInterface $input
154
     * @param \Symfony\Component\Console\Output\OutputInterface $output
155
     * @return int
156
     */
157
    public function run(InputInterface $input, OutputInterface $output)
158
    {
159
        $this->isFinishedCleanly = false;
160
        if ($mutexFile = $this->getMutexFile()) {
161
            $self = $this;
162
            $result = null;
163
164
            $mutex = new Mutex($mutexFile, false);
0 ignored issues
show
Bug introduced by
It seems like $mutexFile can also be of type true; however, parameter $file of Zicht\Util\Mutex::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
            $mutex = new Mutex(/** @scrutinizer ignore-type */ $mutexFile, false);
Loading history...
165
            $isLockAcquired = false;
166
            $mutex->run(
167
                function () use ($self, $input, $output, &$result) {
0 ignored issues
show
Unused Code introduced by
The import $result is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
168
                    return $self->doParentRun($input, $output);
169
                },
170
                $isLockAcquired
171
            );
172
            if (!$isLockAcquired && $this->logger) {
173
                $this->logger->addWarning("Mutex failed in " . get_class($this) . ", job was not run");
174
            }
175
        } else {
176
            $result = $this->doParentRun($input, $output);
177
        }
178
        $this->cleanup();
179
        return $result;
180
    }
181
182
183
    /**
184
     * Wrapped in a separate method so we can call it from the mutex closure.
185
     *
186
     * @param InputInterface $input
187
     * @param OutputInterface $output
188
     * @return int
189
     */
190
    final public function doParentRun(InputInterface $input, OutputInterface $output)
191
    {
192
        return parent::run($input, $output);
193
    }
194
195
196
    /**
197
     * Returns a path to the file which can be used as a mutex.
198
     *
199
     * @return bool|string
200
     */
201
    protected function getMutexFile()
202
    {
203
        $file = false;
204
205
        if (true === $this->mutex) {
206
            $file = $this->getContainer()->getParameter('kernel.cache_dir')
207
                . '/'
208
                . Str::dash(lcfirst(Str::classname(get_class($this))))
209
                . '.lock';
210
        } elseif ($this->mutex) {
211
            $file = $this->mutex;
212
        }
213
        return $file;
214
    }
215
}
216