Completed
Push — master ( a7caf4...17170d )
by Tim
10s
created

AbstractSubject::isDebugMode()   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
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
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\RegistryKeys;
31
use TechDivision\Import\Utils\ConfigurationKeys;
32
use TechDivision\Import\Services\RegistryProcessor;
33
use TechDivision\Import\Callbacks\CallbackVisitor;
34
use TechDivision\Import\Callbacks\CallbackInterface;
35
use TechDivision\Import\Observers\ObserverVisitor;
36
use TechDivision\Import\Observers\ObserverInterface;
37
use TechDivision\Import\Services\RegistryProcessorInterface;
38
use TechDivision\Import\Configuration\SubjectConfigurationInterface;
39
40
/**
41
 * An abstract subject implementation.
42
 *
43
 * @author    Tim Wagner <[email protected]>
44
 * @copyright 2016 TechDivision GmbH <[email protected]>
45
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
46
 * @link      https://github.com/techdivision/import
47
 * @link      http://www.techdivision.com
48
 */
49
abstract class AbstractSubject implements SubjectInterface
50
{
51
52
    /**
53
     * The root directory for the virtual filesystem.
54
     *
55
     * @var string
56
     */
57
    protected $rootDir;
58
59
    /**
60
     * The system configuration.
61
     *
62
     * @var \TechDivision\Import\Configuration\SubjectConfigurationInterface
63
     */
64
    protected $configuration;
65
66
    /**
67
     * The system logger implementation.
68
     *
69
     * @var \Psr\Log\LoggerInterface
70
     */
71
    protected $systemLogger;
72
73
    /**
74
     * The RegistryProcessor instance to handle running threads.
75
     *
76
     * @var \TechDivision\Import\Services\RegistryProcessorInterface
77
     */
78
    protected $registryProcessor;
79
80
    /**
81
     * The actions unique serial.
82
     *
83
     * @var string
84
     */
85
    protected $serial;
86
87
    /**
88
     * The name of the file to be imported.
89
     *
90
     * @var string
91
     */
92
    protected $filename;
93
94
    /**
95
     * Array with the subject's observers.
96
     *
97
     * @var array
98
     */
99
    protected $observers = array();
100
101
    /**
102
     * Array with the subject's callbacks.
103
     *
104
     * @var array
105
     */
106
    protected $callbacks = array();
107
108
    /**
109
     * The subject's callback mappings.
110
     *
111
     * @var array
112
     */
113
    protected $callbackMappings = array();
114
115
    /**
116
     * Contain's the column names from the header line.
117
     *
118
     * @var array
119
     */
120
    protected $headers = array();
121
122
    /**
123
     * The virtual filesystem instance.
124
     *
125
     * @var \League\Flysystem\FilesystemInterface
126
     */
127
    protected $filesystem;
128
129
    /**
130
     * The actual line number.
131
     *
132
     * @var integer
133
     */
134
    protected $lineNumber = 0;
135
136
    /**
137
     * The actual operation name.
138
     *
139
     * @var string
140
     */
141
    protected $operationName ;
142
143
    /**
144
     * The flag that stop's overserver execution on the actual row.
145
     *
146
     * @var boolean
147
     */
148
    protected $skipRow = false;
149
150
    /**
151
     * Mappings for attribute code => CSV column header.
152
     *
153
     * @var array
154
     */
155
    protected $headerMappings = array(
156
        'product_online' => 'status',
157
        'tax_class_name' => 'tax_class_id',
158
        'bundle_price_type' => 'price_type',
159
        'bundle_sku_type' => 'sku_type',
160
        'bundle_price_view' => 'price_view',
161
        'bundle_weight_type' => 'weight_type',
162
        'base_image' => 'image',
163
        'base_image_label' => 'image_label',
164
        'thumbnail_image' => 'thumbnail',
165
        'thumbnail_image_label'=> 'thumbnail_label',
166
        'bundle_shipment_type' => 'shipment_type'
167
    );
168
169
    /**
170
     * Initialize the subject instance.
171
     *
172
     * @param \Psr\Log\LoggerInterface                                         $systemLogger      The system logger instance
173
     * @param \TechDivision\Import\Configuration\SubjectConfigurationInterface $configuration     The subject configuration instance
174
     * @param \TechDivision\Import\Services\RegistryProcessorInterface         $registryProcessor The registry processor instance
175
     */
176
    public function __construct(
177
        LoggerInterface $systemLogger,
178
        SubjectConfigurationInterface $configuration,
179
        RegistryProcessorInterface $registryProcessor
180
    ) {
181
        $this->systemLogger = $systemLogger;
182
        $this->configuration = $configuration;
183
        $this->registryProcessor = $registryProcessor;
184
    }
185
186
    /**
187
     * Stop's observer execution on the actual row.
188
     *
189
     * @return void
190
     */
191
    public function skipRow()
192
    {
193
        $this->skipRow = true;
194
    }
195
196
    /**
197
     * Return's the actual line number.
198
     *
199
     * @return integer The line number
200
     */
201
    public function getLineNumber()
202
    {
203
        return $this->lineNumber;
204
    }
205
206
    /**
207
     * Return's the actual operation name.
208
     *
209
     * @return string
210
     */
211
    public function getOperationName()
212
    {
213
        return $this->operationName;
214
    }
215
216
    /**
217
     * Set's the array containing header row.
218
     *
219
     * @param array $headers The array with the header row
220
     *
221
     * @return void
222
     */
223
    public function setHeaders(array $headers)
224
    {
225
        $this->headers = $headers;
226
    }
227
228
    /**
229
     * Return's the array containing header row.
230
     *
231
     * @return array The array with the header row
232
     */
233
    public function getHeaders()
234
    {
235
        return $this->headers;
236
    }
237
238
    /**
239
     * Queries whether or not the header with the passed name is available.
240
     *
241
     * @param string $name The header name to query
242
     *
243
     * @return boolean TRUE if the header is available, else FALSE
244
     */
245
    public function hasHeader($name)
246
    {
247
        return isset($this->headers[$name]);
248
    }
249
250
    /**
251
     * Return's the header value for the passed name.
252
     *
253
     * @param string $name The name of the header to return the value for
254
     *
255
     * @return mixed The header value
256
     * \InvalidArgumentException Is thrown, if the header with the passed name is NOT available
257
     */
258
    public function getHeader($name)
259
    {
260
261
        // query whether or not, the header is available
262
        if (isset($this->headers[$name])) {
263
            return $this->headers[$name];
264
        }
265
266
        // throw an exception, if not
267
        throw new \InvalidArgumentException(sprintf('Header %s is not available', $name));
268
    }
269
270
    /**
271
     * Add's the header with the passed name and position, if not NULL.
272
     *
273
     * @param string $name The header name to add
274
     *
275
     * @return integer The new headers position
276
     */
277
    public function addHeader($name)
278
    {
279
280
        // add the header
281
        $this->headers[$name] = $position = sizeof($this->headers);
282
283
        // return the new header's position
284
        return $position;
285
    }
286
287
    /**
288
     * Queries whether or not debug mode is enabled or not, default is TRUE.
289
     *
290
     * @return boolean TRUE if debug mode is enabled, else FALSE
291
     */
292
    public function isDebugMode()
293
    {
294
        return $this->getConfiguration()->isDebugMode();
295
    }
296
297
    /**
298
     * Return's the system configuration.
299
     *
300
     * @return \TechDivision\Import\Configuration\SubjectConfigurationInterface The system configuration
301
     */
302
    public function getConfiguration()
303
    {
304
        return $this->configuration;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->configuration; (TechDivision\Import\Conf...tConfigurationInterface) is incompatible with the return type declared by the interface TechDivision\Import\Subj...rface::getConfiguration of type TechDivision\Import\Configuration\SubjectInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
305
    }
306
307
    /**
308
     * Return's the system logger.
309
     *
310
     * @return \Psr\Log\LoggerInterface The system logger instance
311
     */
312
    public function getSystemLogger()
313
    {
314
        return $this->systemLogger;
315
    }
316
317
    /**
318
     * Set's root directory for the virtual filesystem.
319
     *
320
     * @param string $rootDir The root directory for the virtual filesystem
321
     *
322
     * @return void
323
     */
324
    public function setRootDir($rootDir)
325
    {
326
        $this->rootDir = $rootDir;
327
    }
328
329
    /**
330
     * Return's the root directory for the virtual filesystem.
331
     *
332
     * @return string The root directory for the virtual filesystem
333
     */
334
    public function getRootDir()
335
    {
336
        return $this->rootDir;
337
    }
338
339
    /**
340
     * Set's the virtual filesystem instance.
341
     *
342
     * @param \League\Flysystem\FilesystemInterface $filesystem The filesystem instance
343
     *
344
     * @return void
345
     */
346
    public function setFilesystem(FilesystemInterface $filesystem)
347
    {
348
        $this->filesystem = $filesystem;
349
    }
350
351
    /**
352
     * Return's the virtual filesystem instance.
353
     *
354
     * @return \League\Flysystem\FilesystemInterface The filesystem instance
355
     */
356
    public function getFilesystem()
357
    {
358
        return $this->filesystem;
359
    }
360
361
    /**
362
     * Return's the RegistryProcessor instance to handle the running threads.
363
     *
364
     * @return \TechDivision\Import\Services\RegistryProcessorInterface The registry processor instance
365
     */
366
    public function getRegistryProcessor()
367
    {
368
        return $this->registryProcessor;
369
    }
370
371
    /**
372
     * Set's the unique serial for this import process.
373
     *
374
     * @param string $serial The unique serial
375
     *
376
     * @return void
377
     */
378
    public function setSerial($serial)
379
    {
380
        $this->serial = $serial;
381
    }
382
383
    /**
384
     * Return's the unique serial for this import process.
385
     *
386
     * @return string The unique serial
387
     */
388
    public function getSerial()
389
    {
390
        return $this->serial;
391
    }
392
393
    /**
394
     * Set's the name of the file to import
395
     *
396
     * @param string $filename The filename
397
     *
398
     * @return void
399
     */
400
    public function setFilename($filename)
401
    {
402
        $this->filename = $filename;
403
    }
404
405
    /**
406
     * Return's the name of the file to import.
407
     *
408
     * @return string The filename
409
     */
410
    public function getFilename()
411
    {
412
        return $this->filename;
413
    }
414
415
    /**
416
     * Return's the source date format to use.
417
     *
418
     * @return string The source date format
419
     */
420
    public function getSourceDateFormat()
421
    {
422
        return $this->getConfiguration()->getSourceDateFormat();
423
    }
424
425
    /**
426
     * Return's the multiple field delimiter character to use, default value is comma (,).
427
     *
428
     * @return string The multiple field delimiter character
429
     */
430
    public function getMultipleFieldDelimiter()
431
    {
432
        return $this->getConfiguration()->getMultipleFieldDelimiter();
0 ignored issues
show
Bug introduced by
The method getMultipleFieldDelimiter() does not seem to exist on object<TechDivision\Impo...ConfigurationInterface>.

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...
433
    }
434
435
    /**
436
     * Return's the initialized PDO connection.
437
     *
438
     * @return \PDO The initialized PDO connection
439
     */
440
    public function getConnection()
441
    {
442
        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...
443
    }
444
445
    /**
446
     * Intializes the previously loaded global data for exactly one bunch.
447
     *
448
     * @return void
449
     * @see \Importer\Csv\Actions\ProductImportAction::prepare()
450
     */
451
    public function setUp()
452
    {
453
454
        // initialize the filesystems root directory
455
        $this->setRootDir(
456
            $this->getConfiguration()->getParam(ConfigurationKeys::ROOT_DIRECTORY, getcwd())
457
        );
458
459
        // initialize the filesystem
460
        $this->filesystem = new Filesystem(new Local($this->getRootDir()));
461
462
        // initialize the operation name
463
        $this->operationName = $this->getConfiguration()->getConfiguration()->getOperationName();
464
465
        // initialize the callbacks/observers
466
        CallbackVisitor::get()->visit($this);
467
        ObserverVisitor::get()->visit($this);
468
    }
469
470
    /**
471
     * This method tries to resolve the passed path and returns it. If the path
472
     * is relative, the actual working directory will be prepended.
473
     *
474
     * @param string $path The path to be resolved
475
     *
476
     * @return string The resolved path
477
     * @throws \InvalidArgumentException Is thrown, if the path can not be resolved
478
     */
479
    public function resolvePath($path)
480
    {
481
        // if we've an absolute path, return it immediately
482
        if ($this->getFilesystem()->has($path)) {
483
            return $path;
484
        }
485
486
        // try to prepend the actual working directory, assuming we've a relative path
487
        if ($this->getFilesystem()->has($path = getcwd() . DIRECTORY_SEPARATOR . $path)) {
488
            return $path;
489
        }
490
491
        // throw an exception if the passed directory doesn't exists
492
        throw new \InvalidArgumentException(
493
            sprintf('Directory %s doesn\'t exist', $path)
494
        );
495
    }
496
497
    /**
498
     * Clean up the global data after importing the variants.
499
     *
500
     * @return void
501
     */
502
    public function tearDown()
503
    {
504
505
        // load the registry processor
506
        $registryProcessor = $this->getRegistryProcessor();
507
508
        // update the source directory for the next subject
509
        $registryProcessor->mergeAttributesRecursive(
510
            $this->getSerial(),
511
            array(RegistryKeys::SOURCE_DIRECTORY => $this->getNewSourceDir())
512
        );
513
514
        // log a debug message with the new source directory
515
        $this->getSystemLogger()->debug(
516
            sprintf('Subject %s successfully updated source directory to %s', __CLASS__, $this->getNewSourceDir())
517
        );
518
    }
519
520
    /**
521
     * Return's the next source directory, which will be the target directory
522
     * of this subject, in most cases.
523
     *
524
     * @return string The new source directory
525
     */
526
    protected function getNewSourceDir()
527
    {
528
        return sprintf('%s/%s', $this->getConfiguration()->getTargetDir(), $this->getSerial());
529
    }
530
531
    /**
532
     * Register the passed observer with the specific type.
533
     *
534
     * @param \TechDivision\Import\Observers\ObserverInterface $observer The observer to register
535
     * @param string                                           $type     The type to register the observer with
536
     *
537
     * @return void
538
     */
539
    public function registerObserver(ObserverInterface $observer, $type)
540
    {
541
542
        // query whether or not the array with the callbacks for the
543
        // passed type has already been initialized, or not
544
        if (!isset($this->observers[$type])) {
545
            $this->observers[$type] = array();
546
        }
547
548
        // append the callback with the instance of the passed type
549
        $this->observers[$type][] = $observer;
550
    }
551
552
    /**
553
     * Register the passed callback with the specific type.
554
     *
555
     * @param \TechDivision\Import\Callbacks\CallbackInterface $callback The subject to register the callbacks for
556
     * @param string                                           $type     The type to register the callback with
557
     *
558
     * @return void
559
     */
560
    public function registerCallback(CallbackInterface $callback, $type)
561
    {
562
563
        // query whether or not the array with the callbacks for the
564
        // passed type has already been initialized, or not
565
        if (!isset($this->callbacks[$type])) {
566
            $this->callbacks[$type] = array();
567
        }
568
569
        // append the callback with the instance of the passed type
570
        $this->callbacks[$type][] = $callback;
571
    }
572
573
    /**
574
     * Return's the array with callbacks for the passed type.
575
     *
576
     * @param string $type The type of the callbacks to return
577
     *
578
     * @return array The callbacks
579
     */
580
    public function getCallbacksByType($type)
581
    {
582
583
        // initialize the array for the callbacks
584
        $callbacks = array();
585
586
        // query whether or not callbacks for the type are available
587
        if (isset($this->callbacks[$type])) {
588
            $callbacks = $this->callbacks[$type];
589
        }
590
591
        // return the array with the type's callbacks
592
        return $callbacks;
593
    }
594
595
    /**
596
     * Return's the array with the available observers.
597
     *
598
     * @return array The observers
599
     */
600
    public function getObservers()
601
    {
602
        return $this->observers;
603
    }
604
605
    /**
606
     * Return's the array with the available callbacks.
607
     *
608
     * @return array The callbacks
609
     */
610
    public function getCallbacks()
611
    {
612
        return $this->callbacks;
613
    }
614
615
    /**
616
     * Return's the callback mappings for this subject.
617
     *
618
     * @return array The array with the subject's callback mappings
619
     */
620
    public function getCallbackMappings()
621
    {
622
        return $this->callbackMappings;
623
    }
624
625
    /**
626
     * Imports the content of the file with the passed filename.
627
     *
628
     * @param string $serial   The unique process serial
629
     * @param string $filename The filename to process
630
     *
631
     * @return void
632
     * @throws \Exception Is thrown, if the import can't be processed
633
     */
634
    public function import($serial, $filename)
635
    {
636
637
        try {
638
            // stop processing, if the filename doesn't match
639
            if (!$this->match($filename)) {
640
                return;
641
            }
642
643
            // load the system logger instance
644
            $systemLogger = $this->getSystemLogger();
645
646
            // prepare the flag filenames
647
            $inProgressFilename = sprintf('%s.inProgress', $filename);
648
            $importedFilename = sprintf('%s.imported', $filename);
649
            $failedFilename = sprintf('%s.failed', $filename);
650
651
            // query whether or not the file has already been imported
652
            if (is_file($failedFilename) ||
653
                is_file($importedFilename) ||
654
                is_file($inProgressFilename)
655
            ) {
656
                // log a debug message and exit
657
                $systemLogger->debug(sprintf('Import running, found inProgress file %s', $inProgressFilename));
658
                return;
659
            }
660
661
            // flag file as in progress
662
            touch($inProgressFilename);
663
664
            // track the start time
665
            $startTime = microtime(true);
666
667
            // initialize serial and filename
668
            $this->setSerial($serial);
669
            $this->setFilename($filename);
670
671
            // load the system logger
672
            $systemLogger = $this->getSystemLogger();
673
674
            // initialize the global global data to import a bunch
675
            $this->setUp();
676
677
            // initialize the lexer instance itself
678
            $lexer = new Lexer($this->getLexerConfig());
679
680
            // initialize the interpreter
681
            $interpreter = new Interpreter();
682
            $interpreter->addObserver(array($this, 'importRow'));
683
684
            // query whether or not we want to use the strict mode
685
            if (!$this->getConfiguration()->isStrictMode()) {
686
                $interpreter->unstrict();
687
            }
688
689
            // log a message that the file has to be imported
690
            $systemLogger->debug(sprintf('Now start importing file %s', $filename));
691
692
            // parse the CSV file to be imported
693
            $lexer->parse($filename, $interpreter);
694
695
            // track the time needed for the import in seconds
696
            $endTime = microtime(true) - $startTime;
697
698
            // clean up the data after importing the bunch
699
            $this->tearDown();
700
701
            // log a message that the file has successfully been imported
702
            $systemLogger->debug(sprintf('Succesfully imported file %s in %f s', $filename, $endTime));
703
704
            // rename flag file, because import has been successfull
705
            rename($inProgressFilename, $importedFilename);
706
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
707
        } catch (\Exception $e) {
708
            // rename the flag file, because import failed and write the stack trace
709
            rename($inProgressFilename, $failedFilename);
0 ignored issues
show
Bug introduced by
The variable $inProgressFilename 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...
Bug introduced by
The variable $failedFilename 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...
710
            file_put_contents($failedFilename, $e->__toString());
711
712
            // clean up the data after importing the bunch
713
            $this->tearDown();
714
715
            // re-throw the exception
716
            throw $e;
717
        }
718
    }
719
720
    /**
721
     * This method queries whether or not the passed filename matches
722
     * the pattern, based on the subjects configured prefix.
723
     *
724
     * @param string $filename The filename to match
725
     *
726
     * @return boolean TRUE if the filename matches, else FALSE
727
     */
728
    protected function match($filename)
729
    {
730
731
        // prepare the pattern to query whether the file has to be processed or not
732
        $pattern = sprintf('/^.*\/%s.*\\.csv$/', $this->getConfiguration()->getPrefix());
733
734
        // stop processing, if the filename doesn't match
735
        return (boolean) preg_match($pattern, $filename);
736
    }
737
738
    /**
739
     * Initialize and return the lexer configuration.
740
     *
741
     * @return \Goodby\CSV\Import\Standard\LexerConfig The lexer configuration
742
     */
743
    protected function getLexerConfig()
744
    {
745
746
        // initialize the lexer configuration
747
        $config = new LexerConfig();
748
749
        // query whether or not a delimiter character has been configured
750
        if ($delimiter = $this->getConfiguration()->getDelimiter()) {
751
            $config->setDelimiter($delimiter);
752
        }
753
754
        // query whether or not a custom escape character has been configured
755
        if ($escape = $this->getConfiguration()->getEscape()) {
756
            $config->setEscape($escape);
757
        }
758
759
        // query whether or not a custom enclosure character has been configured
760
        if ($enclosure = $this->getConfiguration()->getEnclosure()) {
761
            $config->setEnclosure($enclosure);
762
        }
763
764
        // query whether or not a custom source charset has been configured
765
        if ($fromCharset = $this->getConfiguration()->getFromCharset()) {
766
            $config->setFromCharset($fromCharset);
767
        }
768
769
        // query whether or not a custom target charset has been configured
770
        if ($toCharset = $this->getConfiguration()->getToCharset()) {
771
            $config->setToCharset($toCharset);
772
        }
773
774
        // return the lexer configuratio
775
        return $config;
776
    }
777
778
    /**
779
     * Imports the passed row into the database.
780
     *
781
     * If the import failed, the exception will be catched and logged,
782
     * but the import process will be continued.
783
     *
784
     * @param array $row The row with the data to be imported
785
     *
786
     * @return void
787
     */
788
    public function importRow(array $row)
789
    {
790
791
        // raise the line number and reset the skip row flag
792
        $this->lineNumber++;
793
        $this->skipRow = false;
794
795
        // initialize the headers with the columns from the first line
796
        if (sizeof($this->headers) === 0) {
797
            foreach ($row as $value => $key) {
798
                $this->headers[$this->mapAttributeCodeByHeaderMapping($key)] = $value;
799
            }
800
            return;
801
        }
802
803
        // process the observers
804
        foreach ($this->getObservers() as $observers) {
805
            // invoke the pre-import/import and post-import observers
806
            foreach ($observers as $observer) {
807
                // query whether or not we have to skip the row
808
                if ($this->skipRow) {
809
                    break;
810
                }
811
                // if not, process the next observer
812
                if ($observer instanceof ObserverInterface) {
813
                    $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...
814
                }
815
            }
816
        }
817
818
        // log a debug message with the actual line nr/file information
819
        $this->getSystemLogger()->debug(
820
            sprintf(
821
                'Successfully processed row (operation: %s) in file %s on line %d',
822
                $this->operationName,
823
                $this->filename,
824
                $this->lineNumber
825
            )
826
        );
827
    }
828
829
    /**
830
     * Map the passed attribute code, if a header mapping exists and return the
831
     * mapped mapping.
832
     *
833
     * @param string $attributeCode The attribute code to map
834
     *
835
     * @return string The mapped attribute code, or the original one
836
     */
837
    public function mapAttributeCodeByHeaderMapping($attributeCode)
838
    {
839
840
        // query weather or not we've a mapping, if yes, map the attribute code
841
        if (isset($this->headerMappings[$attributeCode])) {
842
            $attributeCode = $this->headerMappings[$attributeCode];
843
        }
844
845
        // return the (mapped) attribute code
846
        return $attributeCode;
847
    }
848
849
    /**
850
     * Queries whether or not that the subject needs an OK file to be processed.
851
     *
852
     * @return boolean TRUE if the subject needs an OK file, else FALSE
853
     */
854
    public function isOkFileNeeded()
855
    {
856
        return $this->getConfiguration()->isOkFileNeeded();
857
    }
858
}
859