Completed
Push — master ( 035d24...d62e14 )
by Kanto
15s queued 12s
created

Command::handleShutdown()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Kore : Simple And Minimal Framework
4
 *
5
 */
6
7
namespace Kore;
8
9
use Kore\Log;
10
use Exception;
11
12
/**
13
 * Command class
14
 *
15
 */
16
abstract class Command
17
{
18
    /**
19
     * command namespace
20
     *
21
     * @var string
22
     */
23
    protected $command;
24
    /**
25
     * command arguments
26
     *
27
     * @var array<string>
28
     */
29
    protected $args = array();
30
    /**
31
     * command options
32
     *
33
     * @var array<string>
34
     */
35
    protected $opts = array();
36
    /**
37
     * LockManager
38
     *
39
     * @var \Kore\LockManager
40
     */
41
    protected $lockManager;
42
43
    /**
44
     * Processing Execution
45
     *
46
     * The process is implemented in subclasses.
47
     * @return void
48
     */
49
    abstract protected function exec();
50
    
51
    /**
52
     * Main Processing
53
     *
54
     * @param string $command command namespace
55
     * @param array<string> $args command arguments
56
     * @param array<string> $opts command options
57
     * @return void
58
     */
59
    public function main($command, $args, $opts)
60
    {
61
        $this->command = $command;
62
        $this->args = $args;
63
        $this->opts = $opts;
64
        Log::init($this->commandName(), $this->logLevel());
65
66
        $this->lockManager = new LockManager($this->commandName(), $this->lockTime());
67
        if ($this->lockManager->isLock()) {
68
            Log::warn('Process is running!');
69
            return;
70
        }
71
        $this->lockManager->lock();
72
73
        Log::debug(sprintf('[START]%s', $this->command));
74
        try {
75
            $this->exec();
76
        } catch (Exception $e) {
77
            $this->lockManager->unlock();
78
            $this->handleError($e);
79
        }
80
        Log::debug(sprintf('[END]%s', $this->command));
81
82
        $this->lockManager->unlock();
83
    }
84
85
    /**
86
     * Get the command name
87
     *
88
     * The default is the end of the command namespace.
89
     * If you need to customize, please override it with subclasses.
90
     * @return string command name
91
     */
92
    protected function commandName()
93
    {
94
        $namespace = explode('\\', $this->command);
95
        return $namespace[count($namespace) - 1];
96
    }
97
98
    /**
99
     * Get the log level
100
     *
101
     * The default is Log::LEVEL_DEBUG.
102
     * If you need to customize, please override it with subclasses.
103
     * @return int log level
104
     * @see \Kore\Log
105
     */
106
    protected function logLevel()
107
    {
108
        return Log::LEVEL_DEBUG;
109
    }
110
111
    /**
112
     * Get the lock time
113
     *
114
     * The default is 24 hours.
115
     * If you need to customize, please override it with subclasses.
116
     * @return int lock time
117
     */
118
    protected function lockTime()
119
    {
120
        return 60 * 60 * 24;
121
    }
122
123
    /**
124
     * Handling Errors
125
     *
126
     * If you need to customize the handling of errors, please override it with subclasses.
127
     * @param Exception $e errors
128
     * @return void
129
     * @throws Exception
130
     */
131
    protected function handleError($e)
132
    {
133
        Log::error($e);
134
        throw $e;
135
    }
136
137
    /**
138
     * Handling Shutdown
139
     *
140
     * If you need to customize the handling of shutdown, please override it with subclasses.
141
     * @return void
142
     * @codeCoverageIgnore
143
     */
144
    public function handleShutdown()
145
    {
146
        $error = error_get_last();
147
        if ($error) {
148
            $errorFile = $error['file'];
149
            $errorLine = $error['line'];
150
            $errorMessage = $error['message'];
151
            $errorType = $error['type'];
152
153
            if ($errorType === E_ERROR) {
154
                $this->lockManager->unlock();
155
                $this->handleError(new Exception("$errorMessage $errorFile:$errorLine"));
156
            }
157
        }
158
    }
159
160
    /**
161
     * Get the command arguments
162
     *
163
     * If no key is specified, all command arguments are returned.
164
     * @param string|null $key command argument key
165
     * @param mixed $default default value if there is no value specified in the key
166
     * @return mixed command arguments
167
     */
168
    protected function getArg($key = null, $default = null)
169
    {
170
        return $this->getFromArray($this->args, $key, $default);
171
    }
172
173
    /**
174
     * Get the command options
175
     *
176
     * If no key is specified, all command options are returned.
177
     * @param string|null $key command option key
178
     * @param mixed $default default value if there is no value specified in the key
179
     * @return mixed command options
180
     */
181
    protected function getOpt($key = null, $default = null)
182
    {
183
        return $this->getFromArray($this->opts, $key, $default);
184
    }
185
186
    /**
187
     * Get from array
188
     *
189
     * If no key is specified, array is returned.
190
     * @param array<mixed> $array array
191
     * @param string|null $key path key
192
     * @param mixed $default default value if there is no value specified in the key
193
     * @return mixed value
194
     */
195
    protected function getFromArray($array, $key = null, $default = null)
196
    {
197
        if ($key === null) {
198
            return $array;
199
        }
200
        if (!isset($array[$key])) {
201
            return $default;
202
        }
203
        return $array[$key];
204
    }
205
}
206
207
/**
208
 * Managing Command Lock
209
 *
210
 */
211
class LockManager
212
{
213
    /** @var string process name */
214
    protected $pname;
215
    /** @var int lock time */
216
    protected $lockTime;
217
    /** @var string lock file */
218
    protected $lockFile;
219
220
    /**
221
     * __construct
222
     * @param string $pname process name
223
     * @param int $lockTime lock time
224
     * @return void
225
     */
226
    public function __construct($pname, $lockTime)
227
    {
228
        $this->pname = $pname;
229
        $this->lockTime = $lockTime;
230
    }
231
232
    /**
233
     * Lock
234
     * @return void
235
     */
236
    public function lock()
237
    {
238
        touch($this->lockFile());
239
    }
240
241
    /**
242
     * Unlock
243
     * @return void
244
     */
245
    public function unlock()
246
    {
247
        if (file_exists($this->lockFile())) {
248
            unlink($this->lockFile());
249
        }
250
    }
251
252
    /**
253
     * Locked or not
254
     * @return boolean locked or not
255
     */
256
    public function isLock()
257
    {
258
        return file_exists($this->lockFile()) && filemtime($this->lockFile()) + $this->lockTime >= time();
259
    }
260
261
    /**
262
     * Get lock file
263
     * @return string lock file
264
     */
265
    protected function lockFile()
266
    {
267
        if (!$this->lockFile) {
268
            $this->lockFile = TMP_DIR.'/'.$this->pname.'.lock';
269
        }
270
        return $this->lockFile;
271
    }
272
}
273