FileManager::getLanguages()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

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
eloc 2
nc 1
nop 0
crap 2
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':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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());
0 ignored issues
show
Bug introduced by
It seems like $this->getStructure() targeting FreedomCore\TrinityCore\...Manager::getStructure() can also be of type null; however, FreedomCore\TrinityCore\...Format::setFieldNames() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
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