Completed
Push — master ( fe191c...d6f97a )
by
unknown
02:07
created

PidFileHandler::setSystemLoggers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Handlers\PidFileHandler
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2020 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Handlers;
22
23
use Doctrine\Common\Collections\Collection;
24
use TechDivision\Import\Configuration\ConfigurationInterface;
25
use TechDivision\Import\Exceptions\LineNotFoundException;
26
use TechDivision\Import\Exceptions\FileNotFoundException;
27
use TechDivision\Import\Exceptions\ImportAlreadyRunningException;
28
use TechDivision\Import\SystemLoggerTrait;
29
30
/**
31
 * A PID file handler implementation.
32
 *
33
 * @author    Tim Wagner <[email protected]>
34
 * @copyright 2020 TechDivision GmbH <[email protected]>
35
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
36
 * @link      https://github.com/techdivision/import
37
 * @link      http://www.techdivision.com
38
 */
39
class PidFileHandler implements PidFileHandlerInterface
40
{
41
42
    use SystemLoggerTrait;
43
44
    /**
45
     * The filehandle for the PID file.
46
     *
47
     * @var resource
48
     */
49
    private $fh;
50
51
    /**
52
     * The PID for the running processes.
53
     *
54
     * @var array
55
     */
56
    private $pid;
57
58
    /**
59
     * The system configuration.
60
     *
61
     * @var \TechDivision\Import\Configuration\ConfigurationInterface
62
     */
63
    private $configuration;
64
65
    /**
66
     * The generic file handler instance.
67
     *
68
     * @var \TechDivision\Import\Handlers\GenericFileHandlerInterface
69
     */
70
    private $genericFileHandler;
71
72
    /**
73
     * Initializes the file handler instance.
74
     *
75
     * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration      The actual configuration instance
76
     * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface $genericFileHandler The actual file handler instance
77
     * @param \Doctrine\Common\Collections\Collection                   $systemLoggers      The array with the system logger instances
78
     */
79
    public function __construct(
80
        ConfigurationInterface $configuration,
81
        GenericFileHandlerInterface $genericFileHandler,
82
        Collection $systemLoggers = null
83
    ) {
84
        $this->configuration = $configuration;
85
        $this->genericFileHandler = $genericFileHandler;
86
        if ($systemLoggers) {
87
            $this->setSystemLoggers($systemLoggers);
88
        }
89
    }
90
91
    /**
92
     * The array with the system loggers.
93
     *
94
     * @param \Doctrine\Common\Collections\Collection $systemLoggers The system logger instances
95
     *
96
     * @return void
97
     */
98
    public function setSystemLoggers(Collection $systemLoggers)
99
    {
100
        $this->systemLoggers = $systemLoggers;
0 ignored issues
show
Documentation Bug introduced by
It seems like $systemLoggers of type object<Doctrine\Common\Collections\Collection> is incompatible with the declared type array of property $systemLoggers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
101
    }
102
103
    /**
104
     * Return's the system configuration.
105
     *
106
     * @return \TechDivision\Import\Configuration\ConfigurationInterface The system configuration
107
     */
108
    protected function getConfiguration()
109
    {
110
        return $this->configuration;
111
    }
112
113
    /**
114
     * Return's the generic file handler instance.
115
     *
116
     * @return \TechDivision\Import\Handlers\GenericFileHandlerInterface The generic file handler instance
117
     */
118
    protected function getGenericFileHandler()
119
    {
120
        return $this->genericFileHandler;
121
    }
122
123
    /**
124
     * Return's the PID filename to use.
125
     *
126
     * @return string The PID filename
127
     */
128
    protected function getPidFilename()
129
    {
130
        return $this->getConfiguration()->getPidFilename();
131
    }
132
133
    /**
134
     * Return's the unique serial for this import process.
135
     *
136
     * @return string The unique serial
137
     */
138
    protected function getSerial()
139
    {
140
        return $this->getConfiguration()->getSerial();
141
    }
142
143
    /**
144
     * Remove's the passed line from the file with the passed name.
145
     *
146
     * @param string   $line The line to be removed
147
     * @param resource $fh   The file handle of the file the line has to be removed
148
     *
149
     * @return void
150
     * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed
151
     */
152
    protected function removeLineFromFile($line, $fh)
153
    {
154
        return $this->getGenericFileHandler()->removeLineFromFile($line, $fh);
155
    }
156
157
    /**
158
     * Persist the UUID of the actual import process to the PID file.
159
     *
160
     * @return void
161
     * @throws \Exception Is thrown, if the PID can not be locked or the PID can not be added
162
     * @throws \TechDivision\Import\Exceptions\ImportAlreadyRunningException Is thrown, if a import process is already running
163
     */
164
    public function lock()
165
    {
166
167
        // query whether or not, the PID has already been set
168
        if ($this->pid === $this->getSerial()) {
169
            return;
170
        }
171
172
        // if not, initialize the PID
173
        $this->pid = $this->getSerial();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getSerial() of type string is incompatible with the declared type array of property $pid.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
174
175
        // open the PID file
176
        $this->fh = fopen($filename = $this->getPidFilename(), 'a+');
177
178
        // try to lock the PID file exclusive
179
        if (!flock($this->fh, LOCK_EX|LOCK_NB)) {
180
            throw new ImportAlreadyRunningException(sprintf('PID file %s is already in use', $filename));
181
        }
182
183
        // append the PID to the PID file
184
        if (fwrite($this->fh, $this->pid . PHP_EOL) === false) {
185
            throw new \Exception(sprintf('Can\'t write PID %s to PID file %s', $this->pid, $filename));
186
        }
187
    }
188
189
    /**
190
     * Remove's the UUID of the actual import process from the PID file.
191
     *
192
     * @return void
193
     * @throws \Exception Is thrown, if the PID can not be removed
194
     */
195
    public function unlock()
196
    {
197
        try {
198
            // remove the PID from the PID file if set
199
            if ($this->pid === $this->getSerial() && is_resource($this->fh)) {
200
                // remove the PID from the file
201
                $this->removeLineFromFile($this->pid, $this->fh);
202
203
                // finally unlock/close the PID file
204
                flock($this->fh, LOCK_UN);
205
                fclose($this->fh);
206
207
                // if the PID file is empty, delete the file
208
                if (filesize($filename = $this->getPidFilename()) === 0) {
209
                    unlink($filename);
210
                }
211
            }
212
        } catch (FileNotFoundException $fnfe) {
213
            $this->getSystemLogger()->notice(sprintf('PID file %s doesn\'t exist', $this->getPidFilename()));
214
        } catch (LineNotFoundException $lnfe) {
215
            $this->getSystemLogger()->notice(sprintf('PID %s is can not be found in PID file %s', $this->pid, $this->getPidFilename()));
216
        } catch (\Exception $e) {
217
            throw new \Exception(sprintf('Can\'t remove PID %s from PID file %s', $this->pid, $this->getPidFilename()), null, $e);
218
        }
219
    }
220
}
221