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