Completed
Push — master ( fa1b74...e892f9 )
by Tim
17s queued 11s
created

Simple::finish()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
/**
4
 * TechDivision\Import\App\Simple
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-app-simple
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\App;
22
23
use Psr\Log\LogLevel;
24
use League\Event\EmitterInterface;
25
use Psr\Container\ContainerInterface;
26
use Doctrine\Common\Collections\Collection;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\Console\Helper\FormatterHelper;
29
use TechDivision\Import\Utils\LoggerKeys;
30
use TechDivision\Import\Utils\EventNames;
31
use TechDivision\Import\ApplicationInterface;
32
use TechDivision\Import\App\Utils\DependencyInjectionKeys;
33
use TechDivision\Import\Configuration\ConfigurationInterface;
34
use TechDivision\Import\Exceptions\ImportAlreadyRunningException;
35
use TechDivision\Import\Services\ImportProcessorInterface;
36
use TechDivision\Import\Services\RegistryProcessorInterface;
37
use TechDivision\Import\Exceptions\ApplicationStoppedException;
38
use TechDivision\Import\Exceptions\ApplicationFinishedException;
39
use TechDivision\Import\Handlers\PidFileHandlerInterface;
40
use TechDivision\Import\Handlers\GenericFileHandlerInterface;
41
42
/**
43
 * The M2IF - Simple Application implementation.
44
 *
45
 * This is a example application implementation that should give developers an impression
46
 * on how the M2IF could be used to implement their own Magento 2 importer.
47
 *
48
 * @author    Tim Wagner <[email protected]>
49
 * @copyright 2016 TechDivision GmbH <[email protected]>
50
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
51
 * @link      https://github.com/techdivision/import-app-simple
52
 * @link      http://www.techdivision.com
53
 */
54
class Simple implements ApplicationInterface
55
{
56
57
    /**
58
     * The default style to write messages to the symfony console.
59
     *
60
     * @var string
61
     */
62
    const DEFAULT_STYLE = 'info';
63
64
    /**
65
     * The log level => console style mapping.
66
     *
67
     * @var array
68
     */
69
    protected $logLevelStyleMapping = array(
70
        LogLevel::INFO      => 'info',
71
        LogLevel::DEBUG     => 'comment',
72
        LogLevel::ERROR     => 'error',
73
        LogLevel::ALERT     => 'error',
74
        LogLevel::CRITICAL  => 'error',
75
        LogLevel::EMERGENCY => 'error',
76
        LogLevel::WARNING   => 'error',
77
        LogLevel::NOTICE    => 'info'
78
    );
79
80
    /**
81
     * The PID for the running processes.
82
     *
83
     * @var array
84
     */
85
    protected $pid;
86
87
    /**
88
     * The actions unique serial.
89
     *
90
     * @var string
91
     */
92
    protected $serial;
93
94
    /**
95
     * The array with the system logger instances.
96
     *
97
     * @var \Doctrine\Common\Collections\Collection
98
     */
99
    protected $systemLoggers;
100
101
    /**
102
     * The RegistryProcessor instance to handle running threads.
103
     *
104
     * @var \TechDivision\Import\Services\RegistryProcessorInterface
105
     */
106
    protected $registryProcessor;
107
108
    /**
109
     * The processor to read/write the necessary import data.
110
     *
111
     * @var \TechDivision\Import\Services\ImportProcessorInterface
112
     */
113
    protected $importProcessor;
114
115
    /**
116
     * The DI container builder instance.
117
     *
118
     * @var \Psr\Container\ContainerInterface
119
     */
120
    protected $container;
121
122
    /**
123
     * The system configuration.
124
     *
125
     * @var \TechDivision\Import\Configuration\ConfigurationInterface
126
     */
127
    protected $configuration;
128
129
    /**
130
     * The output stream to write console information to.
131
     *
132
     * @var \Symfony\Component\Console\Output\OutputInterface
133
     */
134
    protected $output;
135
136
    /**
137
     * The plugins to be processed.
138
     *
139
     * @var array
140
     */
141
    protected $plugins = array();
142
143
    /**
144
     * The flag that stop's processing the operation.
145
     *
146
     * @var boolean
147
     */
148
    protected $stopped = false;
149
150
    /**
151
     * The filehandle for the PID file.
152
     *
153
     * @var resource
154
     */
155
    protected $fh;
156
157
    /**
158
     * The array with the module instances.
159
     *
160
     * @var \TechDivision\Import\Modules\ModuleInterface[]
161
     */
162
    protected $modules;
163
164
    /**
165
     * The event emitter instance.
166
     *
167
     * @var \League\Event\EmitterInterface
168
     */
169
    protected $emitter;
170
171
    /**
172
     * The generic file handler instance.
173
     *
174
     * @var \TechDivision\Import\Handlers\GenericFileHandlerInterface
175
     */
176
    protected $genericFileHanlder;
177
178
    /**
179
     * The PID file handler instance.
180
     *
181
     * @var \TechDivision\Import\Handlers\PidFileHandlerInterface
182
     */
183
    protected $pidFileHanlder;
184
185
    /**
186
     * The constructor to initialize the instance.
187
     *
188
     * @param \Psr\Container\ContainerInterface                         $container          The DI container instance
189
     * @param \TechDivision\Import\Services\RegistryProcessorInterface  $registryProcessor  The registry processor instance
190
     * @param \TechDivision\Import\Services\ImportProcessorInterface    $importProcessor    The import processor instance
191
     * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration      The system configuration
192
     * @param \Symfony\Component\Console\Output\OutputInterface         $output             The output instance
193
     * @param \Doctrine\Common\Collections\Collection                   $systemLoggers      The array with the system logger instances
194
     * @param \League\Event\EmitterInterface                            $emitter            The event emitter instance
195
     * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface $genericFileHandler The generic file handler instance
196
     * @param \TechDivision\Import\Handlers\PidFileHandlerInterface     $pidFileHandler     The PID file handler instance
197
     * @param \Traversable                                              $modules            The modules that provides the business logic
198
     */
199
    public function __construct(
200
        ContainerInterface $container,
201
        RegistryProcessorInterface $registryProcessor,
202
        ImportProcessorInterface $importProcessor,
203
        ConfigurationInterface $configuration,
204
        OutputInterface $output,
205
        Collection $systemLoggers,
206
        EmitterInterface $emitter,
207
        GenericFileHandlerInterface $genericFileHandler,
208
        PidFileHandlerInterface $pidFileHandler,
209
        \Traversable $modules
210
    ) {
211
212
        // register the shutdown function
213
        register_shutdown_function(array($this, 'shutdown'));
214
215
        // initialize the instance with the passed values
216
        $this->setOutput($output);
217
        $this->setEmitter($emitter);
218
        $this->setModules($modules);
219
        $this->setContainer($container);
220
        $this->setConfiguration($configuration);
221
        $this->setSystemLoggers($systemLoggers);
222
        $this->setPidFileHandler($pidFileHandler);
223
        $this->setImportProcessor($importProcessor);
224
        $this->setRegistryProcessor($registryProcessor);
225
        $this->setGenericFileHandler($genericFileHandler);
226
    }
227
228
    /**
229
     * Set's the event emitter instance.
230
     *
231
     * @param \League\Event\EmitterInterface $emitter The event emitter instance
232
     *
233
     * @return void
234
     */
235
    public function setEmitter(EmitterInterface $emitter)
236
    {
237
        $this->emitter = $emitter;
238
    }
239
240
    /**
241
     * Return's the event emitter instance.
242
     *
243
     * @return \League\Event\EmitterInterface The event emitter instance
244
     */
245
    public function getEmitter()
246
    {
247
        return $this->emitter;
248
    }
249
250
    /**
251
     * Set's the container instance.
252
     *
253
     * @param \Psr\Container\ContainerInterface $container The container instance
254
     *
255
     * @return void
256
     */
257
    public function setContainer(ContainerInterface $container)
258
    {
259
        $this->container = $container;
260
    }
261
262
    /**
263
     * Return's the container instance.
264
     *
265
     * @return \Psr\Container\ContainerInterface The container instance
266
     */
267
    public function getContainer()
268
    {
269
        return $this->container;
270
    }
271
272
    /**
273
     * Set's the output stream to write console information to.
274
     *
275
     * @param \Symfony\Component\Console\Output\OutputInterface $output The output stream
276
     *
277
     * @return void
278
     */
279
    public function setOutput(OutputInterface $output)
280
    {
281
        $this->output = $output;
282
    }
283
284
    /**
285
     * Return's the output stream to write console information to.
286
     *
287
     * @return \Symfony\Component\Console\Output\OutputInterface The output stream
288
     */
289
    public function getOutput()
290
    {
291
        return $this->output;
292
    }
293
294
    /**
295
     * Set's the system configuration.
296
     *
297
     * @param \TechDivision\Import\Configuration\ConfigurationInterface $configuration The system configuration
298
     *
299
     * @return void
300
     */
301
    public function setConfiguration(ConfigurationInterface $configuration)
302
    {
303
        $this->configuration = $configuration;
304
    }
305
306
    /**
307
     * Return's the system configuration.
308
     *
309
     * @return \TechDivision\Import\Configuration\ConfigurationInterface The system configuration
310
     */
311
    public function getConfiguration()
312
    {
313
        return $this->configuration;
314
    }
315
316
    /**
317
     * Set's the RegistryProcessor instance to handle the running threads.
318
     *
319
     * @param \TechDivision\Import\Services\RegistryProcessor $registryProcessor The registry processor instance
320
     *
321
     * @return void
322
     */
323
    public function setRegistryProcessor(RegistryProcessorInterface $registryProcessor)
324
    {
325
        $this->registryProcessor = $registryProcessor;
326
    }
327
328
    /**
329
     * Return's the RegistryProcessor instance to handle the running threads.
330
     *
331
     * @return \TechDivision\Import\Services\RegistryProcessor The registry processor instance
332
     */
333
    public function getRegistryProcessor()
334
    {
335
        return $this->registryProcessor;
336
    }
337
338
    /**
339
     * Set's the import processor instance.
340
     *
341
     * @param \TechDivision\Import\Services\ImportProcessorInterface $importProcessor The import processor instance
342
     *
343
     * @return void
344
     */
345
    public function setImportProcessor(ImportProcessorInterface $importProcessor)
346
    {
347
        $this->importProcessor = $importProcessor;
348
    }
349
350
    /**
351
     * Return's the import processor instance.
352
     *
353
     * @return \TechDivision\Import\Services\ImportProcessorInterface The import processor instance
354
     */
355
    public function getImportProcessor()
356
    {
357
        return $this->importProcessor;
358
    }
359
360
    /**
361
     * The array with the system loggers.
362
     *
363
     * @param \Doctrine\Common\Collections\Collection $systemLoggers The system logger instances
364
     *
365
     * @return void
366
     */
367
    public function setSystemLoggers(Collection $systemLoggers)
368
    {
369
        $this->systemLoggers = $systemLoggers;
370
    }
371
372
    /**
373
     * Set's the module instances.
374
     *
375
     * @param \Traversable $modules The modules instances
376
     *
377
     * @return void
378
     */
379
    public function setModules(\Traversable $modules)
380
    {
381
        $this->modules = $modules;
0 ignored issues
show
Documentation Bug introduced by
It seems like $modules of type object<Traversable> is incompatible with the declared type array<integer,object<Tec...dules\ModuleInterface>> of property $modules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
382
    }
383
384
    /**
385
     * Return's the module instances.
386
     *
387
     * @return \Traversable The module instances
388
     */
389
    public function getModules()
390
    {
391
        return $this->modules;
392
    }
393
394
    /**
395
     * Set's the PID file handler instance.
396
     *
397
     * @param \TechDivision\Import\Handlers\PidFileHandlerInterface $pidFileHandler The PID file handler instance
398
     *
399
     * @return void
400
     */
401
    public function setPidFileHandler(PidFileHandlerInterface $pidFileHandler) : void
402
    {
403
        $this->pidFileHanlder = $pidFileHandler;
404
    }
405
406
    /**
407
     * Return's the PID file handler instance.
408
     *
409
     * @return \TechDivision\Import\Handlers\PidFileHandlerInterface The PID file handler instance
410
     */
411
    public function getPidFileHandler() : PidFileHandlerInterface
412
    {
413
        return $this->pidFileHanlder;
414
    }
415
416
    /**
417
     * Set's the generic file handler instance.
418
     *
419
     * @param \TechDivision\Import\Handlers\GenericFileHandlerInterface $genericFileHandler The generic file handler instance
420
     *
421
     * @return void
422
     */
423
    public function setGenericFileHandler(GenericFileHandlerInterface $genericFileHandler) : void
424
    {
425
        $this->genericFileHandler = $genericFileHandler;
0 ignored issues
show
Bug introduced by
The property genericFileHandler does not seem to exist. Did you mean genericFileHanlder?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
426
    }
427
428
    /**
429
     * Return's the generic file handler instance.
430
     *
431
     * @return \TechDivision\Import\Handlers\GenericFileHandlerInterface The generic file handler instance
432
     */
433
    public function getGenericFileHandler() : GenericFileHandlerInterface
434
    {
435
        return $this->genericFileHandler;
0 ignored issues
show
Bug introduced by
The property genericFileHandler does not seem to exist. Did you mean genericFileHanlder?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
436
    }
437
438
    /**
439
     * Return's the logger with the passed name, by default the system logger.
440
     *
441
     * @param string $name The name of the requested system logger
442
     *
443
     * @return \Psr\Log\LoggerInterface The logger instance
444
     * @throws \Exception Is thrown, if the requested logger is NOT available
445
     */
446
    public function getSystemLogger($name = LoggerKeys::SYSTEM)
447
    {
448
449
        // query whether or not, the requested logger is available
450
        if (isset($this->systemLoggers[$name])) {
451
            return $this->systemLoggers[$name];
452
        }
453
454
        // throw an exception if the requested logger is NOT available
455
        throw new \Exception(
456
            sprintf(
457
                'The requested logger \'%s\' is not available',
458
                $name
459
            )
460
        );
461
    }
462
463
    /**
464
     * Returns the actual application version.
465
     *
466
     * @return string The application's version
467
     */
468
    public function getVersion()
469
    {
470
        return $this->getContainer()->get(DependencyInjectionKeys::APPLICATION)->getVersion();
471
    }
472
473
    /**
474
     * Returns the actual application name.
475
     *
476
     * @return string The application's name
477
     */
478
    public function getName()
479
    {
480
        return $this->getContainer()->get(DependencyInjectionKeys::APPLICATION)->getName();
481
    }
482
483
    /**
484
     * Query whether or not the system logger with the passed name is available.
485
     *
486
     * @param string $name The name of the requested system logger
487
     *
488
     * @return boolean TRUE if the logger with the passed name exists, else FALSE
489
     */
490
    public function hasSystemLogger($name = LoggerKeys::SYSTEM)
491
    {
492
        return isset($this->systemLoggers[$name]);
493
    }
494
495
    /**
496
     * Return's the array with the system logger instances.
497
     *
498
     * @return \Doctrine\Common\Collections\Collection The logger instance
499
     */
500
    public function getSystemLoggers()
501
    {
502
        return $this->systemLoggers;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->systemLoggers; (Doctrine\Common\Collections\Collection) is incompatible with the return type declared by the interface TechDivision\Import\Appl...rface::getSystemLoggers of type array.

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...
503
    }
504
505
    /**
506
     * Return's the unique serial for this import process.
507
     *
508
     * @return string The unique serial
509
     */
510
    public function getSerial()
511
    {
512
        return $this->serial;
513
    }
514
515
    /**
516
     * The shutdown handler to catch fatal errors.
517
     *
518
     * This method is need to make sure, that an existing PID file will be removed
519
     * if a fatal error has been triggered.
520
     *
521
     * @return void
522
     */
523
    public function shutdown()
524
    {
525
526
        // check if there was a fatal error caused shutdown
527
        if ($lastError = error_get_last()) {
528
            // initialize error type and message
529
            $type = 0;
530
            $message = '';
531
            // extract the last error values
532
            extract($lastError);
533
            // query whether we've a fatal/user error
534
            if ($type === E_ERROR || $type === E_USER_ERROR) {
535
                // clean-up the PID file
536
                $this->unlock();
537
                // log the fatal error message
538
                $this->log($message, LogLevel::ERROR);
539
            }
540
        }
541
    }
542
543
    /**
544
     * Persist the UUID of the actual import process to the PID file.
545
     *
546
     * @return void
547
     * @throws \Exception Is thrown, if the PID can not be locked or the PID can not be added
548
     * @throws \TechDivision\Import\Exceptions\ImportAlreadyRunningException Is thrown, if a import process is already running
549
     */
550
    public function lock()
551
    {
552
        $this->getPidFileHandler()->lock();
553
    }
554
555
    /**
556
     * Remove's the UUID of the actual import process from the PID file.
557
     *
558
     * @return void
559
     * @throws \Exception Is thrown, if the PID can not be removed
560
     */
561
    public function unlock()
562
    {
563
        $this->getPidFileHandler()->unlock();
564
    }
565
566
    /**
567
     * Remove's the passed line from the file with the passed name.
568
     *
569
     * @param string   $line The line to be removed
570
     * @param resource $fh   The file handle of the file the line has to be removed
571
     *
572
     * @return void
573
     * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed
574
     * @deprecated Since version 17.0.0
575
     * @see \TechDivision\Import\Handlers\GenericFileHandler::removeLineFromFile()
576
     */
577
    public function removeLineFromFile($line, $fh)
578
    {
579
580
        // delegate the invocation to the generic file handler's method
581
        $this->getGenericFileHandler()->removeLineFromFile($line, $fh);
582
583
        // log a message that this method has been deprecated now
584
        $this->log(
585
            sprintf('Method "%s" has been deprecated since version 17.0.0, use  \TechDivision\Import\Handlers\GenericFileHandler::removeLineFromFile() instead', __METHOD__),
586
            LogLevel::WARNING
587
        );
588
    }
589
590
    /**
591
     * Process the given operation.
592
     *
593
     * @param string $serial The unique serial of the actual import process
594
     *
595
     * @return null|int null or 0 if everything went fine, or an error code
596
     * @throws \Exception Is thrown if the operation can't be finished successfully
597
     */
598
    public function process($serial)
599
    {
600
601
        try {
602
            // track the start time
603
            $startTime = microtime(true);
604
605
            // set the serial for this import process
606
            $this->serial = $serial;
607
608
            // invoke the event that has to be fired before the application start's the transaction
609
            // (if single transaction mode has been activated)
610
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_START, $this);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
611
612
            // start the transaction, if single transaction mode has been configured
613
            if ($this->getConfiguration()->isSingleTransaction()) {
614
                $this->getImportProcessor()->getConnection()->beginTransaction();
615
            }
616
617
            // prepare the global data for the import process
618
            $this->setUp();
619
620
            // process the modules
621
            foreach ($this->getModules() as $module) {
622
                $module->process();
623
            }
624
625
            // commit the transaction, if single transation mode has been configured
626
            if ($this->getConfiguration()->isSingleTransaction()) {
627
                $this->getImportProcessor()->getConnection()->commit();
628
            }
629
630
            // track the time needed for the import in seconds
631
            $endTime = microtime(true) - $startTime;
632
633
            // log a debug message that import has been finished
634
            $this->getSystemLogger()->info(sprintf('Execution time for operation with serial %s in %f s', $this->getSerial(), $endTime));
635
636
            // invoke the event that has to be fired before the application has the transaction
637
            // committed successfully (if single transaction mode has been activated)
638
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_SUCCESS, $this);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
639
        } catch (ApplicationFinishedException $afe) {
0 ignored issues
show
Bug introduced by
The class TechDivision\Import\Exce...cationFinishedException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
640
            // if a PID has been set (because CSV files has been found),
641
            // remove it from the PID file to unlock the importer
642
            $this->unlock();
643
644
            if ($afe->getMessage()) {
645
                $this->log($afe->getMessage(), LogLevel::NOTICE);
646
            }
647
            return 0;
648
        } catch (ApplicationStoppedException $ase) {
649
            // rollback the transaction, if single transaction mode has been configured
650
            if ($this->getConfiguration()->isSingleTransaction()) {
651
                $this->getImportProcessor()->getConnection()->rollBack();
652
            }
653
654
            // invoke the event that has to be fired after the application rollbacked the
655
            // transaction (if single transaction mode has been activated)
656
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FAILURE, $this, $ase);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
657
658
            // finally, if a PID has been set (because CSV files has been found),
659
            // remove it from the PID file to unlock the importer
660
            $this->unlock();
661
662
            // track the time needed for the import in seconds
663
            $endTime = microtime(true) - $startTime;
664
665
            // log a message that the file import failed
666
            foreach ($this->systemLoggers as $systemLogger) {
667
                $systemLogger->error($ase->__toString());
668
            }
669
670
            // log a message that import has been finished
671
            $this->getSystemLogger()->warning(sprintf('Can\'t finish import with serial %s in %f s', $this->getSerial(), $endTime));
672
673
            // log the exception message as warning
674
            $this->log($ase->getMessage(), LogLevel::WARNING);
675
676
            // return 1 to signal an error
677
            return 1;
678
        } catch (ImportAlreadyRunningException $iare) {
679
            // rollback the transaction, if single transaction mode has been configured
680
            if ($this->getConfiguration()->isSingleTransaction()) {
681
                $this->getImportProcessor()->getConnection()->rollBack();
682
            }
683
684
            // invoke the event that has to be fired after the application rollbacked the
685
            // transaction (if single transaction mode has been activated)
686
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FAILURE, $this, $iare);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
687
688
            // finally, if a PID has been set (because CSV files has been found),
689
            // remove it from the PID file to unlock the importer
690
            $this->unlock();
691
692
            // track the time needed for the import in seconds
693
            $endTime = microtime(true) - $startTime;
694
695
            // log a warning, because another import process is already running
696
            $this->getSystemLogger()->warning($iare->__toString());
697
698
            // log a message that import has been finished
699
            $this->getSystemLogger()->warning(sprintf('Can\'t finish import with serial because another import process is running %s in %f s', $this->getSerial(), $endTime));
700
701
            // log the exception message as warning
702
            $this->log($iare->getMessage(), LogLevel::WARNING);
703
704
            // return 1 to signal an error
705
            return 1;
706
        } catch (\Exception $e) {
707
            // rollback the transaction, if single transaction mode has been configured
708
            if ($this->getConfiguration()->isSingleTransaction()) {
709
                $this->getImportProcessor()->getConnection()->rollBack();
710
            }
711
712
            // invoke the event that has to be fired after the application rollbacked the
713
            // transaction (if single transaction mode has been activated)
714
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FAILURE, $this, $e);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
715
716
            // finally, if a PID has been set (because CSV files has been found),
717
            // remove it from the PID file to unlock the importer
718
            $this->unlock();
719
720
            // track the time needed for the import in seconds
721
            $endTime = microtime(true) - $startTime;
722
723
            // log a message that the file import failed
724
            foreach ($this->systemLoggers as $systemLogger) {
725
                $systemLogger->error($e->__toString());
726
            }
727
728
            // log a message that import has been finished
729
            $this->getSystemLogger()->error(sprintf('Can\'t finish import with serial %s in %f s', $this->getSerial(), $endTime));
730
731
            // log the exception message as warning
732
            $this->log($e->getMessage(), LogLevel::ERROR);
733
734
            // return 1 to signal an error
735
            return 1;
736
        } finally {
737
            // tear down
738
            $this->tearDown();
739
740
            // invoke the event that has to be fired after the application transaction has been finished
741
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FINISHED, $this);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
742
        }
743
    }
744
745
    /**
746
     * Stop processing the operation.
747
     *
748
     * @param string $reason The reason why the operation has been stopped
749
     *
750
     * @return void
751
     * @throws \TechDivision\Import\Exceptions\ApplicationStoppedException Is thrown if the application has been stopped
752
     */
753
    public function stop($reason)
754
    {
755
756
        // stop processing the plugins by setting the flag to TRUE
757
        $this->stopped = true;
758
759
        // throw the exeception
760
        throw new ApplicationStoppedException($reason);
761
    }
762
763
    /**
764
     * Finish processing the operation. The application will be stopped without an error output.
765
     *
766
     * @param string $reason The reason why the operation has been finish
767
     *
768
     * @return void
769
     * @throws \TechDivision\Import\Exceptions\ApplicationFinishedException Is thrown if the application has been finish
770
     */
771
    public function finish($reason = '')
772
    {
773
        $this->stopped = true;
774
        throw new ApplicationFinishedException($reason);
775
    }
776
777
    /**
778
     * Return's TRUE if the operation has been stopped, else FALSE.
779
     *
780
     * @return boolean TRUE if the process has been stopped, else FALSE
781
     */
782
    public function isStopped()
783
    {
784
        return $this->stopped;
785
    }
786
787
    /**
788
     * Gets a service.
789
     *
790
     * @param string $id The service identifier
791
     *
792
     * @return object The associated service
793
     *
794
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException When a circular reference is detected
795
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException          When the service is not defined
796
     */
797
    public function get($id)
798
    {
799
        return $this->getContainer()->get($id);
800
    }
801
802
    /**
803
     * Returns true if the container can return an entry for the given identifier.
804
     * Returns false otherwise.
805
     *
806
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
807
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
808
     *
809
     * @param string $id Identifier of the entry to look for.
810
     *
811
     * @return bool
812
     */
813
    public function has($id)
814
    {
815
        return $this->getContainer()->has($id);
816
    }
817
818
    /**
819
     * Lifecycle callback that will be inovked before the
820
     * import process has been started.
821
     *
822
     * @return void
823
     */
824
    protected function setUp()
825
    {
826
        $this->getEmitter()->emit(EventNames::APP_SET_UP, $this);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
827
    }
828
829
    /**
830
     * Lifecycle callback that will be inovked after the
831
     * import process has been finished.
832
     *
833
     * @return void
834
     */
835
    protected function tearDown()
836
    {
837
        $this->getEmitter()->emit(EventNames::APP_TEAR_DOWN, $this);
0 ignored issues
show
Unused Code introduced by
The call to EmitterInterface::emit() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
838
    }
839
840
    /**
841
     * Simple method that writes the passed method the the console and the
842
     * system logger, if configured and a log level has been passed.
843
     *
844
     * @param string $msg      The message to log
845
     * @param string $logLevel The log level to use
846
     *
847
     * @return void
848
     */
849
    public function log($msg, $logLevel = null)
850
    {
851
852
        // initialize the formatter helper
853
        $helper = new FormatterHelper();
854
855
        // map the log level to the console style
856
        $style = $this->mapLogLevelToStyle($logLevel);
857
858
        // format the message, according to the passed log level and write it to the console
859
        $this->getOutput()->writeln($logLevel ? $helper->formatBlock($msg, $style) : $msg);
860
861
        // log the message if a log level has been passed
862
        if ($logLevel && $systemLogger = $this->getSystemLogger()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $logLevel of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
863
            $systemLogger->log($logLevel, $msg);
864
        }
865
    }
866
867
    /**
868
     * Map's the passed log level to a valid symfony console style.
869
     *
870
     * @param string $logLevel The log level to map
871
     *
872
     * @return string The apropriate symfony console style
873
     */
874
    protected function mapLogLevelToStyle($logLevel)
875
    {
876
877
        // query whether or not the log level is mapped
878
        if (isset($this->logLevelStyleMapping[$logLevel])) {
879
            return $this->logLevelStyleMapping[$logLevel];
880
        }
881
882
        // return the default style => info
883
        return Simple::DEFAULT_STYLE;
884
    }
885
886
    /**
887
     * Return's the PID filename to use.
888
     *
889
     * @return string The PID filename
890
     */
891
    protected function getPidFilename()
892
    {
893
        return $this->getConfiguration()->getPidFilename();
894
    }
895
}
896