Completed
Push — master ( 1291db...47933f )
by Tim
02:52 queued 12s
created

OkFileHandler   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 35.09%

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 5
dl 0
loc 263
ccs 20
cts 57
cp 0.3509
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getGenericFileHandler() 0 4 1
A getFilesystemAdapter() 0 4 1
A getLoader() 0 4 1
A removeLineFromFilename() 0 4 1
A stripSuffix() 0 4 1
A size() 0 4 1
A delete() 0 10 2
A isEqualFilename() 0 12 2
A setLoader() 0 4 1
A setFilesystemAdapter() 0 4 1
A isOkFile() 0 4 1
A createOkFiles() 0 22 3
B cleanUpOkFile() 0 40 7
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 TechDivision\Import\Loaders\FilteredLoaderInterface;
24
use TechDivision\Import\Exceptions\LineNotFoundException;
25
use TechDivision\Import\Adapter\FilesystemAdapterInterface;
26
use TechDivision\Import\Exceptions\OkFileNotEmptyException;
27
28
/**
29
 * An .OK file handler implementation.
30
 *
31
 * @author    Tim Wagner <[email protected]>
32
 * @copyright 2020 TechDivision GmbH <[email protected]>
33
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
 * @link      https://github.com/techdivision/import
35
 * @link      http://www.techdivision.com
36
 */
37
class OkFileHandler implements OkFileHandlerInterface
38
{
39
40
    /**
41
     * The loader instance used to load the proposed .OK filenames and it's content.
42
     *
43
     * @var \TechDivision\Import\Loaders\FilteredLoaderInterface
44
     */
45
    private $loader;
46
47
    /**
48
     * The filesystem adapter instance.
49
     *
50
     * @var \TechDivision\Import\Adapter\FilesystemAdapterInterface
51
     */
52
    private $filesystemAdapter;
53
54
    /**
55
     * The generic file handler instance.
56
     *
57
     * @var \TechDivision\Import\Handlers\GenericFileHandlerInterface
58
     */
59
    private $genericFileHandler;
60
61
    /**
62
     * Initializes the file handler instance.
63
     *
64
     * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface|null $genericFileHandler The generic file handler instance
65
     */
66 2
    public function __construct(GenericFileHandlerInterface $genericFileHandler = null)
67
    {
68 2
        $this->genericFileHandler = $genericFileHandler ?? new GenericFileHandler();
69 2
    }
70
71
    /**
72
     * Return's the generic file handler instance.
73
     *
74
     * @return \TechDivision\Import\Handlers\GenericFileHandlerInterface The generic file handler instance
75
     */
76
    protected function getGenericFileHandler()
77
    {
78
        return $this->genericFileHandler;
79
    }
80
81
    /**
82
     * Return's the filesystem adapter instance.
83
     *
84
     * @return \TechDivision\Import\Adapter\FilesystemAdapterInterface The filesystem adapter instance
85
     */
86 2
    protected function getFilesystemAdapter()
87
    {
88 2
        return $this->filesystemAdapter;
89
    }
90
91
    /**
92
     * Return's the loader instance used to load the proposed .OK filenames and it's content.
93
     *
94
     * @return \TechDivision\Import\Loaders\FilteredLoaderInterface The loader instance
95
     */
96 2
    protected function getLoader() : FilteredLoaderInterface
97
    {
98 2
        return $this->loader;
99
    }
100
101
    /**
102
     * Remove's the passed line from the file with the passed name.
103
     *
104
     * @param string $line     The line to be removed
105
     * @param string $filename The name of the file the line has to be removed from
106
     *
107
     * @return void
108
     * @throws \TechDivision\Import\Exceptions\LineNotFoundException Is thrown, if the requested line can not be found in the file
109
     * @throws \Exception Is thrown, if the file can not be written, after the line has been removed
110
     * @see \TechDivision\Import\Handlers\GenericFileHandlerInterface::removeLineFromFile()
111
     */
112
    protected function removeLineFromFilename(string $line, string $filename) : void
113
    {
114
        $this->getGenericFileHandler()->removeLineFromFilename($line, $filename);
115
    }
116
117
    /**
118
     * Strips the passed suffix, including the (.), from the filename and returns it.
119
     *
120
     * @param string $filename The filename to return the suffix from
121
     *
122
     * @return string The filname without the suffix
123
     */
124
    protected function stripSuffix(string $filename) : string
125
    {
126
        return basename($filename, sprintf('.%s', pathinfo($filename, PATHINFO_EXTENSION)));
127
    }
128
129
    /**
130
     * Return's the size of the file with the passed name.
131
     *
132
     * @param string $okFilename The name of the file to return the size for
133
     *
134
     * @return int The size of the file in bytes
135
     * @throws \Exception Is thrown, if the size can not be calculated
136
     */
137
    protected function size($okFilename)
138
    {
139
        return $this->getFilesystemAdapter()->size($okFilename);
140
    }
141
142
    /**
143
     * Deletes the .OK file with the passed name, but only if it is empty.
144
     *
145
     * @param string $okFilename The name of the .OK file to delete
146
     *
147
     * @return void
148
     * @throws \TechDivision\Import\Exceptions\OkFileNotEmptyException Is thrown, if the .OK file is NOT empty
149
     */
150
    protected function delete(string $okFilename)
151
    {
152
153
        // if the .OK file is empty, delete it
154
        if (filesize($okFilename) === 0) {
155
            $this->getFilesystemAdapter()->delete($okFilename);
156
        } else {
157
            throw new OkFileNotEmptyException(sprintf('Can\'t delete file "%s" because it\'s not empty', $okFilename));
158
        }
159
    }
160
161
    /**
162
     * Query whether or not the basename, without suffix, of the passed filenames are equal.
163
     *
164
     * @param string $filename   The filename to compare
165
     * @param string $okFilename The name of the .OK file to compare
166
     *
167
     * @return boolean TRUE if the passed files basename are equal, else FALSE
168
     */
169
    protected function isEqualFilename(string $filename, string $okFilename) : bool
170
    {
171
172
        // strip the suffix of the files and compare them
173
        if (strcmp($this->stripSuffix($filename), $this->stripSuffix($okFilename)) === 0) {
174
            // return TRUE, if the filenames ARE equal
175
            return true;
176
        }
177
178
        // return FALSE, if the filenames are NOT equal
179
        return false;
180
    }
181
182
    /**
183
     * Set's the loader instance used to load the proposed .OK filenames and it's content.
184
     *
185
     * @param \TechDivision\Import\Loaders\FilteredLoaderInterface $loader The loader instance
186
     *
187
     * @return void
188
     */
189 2
    public function setLoader(FilteredLoaderInterface $loader) : void
190
    {
191 2
        $this->loader = $loader;
192 2
    }
193
194
    /**
195
     * Set's the filesystem adapter instance.
196
     *
197
     * @param \TechDivision\Import\Adapter\FilesystemAdapterInterface $filesystemAdapter The filesystem adapter instance
198
     *
199
     * @return void
200
     */
201 2
    public function setFilesystemAdapter(FilesystemAdapterInterface $filesystemAdapter) : void
202
    {
203 2
        $this->filesystemAdapter = $filesystemAdapter;
204 2
    }
205
206
    /**
207
     * Query's whether or not the passed file is available and can be used as .OK file.
208
     *
209
     * @param string $okFilename The .OK file that has to be queried
210
     *
211
     * @return bool TRUE if the passed filename is an .OK file, else FALSE
212
     */
213
    public function isOkFile(string $okFilename) : bool
214
    {
215
        return $this->getFilesystemAdapter()->isFile($okFilename);
216
    }
217
218
    /**
219
     * Query whether or not, the passed CSV filename is in the passed OK file. If the filename was found,
220
     * the OK file will be cleaned-up.
221
     *
222
     * @param string $filename   The filename to be cleaned-up
223
     * @param string $okFilename The filename of the .OK filename
224
     *
225
     * @return bool TRUE if the passed filename matches the also passed .OK file
226
     * @throws \Exception Is thrown, if the passed filename is NOT in the OK file or the OK can not be cleaned-up
227
     */
228
    public function cleanUpOkFile(string $filename, string $okFilename) : bool
229
    {
230
231
        try {
232
            // if the OK filename matches the CSV filename AND the OK file is empty
233
            if ($this->isEqualFilename($filename, $okFilename) && $this->size($okFilename) === 0) {
234
                // finally delete the .OK file
235
                $this->delete($okFilename);
236
                // and return TRUE
237
                return true;
238
            } else {
239
                // if the OK filename matches the CSV filename AND the OK file is empty
240
                foreach ($this->getFilesystemAdapter()->read($okFilename) as $line) {
241
                    if (strcmp(basename($filename), $trimmedLine = trim($line, PHP_EOL)) === 0) {
242
                        // else, remove the CSV filename from the OK file
243
                        $this->removeLineFromFilename($trimmedLine, $okFilename);
244
                        // finally delete the .OK file, if empty
245
                        if ($this->size($okFilename) === 0) {
246
                            $this->delete($okFilename);
247
                        }
248
                        // return TRUE, when the line has successfully been removed
249
                        return true;
250
                    }
251
                }
252
            }
253
        } catch (LineNotFoundException $lne) {
254
            // wrap and re-throw the exception
255
            throw new \Exception(
256
                sprintf(
257
                    'Can\'t remove filename "%s" from .OK file: "%s"',
258
                    $filename,
259
                    $okFilename
260
                ),
261
                null,
262
                $lne
263
            );
264
        }
265
        // otherwise, return FALSE
266
        return false;
267
    }
268
269
    /**
270
     * Create's the .OK files for all .CSV files that matches the passed pattern.
271
     *
272
     * @param string $pattern The pattern that matches the .CSV files we want to create the .OK files for
273
     *
274
     * @return int Return's the number of created .OK files
275
     * @throws \Exception Is thrown, one of the proposed .OK files can not be created
276
     */
277 2
    public function createOkFiles(string $pattern) : int
278
    {
279
280
        // initialize the counter for the processed .OK files
281 2
        $counter = 0;
282
283
        // load the array with the proposed .OK filenames
284 2
        $proposedOkFilenames = $this->getLoader()->load($pattern);
0 ignored issues
show
Unused Code introduced by
The call to FilteredLoaderInterface::load() has too many arguments starting with $pattern.

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...
285
286
        // create the proposed .OK files
287 2
        foreach ($proposedOkFilenames as $okFilename => $csvFilenames) {
288
            // write the proposed .OK file
289 2
            if ($this->getFilesystemAdapter()->write($okFilename, implode(PHP_EOL, $csvFilenames)) === false) {
290
                throw new \Exception(sprintf('Can\' create .OK file "%s"', $okFilename));
291
            }
292
            // raise the counter
293 2
            $counter++;
294
        }
295
296
        // return the number of created .OK files
297 2
        return $counter;
298
    }
299
}
300