Completed
Pull Request — master (#8)
by Tim
06:21
created

AbstractSubject::getFilename()   A

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
rs 10
c 0
b 0
f 0
ccs 0
cts 4
cp 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Subjects\AbstractSubject
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 2016 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\Subjects;
22
23
use Psr\Log\LoggerInterface;
24
use League\Flysystem\Filesystem;
25
use League\Flysystem\Adapter\Local;
26
use League\Flysystem\FilesystemInterface;
27
use Goodby\CSV\Import\Standard\Lexer;
28
use Goodby\CSV\Import\Standard\LexerConfig;
29
use Goodby\CSV\Import\Standard\Interpreter;
30
use TechDivision\Import\Utils\ConfigurationKeys;
31
use TechDivision\Import\Services\RegistryProcessor;
32
use TechDivision\Import\Callbacks\CallbackInterface;
33
use TechDivision\Import\Observers\ObserverInterface;
34
use TechDivision\Import\Services\RegistryProcessorInterface;
35
use TechDivision\Import\Configuration\SubjectInterface as SubjectConfigurationInterface;
36
37
/**
38
 * An abstract subject implementation.
39
 *
40
 * @author    Tim Wagner <[email protected]>
41
 * @copyright 2016 TechDivision GmbH <[email protected]>
42
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
43
 * @link      https://github.com/techdivision/import
44
 * @link      http://www.techdivision.com
45
 */
46
abstract class AbstractSubject implements SubjectInterface
47
{
48
49
    /**
50
     * The root directory for the virtual filesystem.
51
     *
52
     * @var string
53
     */
54
    protected $rootDir;
55
56
    /**
57
     * The system configuration.
58
     *
59
     * @var \TechDivision\Import\Configuration\SubjectInterface
60
     */
61
    protected $configuration;
62
63
    /**
64
     * The system logger implementation.
65
     *
66
     * @var \Psr\Log\LoggerInterface
67
     */
68
    protected $systemLogger;
69
70
    /**
71
     * The RegistryProcessor instance to handle running threads.
72
     *
73
     * @var \TechDivision\Import\Services\RegistryProcessorInterface
74
     */
75
    protected $registryProcessor;
76
77
    /**
78
     * The actions unique serial.
79
     *
80
     * @var string
81
     */
82
    protected $serial;
83
84
    /**
85
     * The name of the file to be imported.
86
     *
87
     * @var string
88
     */
89
    protected $filename;
90
91
    /**
92
     * Array with the subject's observers.
93
     *
94
     * @var array
95
     */
96
    protected $observers = array();
97
98
    /**
99
     * Array with the subject's callbacks.
100
     *
101
     * @var array
102
     */
103
    protected $callbacks = array();
104
105
    /**
106
     * Contain's the column names from the header line.
107
     *
108
     * @var array
109
     */
110
    protected $headers = array();
111
112
    /**
113
     * The virtual filesystem instance.
114
     *
115
     * @var \League\Flysystem\FilesystemInterface
116
     */
117
    protected $filesystem;
118
119
    /**
120
     * Set's the array containing header row.
121
     *
122
     * @param array $headers The array with the header row
123
     *
124
     * @return void
125
     */
126
    public function setHeaders(array $headers)
127
    {
128
        $this->headers = $headers;
129
    }
130
131
    /**
132
     * Return's the array containing header row.
133
     *
134
     * @return array The array with the header row
135
     */
136
    public function getHeaders()
137
    {
138
        return $this->headers;
139
    }
140
141
    /**
142
     * Set's the system configuration.
143
     *
144
     * @param \TechDivision\Import\Configuration\Subject $configuration The system configuration
145
     *
146
     * @return void
147
     */
148
    public function setConfiguration(SubjectConfigurationInterface $configuration)
149
    {
150
        $this->configuration = $configuration;
151
    }
152
153
    /**
154
     * Return's the system configuration.
155
     *
156
     * @return \TechDivision\Import\Configuration\SubjectInterface The system configuration
157
     */
158
    public function getConfiguration()
159
    {
160
        return $this->configuration;
161
    }
162
163
    /**
164
     * Set's the system logger.
165
     *
166
     * @param \Psr\Log\LoggerInterface $systemLogger The system logger
167
     *
168
     * @return void
169
     */
170
    public function setSystemLogger(LoggerInterface $systemLogger)
171
    {
172
        $this->systemLogger = $systemLogger;
173
    }
174
175
    /**
176
     * Return's the system logger.
177
     *
178
     * @return \Psr\Log\LoggerInterface The system logger instance
179
     */
180
    public function getSystemLogger()
181
    {
182
        return $this->systemLogger;
183
    }
184
185
    /**
186
     * Set's root directory for the virtual filesystem.
187
     *
188
     * @param string $rootDir The root directory for the virtual filesystem
189
     *
190
     * @return void
191
     */
192
    public function setRootDir($rootDir)
193
    {
194
        $this->rootDir = $rootDir;
195
    }
196
197
    /**
198
     * Return's the root directory for the virtual filesystem.
199
     *
200
     * @return string The root directory for the virtual filesystem
201
     */
202
    public function getRootDir()
203
    {
204
        return $this->rootDir;
205
    }
206
207
    /**
208
     * Set's the virtual filesystem instance.
209
     *
210
     * @param \League\Flysystem\FilesystemInterface $filesystem The filesystem instance
211
     *
212
     * @return void
213
     */
214
    public function setFilesystem(FilesystemInterface $filesystem)
215
    {
216
        $this->filesystem = $filesystem;
217
    }
218
219
    /**
220
     * Return's the virtual filesystem instance.
221
     *
222
     * @return \League\Flysystem\FilesystemInterface The filesystem instance
223
     */
224
    public function getFilesystem()
225
    {
226
        return $this->filesystem;
227
    }
228
229
    /**
230
     * Sets's the RegistryProcessor instance to handle the running threads.
231
     *
232
     * @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor The registry processor instance
233
     *
234
     * @return void
235
     */
236
    public function setRegistryProcessor(RegistryProcessorInterface $registryProcessor)
237
    {
238
        $this->registryProcessor = $registryProcessor;
239
    }
240
241
    /**
242
     * Return's the RegistryProcessor instance to handle the running threads.
243
     *
244
     * @return \TechDivision\Import\Services\RegistryProcessorInterface The registry processor instance
245
     */
246
    public function getRegistryProcessor()
247
    {
248
        return $this->registryProcessor;
249
    }
250
251
    /**
252
     * Set's the unique serial for this import process.
253
     *
254
     * @param string $serial The unique serial
255
     *
256
     * @return void
257
     */
258
    public function setSerial($serial)
259
    {
260
        $this->serial = $serial;
261
    }
262
263
    /**
264
     * Return's the unique serial for this import process.
265
     *
266
     * @return string The unique serial
267
     */
268
    public function getSerial()
269
    {
270
        return $this->serial;
271
    }
272
273
    /**
274
     * Set's the name of the file to import
275
     *
276
     * @param string $filename The filename
277
     *
278
     * @return void
279
     */
280
    public function setFilename($filename)
281
    {
282
        $this->filename = $filename;
283
    }
284
285
    /**
286
     * Return's the name of the file to import.
287
     *
288
     * @return string The filename
289
     */
290
    public function getFilename()
291
    {
292
        return $this->filename;
293
    }
294
295
    /**
296
     * Return's the source date format to use.
297
     *
298
     * @return string The source date format
299
     */
300
    public function getSourceDateFormat()
301
    {
302
        return $this->getConfiguration()->getSourceDateFormat();
303
    }
304
305
    /**
306
     * Return's the initialized PDO connection.
307
     *
308
     * @return \PDO The initialized PDO connection
309
     */
310
    public function getConnection()
311
    {
312
        return $this->getProductProcessor()->getConnection();
0 ignored issues
show
Bug introduced by
The method getProductProcessor() does not seem to exist on object<TechDivision\Impo...bjects\AbstractSubject>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
313
    }
314
315
    /**
316
     * Intializes the previously loaded global data for exactly one bunch.
317
     *
318
     * @return void
319
     * @see \Importer\Csv\Actions\ProductImportAction::prepare()
320
     */
321
    public function setUp()
322
    {
323
324
        // initialize the filesystems root directory
325
        $this->setRootDir(
326
            $this->getConfiguration()->getParam(ConfigurationKeys::ROOT_DIRECTORY, getcwd())
327
        );
328
329
        // initialize the filesystem
330
        $this->setFilesystem(new Filesystem(new Local($this->getRootDir())));
331
    }
332
333
    /**
334
     * This method tries to resolve the passed path and returns it. If the path
335
     * is relative, the actual working directory will be prepended.
336
     *
337
     * @param string $path The path to be resolved
338
     *
339
     * @return string The resolved path
340
     * @throws \InvalidArgumentException Is thrown, if the path can not be resolved
341
     */
342
    public function resolvePath($path)
343
    {
344
        // if we've an absolute path, return it immediately
345
        if ($this->getFilesystem()->has($path)) {
346
            return $path;
347
        }
348
349
        // try to prepend the actual working directory, assuming we've a relative path
350
        if ($this->getFilesystem()->has($path = getcwd() . DIRECTORY_SEPARATOR . $path)) {
351
            return $path;
352
        }
353
354
        // throw an exception if the passed directory doesn't exists
355
        throw new \InvalidArgumentException(
356
            sprintf('Directory %s doesn\'t exist', $path)
357
        );
358
    }
359
360
    /**
361
     * Clean up the global data after importing the variants.
362
     *
363
     * @return void
364
     */
365
    public function tearDown()
366
    {
367
    }
368
369
    /**
370
     * Register the passed observer with the specific type.
371
     *
372
     * @param \TechDivision\Import\Observers\ObserverInterface $observer The observer to register
373
     * @param string                                           $type     The type to register the observer with
374
     *
375
     * @return void
376
     */
377
    public function registerObserver(ObserverInterface $observer, $type)
378
    {
379
380
        // query whether or not the array with the callbacks for the
381
        // passed type has already been initialized, or not
382
        if (!isset($this->observers[$type])) {
383
            $this->observers[$type] = array();
384
        }
385
386
        // append the callback with the instance of the passed type
387
        $this->observers[$type][] = $observer;
388
    }
389
390
    /**
391
     * Register the passed callback with the specific type.
392
     *
393
     * @param \TechDivision\Import\Callbacks\CallbackInterface $callback The subject to register the callbacks for
394
     * @param string                                           $type     The type to register the callback with
395
     *
396
     * @return void
397
     */
398
    public function registerCallback(CallbackInterface $callback, $type)
399
    {
400
401
        // query whether or not the array with the callbacks for the
402
        // passed type has already been initialized, or not
403
        if (!isset($this->callbacks[$type])) {
404
            $this->callbacks[$type] = array();
405
        }
406
407
        // append the callback with the instance of the passed type
408
        $this->callbacks[$type][] = $callback;
409
    }
410
411
    /**
412
     * Return's the array with callbacks for the passed type.
413
     *
414
     * @param string $type The type of the callbacks to return
415
     *
416
     * @return array The callbacks
417
     */
418
    public function getCallbacksByType($type)
419
    {
420
421
        // initialize the array for the callbacks
422
        $callbacks = array();
423
424
        // query whether or not callbacks for the type are available
425
        if (isset($this->callbacks[$type])) {
426
            $callbacks = $this->callbacks[$type];
427
        }
428
429
        // return the array with the type's callbacks
430
        return $callbacks;
431
    }
432
433
    /**
434
     * Return's the array with the available observers.
435
     *
436
     * @return array The observers
437
     */
438
    public function getObservers()
439
    {
440
        return $this->observers;
441
    }
442
443
    /**
444
     * Return's the array with the available callbacks.
445
     *
446
     * @return array The callbacks
447
     */
448
    public function getCallbacks()
449
    {
450
        return $this->callbacks;
451
    }
452
453
    /**
454
     * Imports the content of the file with the passed filename.
455
     *
456
     * @param string $serial   The unique process serial
457
     * @param string $filename The filename to process
458
     *
459
     * @return void
460
     */
461
    public function import($serial, $filename)
462
    {
463
464
        try {
465
            // track the start time
466
            $startTime = microtime(true);
467
468
            // initialize serial and filename
469
            $this->setSerial($serial);
470
            $this->setFilename($filename);
471
472
            // load the system logger
473
            $systemLogger = $this->getSystemLogger();
474
475
            // initialize the global global data to import a bunch
476
            $this->setUp();
477
478
            // initialize the lexer instance itself
479
            $lexer = new Lexer($this->getLexerConfig());
480
481
            // initialize the interpreter
482
            $interpreter = new Interpreter();
483
            $interpreter->addObserver(array($this, 'importRow'));
484
485
            // query whether or not we want to use the strict mode
486
            if (!$this->getConfiguration()->isStrictMode()) {
487
                $interpreter->unstrict();
488
            }
489
490
            // log a message that the file has to be imported
491
            $systemLogger->debug(sprintf('Now start importing file %s', $filename));
492
493
            // parse the CSV file to be imported
494
            $lexer->parse($filename, $interpreter);
495
496
            // track the time needed for the import in seconds
497
            $endTime = microtime(true) - $startTime;
498
499
            // log a message that the file has successfully been imported
500
            $systemLogger->debug(sprintf('Succesfully imported file %s in %f s', $filename, $endTime));
501
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
502
        } catch (\Exception $e) {
503
            // log a message with the stack trace
504
            $systemLogger->error($e->__toString());
0 ignored issues
show
Bug introduced by
The variable $systemLogger does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
505
506
            // re-throw the exception
507
            throw $e;
508
        }
509
510
        // clean up the data after importing the bunch
511
        $this->tearDown();
512
    }
513
514
    /**
515
     * Initialize and return the lexer configuration.
516
     *
517
     * @return \Goodby\CSV\Import\Standard\LexerConfig The lexer configuration
518
     */
519
    protected function getLexerConfig()
520
    {
521
522
        // initialize the lexer configuration
523
        $config = new LexerConfig();
524
525
        // query whether or not a delimiter character has been configured
526
        if ($delimiter = $this->getConfiguration()->getDelimiter()) {
527
            $config->setDelimiter($delimiter);
528
        }
529
530
        // query whether or not a custom escape character has been configured
531
        if ($escape = $this->getConfiguration()->getEscape()) {
532
            $config->setEscape($escape);
533
        }
534
535
        // query whether or not a custom enclosure character has been configured
536
        if ($enclosure = $this->getConfiguration()->getEnclosure()) {
537
            $config->setEnclosure($enclosure);
538
        }
539
540
        // query whether or not a custom source charset has been configured
541
        if ($fromCharset = $this->getConfiguration()->getFromCharset()) {
542
            $config->setFromCharset($fromCharset);
543
        }
544
545
        // query whether or not a custom target charset has been configured
546
        if ($toCharset = $this->getConfiguration()->getToCharset()) {
547
            $config->setToCharset($toCharset);
548
        }
549
550
        // return the lexer configuratio
551
        return $config;
552
    }
553
554
    /**
555
     * Imports the passed row into the database.
556
     *
557
     * If the import failed, the exception will be catched and logged,
558
     * but the import process will be continued.
559
     *
560
     * @param array $row The row with the data to be imported
561
     *
562
     * @return void
563
     */
564
    public function importRow(array $row)
565
    {
566
567
        // initialize the headers with the columns from the first line
568
        if (sizeof($this->getHeaders()) === 0) {
569
            $this->setHeaders(array_flip($row));
570
            return;
571
        }
572
573
        // process the observers
574
        foreach ($this->getObservers() as $observers) {
575
            // invoke the pre-import/import and post-import observers
576
            foreach ($observers as $observer) {
577
                if ($observer instanceof ObserverInterface) {
578
                    $row = $observer->handle($row);
0 ignored issues
show
Bug introduced by
The method handle() does not seem to exist on object<TechDivision\Impo...vers\ObserverInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
579
                }
580
            }
581
        }
582
    }
583
}
584