1
|
|
|
<?php namespace FreedomCore\TrinityCore\Support\DB2Reader; |
2
|
|
|
|
3
|
|
|
use FreedomCore\TrinityCore\Support\Filesystem; |
4
|
|
|
use FreedomCore\TrinityCore\Support\DB2Reader\Processor\WDC1; |
5
|
|
|
use FreedomCore\TrinityCore\Support\DB2Reader\Processor\WDB5; |
6
|
|
|
use FreedomCore\TrinityCore\Support\DB2Reader\Processor\WDB2; |
7
|
|
|
use FreedomCore\TrinityCore\Support\DB2Reader\Processor\BaseFormat; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class FileManager |
11
|
|
|
* @package FreedomCore\TrinityCore\Support\DB2Manager |
12
|
|
|
*/ |
13
|
|
|
class FileManager |
14
|
|
|
{ |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Build Number |
18
|
|
|
* @var null|int |
19
|
|
|
*/ |
20
|
|
|
protected $build = null; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Filesystem Instance |
24
|
|
|
* @var Filesystem|null |
25
|
|
|
*/ |
26
|
|
|
protected $fileSystem = null; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* File handle resource instance |
30
|
|
|
* @var null|resource |
31
|
|
|
*/ |
32
|
|
|
protected $fileHandle = null; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Currently opened file |
36
|
|
|
* @var null|string |
37
|
|
|
*/ |
38
|
|
|
protected $fileName = null; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Processor Instance |
42
|
|
|
* @var WDC1|WDB5|WDB2|BaseFormat|null |
43
|
|
|
*/ |
44
|
|
|
protected $processor = null; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Whether the structure for the file exists or not |
48
|
|
|
* @var bool |
49
|
|
|
*/ |
50
|
|
|
protected $structureExists = false; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* File structure |
54
|
|
|
* @var null|array |
55
|
|
|
*/ |
56
|
|
|
protected $fileStructure = null; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Whether all required items have been loaded |
60
|
|
|
* @var bool |
61
|
|
|
*/ |
62
|
|
|
protected $loaded = false; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Structure for data folder |
66
|
|
|
* @var array |
67
|
|
|
*/ |
68
|
|
|
protected $dataFolderStructure = []; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* List of available DBC languages |
72
|
|
|
* @var array |
73
|
|
|
*/ |
74
|
|
|
protected $availableLanguages = []; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Available DBC/DB2 files |
78
|
|
|
* @var array |
79
|
|
|
*/ |
80
|
|
|
protected $availableFiles = []; |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Data acquired from initial processing |
84
|
|
|
* @var array |
85
|
|
|
*/ |
86
|
|
|
protected $initialProcessing = []; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* FileManager constructor. |
90
|
|
|
* @param Filesystem $fs |
91
|
|
|
* @param int $build |
92
|
|
|
*/ |
93
|
|
|
public function __construct(Filesystem $fs, int $build) |
94
|
|
|
{ |
95
|
|
|
$this->fileSystem = $fs; |
96
|
|
|
$this->build = $build; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* FileManager destructor. |
101
|
|
|
*/ |
102
|
|
|
public function __destruct() |
103
|
|
|
{ |
104
|
|
|
if ($this->fileHandle !== null) { |
105
|
|
|
$this->closeFileHandle(); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Get file system instance |
111
|
|
|
* @return Filesystem |
112
|
|
|
*/ |
113
|
|
|
public function getFileSystem() : Filesystem |
114
|
|
|
{ |
115
|
|
|
return $this->fileSystem; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Set file system instance |
120
|
|
|
* @param Filesystem $fs |
121
|
|
|
*/ |
122
|
|
|
public function setFileSystem(Filesystem $fs) |
123
|
|
|
{ |
124
|
|
|
$this->fileSystem = $fs; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Get file handle instance |
129
|
|
|
* @return null|resource |
130
|
|
|
*/ |
131
|
|
|
public function getFileHandle() |
132
|
|
|
{ |
133
|
|
|
return $this->fileHandle; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Set file name |
138
|
|
|
* @param string $fileName |
139
|
|
|
*/ |
140
|
|
|
public function setFileName(string $fileName) |
141
|
|
|
{ |
142
|
|
|
$this->fileName = $fileName; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Get file name |
147
|
|
|
* @return string |
148
|
|
|
*/ |
149
|
|
|
public function getFileName() : string |
150
|
|
|
{ |
151
|
|
|
return $this->fileName; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Set file handle instance |
156
|
|
|
* @param $fileHandle |
157
|
|
|
*/ |
158
|
|
|
public function setFileHandle($fileHandle) |
159
|
|
|
{ |
160
|
|
|
$this->fileHandle = $fileHandle; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Check if file structure exists |
165
|
|
|
* @return bool |
166
|
|
|
*/ |
167
|
|
|
public function structureExists() : bool |
168
|
|
|
{ |
169
|
|
|
return $this->structureExists; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Get File Structure |
174
|
|
|
* @return null|array |
175
|
|
|
*/ |
176
|
|
|
public function getStructure() : array |
177
|
|
|
{ |
178
|
|
|
return $this->fileStructure; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Load structure of the data folder |
183
|
|
|
* @return array |
184
|
|
|
*/ |
185
|
|
|
public function loadDataDirectory() : array |
186
|
|
|
{ |
187
|
|
|
$this->dataFolderStructure = []; |
188
|
|
|
foreach (Filesystem::foldersInFolder($this->fileSystem->getDataStorage()) as $folder) { |
189
|
|
|
$folderName = str_replace($this->fileSystem->getDataStorage() . DIRECTORY_SEPARATOR, '', $folder); |
190
|
|
|
$folderData = [ |
191
|
|
|
'path' => $folder, |
192
|
|
|
'name' => $folderName, |
193
|
|
|
'type' => $this->getFolderType($folderName) |
194
|
|
|
]; |
195
|
|
|
$this->dataFolderStructure[$folderName] = $folderData; |
196
|
|
|
} |
197
|
|
|
return $this->dataFolderStructure; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Load information about all available DBC languages |
202
|
|
|
* @return array |
203
|
|
|
*/ |
204
|
|
|
public function loadAvailableLanguages() : array |
205
|
|
|
{ |
206
|
|
|
if (array_key_exists('dbc', $this->dataFolderStructure)) { |
207
|
|
|
$this->availableLanguages = []; |
208
|
|
|
foreach (Filesystem::foldersInFolder($this->dataFolderStructure['dbc']['path']) as $folder) { |
209
|
|
|
$folderName = str_replace($this->dataFolderStructure['dbc']['path'] . DIRECTORY_SEPARATOR, '', $folder); |
210
|
|
|
$folderData = [ |
211
|
|
|
'path' => $folder, |
212
|
|
|
'name' => $folderName, |
213
|
|
|
'type' => $this->getFolderType($folderName) |
214
|
|
|
]; |
215
|
|
|
$this->availableLanguages[] = $folderData; |
216
|
|
|
} |
217
|
|
|
return $this->availableLanguages; |
218
|
|
|
} else { |
219
|
|
|
throw new \RuntimeException('Data folder structure is not loaded!'); |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Load all available files |
225
|
|
|
* @param string $selectedLanguage |
226
|
|
|
* @return array |
227
|
|
|
*/ |
228
|
|
|
public function loadAvailableFiles(string $selectedLanguage) : array |
229
|
|
|
{ |
230
|
|
|
$this->availableFiles = []; |
231
|
|
|
$filesFolder = $this->dataFolderStructure['dbc']['path'] . DIRECTORY_SEPARATOR . $selectedLanguage; |
232
|
|
|
foreach (Filesystem::filesInFolder($filesFolder) as $file) { |
233
|
|
|
$fileStructure = [ |
234
|
|
|
'path' => $file, |
235
|
|
|
'extension' => pathinfo($file, PATHINFO_EXTENSION), |
236
|
|
|
'size' => filesize($file), |
237
|
|
|
'name' => str_replace(['_', '-'], '', basename($file, '.' . pathinfo($file, PATHINFO_EXTENSION))) |
238
|
|
|
]; |
239
|
|
|
$this->availableFiles[$fileStructure['name']] = $fileStructure; |
240
|
|
|
} |
241
|
|
|
return $this->availableFiles; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* Load everything required for operation |
246
|
|
|
* @param string $selectedLanguage |
247
|
|
|
*/ |
248
|
|
|
public function loadEverything(string $selectedLanguage) |
249
|
|
|
{ |
250
|
|
|
$this->loadDataDirectory(); |
251
|
|
|
$this->loadAvailableLanguages(); |
252
|
|
|
$this->loadAvailableFiles($selectedLanguage); |
253
|
|
|
$this->loaded = true; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Check if we are ready to perform other tasks |
258
|
|
|
* @return bool |
259
|
|
|
*/ |
260
|
|
|
public function isReady() : bool |
261
|
|
|
{ |
262
|
|
|
return $this->loaded; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Get available languages |
267
|
|
|
* @return array |
268
|
|
|
*/ |
269
|
|
|
public function getLanguages() : array |
270
|
|
|
{ |
271
|
|
|
return $this->availableLanguages; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Get available languages as codes |
276
|
|
|
* @return array |
277
|
|
|
*/ |
278
|
|
|
public function getLanguageCodes() : array |
279
|
|
|
{ |
280
|
|
|
return array_map(function (array $language) { |
281
|
|
|
return $language['name']; |
282
|
|
|
}, $this->getLanguages()); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Get data folder structure |
287
|
|
|
* @return array |
288
|
|
|
*/ |
289
|
|
|
public function getDataFolderStructure() : array |
290
|
|
|
{ |
291
|
|
|
return $this->dataFolderStructure; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Get processor instance |
296
|
|
|
* @return WDB5|WDB2|BaseFormat|null |
297
|
|
|
*/ |
298
|
|
|
public function getProcessor() |
299
|
|
|
{ |
300
|
|
|
return $this->processor; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Check if requested file actually exists |
305
|
|
|
* @param string $fileName |
306
|
|
|
* @return bool |
307
|
|
|
*/ |
308
|
|
|
public function isFileAvailable(string $fileName) : bool |
309
|
|
|
{ |
310
|
|
|
$fileName = $this->formatFileName($fileName); |
311
|
|
|
return (array_key_exists($fileName, $this->availableFiles)); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Open requested file |
316
|
|
|
* @param string $fileName |
317
|
|
|
* @param array $arguments |
318
|
|
|
* @throws \Exception |
319
|
|
|
*/ |
320
|
|
|
public function openFile(string $fileName, array $arguments = []) |
321
|
|
|
{ |
322
|
|
|
$fileData = $this->availableFiles[$fileName]; |
323
|
|
|
$this->fileName = $fileName; |
324
|
|
|
$this->fileHandle = fopen($fileData['path'], 'rb'); |
325
|
|
|
$this->performInitialProcessing(); |
326
|
|
|
$this->loadStructure($fileName); |
327
|
|
|
$this->createProcessor($arguments); |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Format file name string |
332
|
|
|
* @param string $fileName |
333
|
|
|
* @return string |
334
|
|
|
*/ |
335
|
|
|
public function formatFileName(string $fileName) : string |
336
|
|
|
{ |
337
|
|
|
if (strstr($fileName, '.db2') || strstr($fileName, '.dbc')) { |
338
|
|
|
$fileName = str_replace(['.db2', '.dbc'], '', $fileName); |
339
|
|
|
} |
340
|
|
|
return str_replace(['_', '-'], '', $fileName); |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* Seek Bytes In File |
345
|
|
|
* @param integer $bytes |
346
|
|
|
* @param mixed|null extra |
347
|
|
|
* @return int |
348
|
|
|
*/ |
349
|
|
|
public function seekBytes(int $bytes, $extra = null) |
350
|
|
|
{ |
351
|
|
|
if ($extra !== null) { |
352
|
|
|
return fseek($this->fileHandle, $bytes, $extra); |
353
|
|
|
} else { |
354
|
|
|
return fseek($this->fileHandle, $bytes); |
355
|
|
|
} |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* Read Bytes From File |
360
|
|
|
* @param integer $bytes |
361
|
|
|
* @return bool|string |
362
|
|
|
*/ |
363
|
|
|
public function readBytes(int $bytes) |
364
|
|
|
{ |
365
|
|
|
return fread($this->fileHandle, $bytes); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
/** |
369
|
|
|
* Get file format |
370
|
|
|
* @return string |
371
|
|
|
*/ |
372
|
|
|
public function getFormat() : string |
373
|
|
|
{ |
374
|
|
|
return $this->initialProcessing['format']; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Get size of processed file |
379
|
|
|
* @return int |
380
|
|
|
*/ |
381
|
|
|
public function getProcessedSize() : int |
382
|
|
|
{ |
383
|
|
|
return $this->initialProcessing['size']; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* Close file handle |
388
|
|
|
*/ |
389
|
|
|
protected function closeFileHandle() |
390
|
|
|
{ |
391
|
|
|
if ($this->fileHandle !== null) { |
392
|
|
|
fclose($this->fileHandle); |
393
|
|
|
$this->fileHandle = null; |
394
|
|
|
} |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Get folder type |
399
|
|
|
* @param string $folderName |
400
|
|
|
* @return string |
401
|
|
|
*/ |
402
|
|
|
protected function getFolderType(string $folderName) : string |
403
|
|
|
{ |
404
|
|
|
$types = [ |
405
|
|
|
'dbc' => 'DBClientFiles', |
406
|
|
|
'gt' => 'GT', |
407
|
|
|
'enUS' => 'language', |
408
|
|
|
'enGB' => 'language', |
409
|
|
|
'esES' => 'language', |
410
|
|
|
'esMX' => 'language', |
411
|
|
|
'ruRU' => 'language', |
412
|
|
|
]; |
413
|
|
|
return (array_key_exists($folderName, $types)) ? $types[$folderName] : 'unknown'; |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
/** |
417
|
|
|
* Perform initial file processing |
418
|
|
|
*/ |
419
|
|
|
protected function performInitialProcessing() |
420
|
|
|
{ |
421
|
|
|
$status = fstat($this->fileHandle); |
422
|
|
|
$this->initialProcessing = [ |
423
|
|
|
'status' => $status, |
424
|
|
|
'size' => $status['size'], |
425
|
|
|
'format' => $this->readBytes(4) |
426
|
|
|
]; |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* Create processor instance |
431
|
|
|
* @param array $arguments |
432
|
|
|
* @throws \Exception |
433
|
|
|
*/ |
434
|
|
|
protected function createProcessor(array $arguments) |
435
|
|
|
{ |
436
|
|
|
switch ($this->getFormat()) { |
437
|
|
|
case 'WDBC': |
438
|
|
|
case 'WDB2': |
439
|
|
|
$this->processor = new WDB2($this); |
440
|
|
|
break; |
441
|
|
|
case 'WDB5': |
442
|
|
View Code Duplication |
case 'WDB6': |
|
|
|
|
443
|
|
|
if (!is_array($arguments)) { |
444
|
|
|
throw new \Exception("You may only pass an array of string fields when loading a DB2"); |
445
|
|
|
} |
446
|
|
|
$this->processor = new WDB5($this, $arguments); |
447
|
|
|
break; |
448
|
|
View Code Duplication |
case 'WDC1': |
|
|
|
|
449
|
|
|
if (!is_array($arguments)) { |
450
|
|
|
throw new \Exception("You may only pass an array of string fields when loading a DB2"); |
451
|
|
|
} |
452
|
|
|
$this->processor = new WDC1($this, $arguments); |
453
|
|
|
break; |
454
|
|
|
default: |
455
|
|
|
throw new \Exception("Unknown DB2 format: " . $this->getFormat()); |
456
|
|
|
} |
457
|
|
|
if ($this->structureExists()) { |
458
|
|
|
$this->processor->setFieldNames($this->getStructure()); |
|
|
|
|
459
|
|
|
} |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Load file structure |
464
|
|
|
* @param string $fileName |
465
|
|
|
* @return $this |
466
|
|
|
*/ |
467
|
|
|
private function loadStructure(string $fileName) |
468
|
|
|
{ |
469
|
|
|
$structureFile = $this->fileSystem->getStructuresFolder() . $this->build . DIRECTORY_SEPARATOR . $fileName . '.txt'; |
470
|
|
|
$fileFound = Filesystem::fileExists($structureFile); |
471
|
|
|
if ($fileFound) { |
472
|
|
|
$this->structureExists = true; |
473
|
|
|
$this->fileStructure = file($structureFile, FILE_IGNORE_NEW_LINES); |
474
|
|
|
} |
475
|
|
|
return $this; |
476
|
|
|
} |
477
|
|
|
} |
478
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.