Completed
Pull Request — master (#16)
by
unknown
04:07
created

Simple::removeLineFromFile()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 42
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 8.439
c 0
b 0
f 0
cc 6
eloc 17
nc 12
nop 2
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 Rhumsaa\Uuid\Uuid;
25
use League\Event\EmitterInterface;
26
use Doctrine\Common\Collections\Collection;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\Console\Helper\FormatterHelper;
29
use Symfony\Component\DependencyInjection\TaggedContainerInterface;
30
use TechDivision\Import\Utils\LoggerKeys;
31
use TechDivision\Import\Utils\EventNames;
32
use TechDivision\Import\Utils\RegistryKeys;
33
use TechDivision\Import\App\Utils\DependencyInjectionKeys;
34
use TechDivision\Import\ApplicationInterface;
35
use TechDivision\Import\ConfigurationInterface;
36
use TechDivision\Import\Plugins\PluginFactoryInterface;
37
use TechDivision\Import\Exceptions\LineNotFoundException;
38
use TechDivision\Import\Exceptions\FileNotFoundException;
39
use TechDivision\Import\Exceptions\ImportAlreadyRunningException;
40
use TechDivision\Import\Services\ImportProcessorInterface;
41
use TechDivision\Import\Services\RegistryProcessorInterface;
42
43
/**
44
 * The M2IF - Simple Application implementation.
45
 *
46
 * This is a example application implementation that should give developers an impression
47
 * on how the M2IF could be used to implement their own Magento 2 importer.
48
 *
49
 * @author    Tim Wagner <[email protected]>
50
 * @copyright 2016 TechDivision GmbH <[email protected]>
51
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
52
 * @link      https://github.com/techdivision/import-app-simple
53
 * @link      http://www.techdivision.com
54
 */
55
class Simple implements ApplicationInterface
56
{
57
58
    /**
59
     * The default style to write messages to the symfony console.
60
     *
61
     * @var string
62
     */
63
    const DEFAULT_STYLE = 'info';
64
65
    /**
66
     * The TechDivision company name as ANSI art.
67
     *
68
     * @var string
69
     */
70
    protected $ansiArt = ' _______        _     _____  _       _     _
71
|__   __|      | |   |  __ \(_)     (_)   (_)
72
   | | ___  ___| |__ | |  | |___   ___ ___ _  ___  _ __
73
   | |/ _ \/ __| \'_ \| |  | | \ \ / / / __| |/ _ \| \'_ \
74
   | |  __/ (__| | | | |__| | |\ V /| \__ \ | (_) | | | |
75
   |_|\___|\___|_| |_|_____/|_| \_/ |_|___/_|\___/|_| |_|
76
';
77
78
    /**
79
     * The log level => console style mapping.
80
     *
81
     * @var array
82
     */
83
    protected $logLevelStyleMapping = array(
84
        LogLevel::INFO      => 'info',
85
        LogLevel::DEBUG     => 'comment',
86
        LogLevel::ERROR     => 'error',
87
        LogLevel::ALERT     => 'error',
88
        LogLevel::CRITICAL  => 'error',
89
        LogLevel::EMERGENCY => 'error',
90
        LogLevel::WARNING   => 'error',
91
        LogLevel::NOTICE    => 'info'
92
    );
93
94
    /**
95
     * The PID for the running processes.
96
     *
97
     * @var array
98
     */
99
    protected $pid;
100
101
    /**
102
     * The actions unique serial.
103
     *
104
     * @var string
105
     */
106
    protected $serial;
107
108
    /**
109
     * The array with the system logger instances.
110
     *
111
     * @var \Doctrine\Common\Collections\Collection
112
     */
113
    protected $systemLoggers;
114
115
    /**
116
     * The RegistryProcessor instance to handle running threads.
117
     *
118
     * @var \TechDivision\Import\Services\RegistryProcessorInterface
119
     */
120
    protected $registryProcessor;
121
122
    /**
123
     * The processor to read/write the necessary import data.
124
     *
125
     * @var \TechDivision\Import\Services\ImportProcessorInterface
126
     */
127
    protected $importProcessor;
128
129
    /**
130
     * The DI container builder instance.
131
     *
132
     * @var \Symfony\Component\DependencyInjection\TaggedContainerInterface
133
     */
134
    protected $container;
135
136
    /**
137
     * The system configuration.
138
     *
139
     * @var \TechDivision\Import\ConfigurationInterface
140
     */
141
    protected $configuration;
142
143
    /**
144
     * The output stream to write console information to.
145
     *
146
     * @var \Symfony\Component\Console\Output\OutputInterface
147
     */
148
    protected $output;
149
150
    /**
151
     * The plugins to be processed.
152
     *
153
     * @var array
154
     */
155
    protected $plugins = array();
156
157
    /**
158
     * The flag that stop's processing the operation.
159
     *
160
     * @var boolean
161
     */
162
    protected $stopped = false;
163
164
    /**
165
     * The filehandle for the PID file.
166
     *
167
     * @var resource
168
     */
169
    protected $fh;
170
171
    /**
172
     * The plugin factory instance.
173
     *
174
     * @var \TechDivision\Import\Plugins\PluginFactoryInterface
175
     */
176
    protected $pluginFactory;
177
178
    /**
179
     * The event emitter instance.
180
     *
181
     * @var \League\Event\EmitterInterface
182
     */
183
    protected $emitter;
184
185
    /**
186
     * The constructor to initialize the instance.
187
     *
188
     * @param \Symfony\Component\DependencyInjection\TaggedContainerInterface $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\ConfigurationInterface                     $configuration     The system configuration
192
     * @param \TechDivision\Import\Plugins\PluginFactoryInterface             $pluginFactory     The plugin factory instance
193
     * @param \Symfony\Component\Console\Output\OutputInterface               $output            The output instance
194
     * @param \Doctrine\Common\Collections\Collection                         $systemLoggers     The array with the system logger instances
195
     * @param \League\Event\EmitterInterface                                  $emitter           The event emitter instance
196
     */
197
    public function __construct(
198
        TaggedContainerInterface $container,
199
        RegistryProcessorInterface $registryProcessor,
200
        ImportProcessorInterface $importProcessor,
201
        ConfigurationInterface $configuration,
202
        PluginFactoryInterface $pluginFactory,
203
        OutputInterface $output,
204
        Collection $systemLoggers,
205
        EmitterInterface $emitter
206
    ) {
207
208
        // register the shutdown function
209
        register_shutdown_function(array($this, 'shutdown'));
210
211
        // initialize the instance with the passed values
212
        $this->setOutput($output);
213
        $this->setEmitter($emitter);
214
        $this->setContainer($container);
215
        $this->setConfiguration($configuration);
216
        $this->setSystemLoggers($systemLoggers);
217
        $this->setPluginFactory($pluginFactory);
218
        $this->setImportProcessor($importProcessor);
219
        $this->setRegistryProcessor($registryProcessor);
220
    }
221
222
    /**
223
     * Set's the event emitter instance.
224
     *
225
     * @param \League\Event\EmitterInterface $emitter The event emitter instance
226
     *
227
     * @return void
228
     */
229
    public function setEmitter(EmitterInterface $emitter)
230
    {
231
        $this->emitter = $emitter;
232
    }
233
234
    /**
235
     * Return's the event emitter instance.
236
     *
237
     * @return \League\Event\EmitterInterface The event emitter instance
238
     */
239
    public function getEmitter()
240
    {
241
        return $this->emitter;
242
    }
243
244
    /**
245
     * Set's the container instance.
246
     *
247
     * @param \Symfony\Component\DependencyInjection\TaggedContainerInterface $container The container instance
248
     *
249
     * @return void
250
     */
251
    public function setContainer(TaggedContainerInterface $container)
252
    {
253
        $this->container = $container;
254
    }
255
256
    /**
257
     * Return's the container instance.
258
     *
259
     * @return \Symfony\Component\DependencyInjection\TaggedContainerInterface The container instance
260
     */
261
    public function getContainer()
262
    {
263
        return $this->container;
264
    }
265
266
    /**
267
     * Set's the output stream to write console information to.
268
     *
269
     * @param \Symfony\Component\Console\Output\OutputInterface $output The output stream
270
     *
271
     * @return void
272
     */
273
    public function setOutput(OutputInterface $output)
274
    {
275
        $this->output = $output;
276
    }
277
278
    /**
279
     * Return's the output stream to write console information to.
280
     *
281
     * @return \Symfony\Component\Console\Output\OutputInterface The output stream
282
     */
283
    public function getOutput()
284
    {
285
        return $this->output;
286
    }
287
288
    /**
289
     * Set's the system configuration.
290
     *
291
     * @param \TechDivision\Import\ConfigurationInterface $configuration The system configuration
292
     *
293
     * @return void
294
     */
295
    public function setConfiguration(ConfigurationInterface $configuration)
296
    {
297
        $this->configuration = $configuration;
298
    }
299
300
    /**
301
     * Return's the system configuration.
302
     *
303
     * @return \TechDivision\Import\ConfigurationInterface The system configuration
304
     */
305
    public function getConfiguration()
306
    {
307
        return $this->configuration;
308
    }
309
310
    /**
311
     * Set's the RegistryProcessor instance to handle the running threads.
312
     *
313
     * @param \TechDivision\Import\Services\RegistryProcessor $registryProcessor The registry processor instance
314
     *
315
     * @return void
316
     */
317
    public function setRegistryProcessor(RegistryProcessorInterface $registryProcessor)
318
    {
319
        $this->registryProcessor = $registryProcessor;
320
    }
321
322
    /**
323
     * Return's the RegistryProcessor instance to handle the running threads.
324
     *
325
     * @return \TechDivision\Import\Services\RegistryProcessor The registry processor instance
326
     */
327
    public function getRegistryProcessor()
328
    {
329
        return $this->registryProcessor;
330
    }
331
332
    /**
333
     * Set's the import processor instance.
334
     *
335
     * @param \TechDivision\Import\Services\ImportProcessorInterface $importProcessor The import processor instance
336
     *
337
     * @return void
338
     */
339
    public function setImportProcessor(ImportProcessorInterface $importProcessor)
340
    {
341
        $this->importProcessor = $importProcessor;
342
    }
343
344
    /**
345
     * Return's the import processor instance.
346
     *
347
     * @return \TechDivision\Import\Services\ImportProcessorInterface The import processor instance
348
     */
349
    public function getImportProcessor()
350
    {
351
        return $this->importProcessor;
352
    }
353
354
    /**
355
     * The array with the system loggers.
356
     *
357
     * @param \Doctrine\Common\Collections\Collection $systemLoggers The system logger instances
358
     *
359
     * @return void
360
     */
361
    public function setSystemLoggers(Collection $systemLoggers)
362
    {
363
        $this->systemLoggers = $systemLoggers;
364
    }
365
366
    /**
367
     * Set's the plugin factory instance.
368
     *
369
     * @param \TechDivision\Import\Plugins\PluginFactoryInterface $pluginFactory The plugin factory instance
370
     *
371
     * @return void
372
     */
373
    public function setPluginFactory(PluginFactoryInterface $pluginFactory)
374
    {
375
        $this->pluginFactory = $pluginFactory;
376
    }
377
378
    /**
379
     * Return's the plugin factory instance.
380
     *
381
     * @return \TechDivision\Import\Plugins\PluginFactoryInterface The plugin factory instance
382
     */
383
    public function getPluginFactory()
384
    {
385
        return $this->pluginFactory;
386
    }
387
388
    /**
389
     * Return's the logger with the passed name, by default the system logger.
390
     *
391
     * @param string $name The name of the requested system logger
392
     *
393
     * @return \Psr\Log\LoggerInterface The logger instance
394
     * @throws \Exception Is thrown, if the requested logger is NOT available
395
     */
396
    public function getSystemLogger($name = LoggerKeys::SYSTEM)
397
    {
398
399
        // query whether or not, the requested logger is available
400
        if (isset($this->systemLoggers[$name])) {
401
            return $this->systemLoggers[$name];
402
        }
403
404
        // throw an exception if the requested logger is NOT available
405
        throw new \Exception(
406
            sprintf(
407
                'The requested logger \'%s\' is not available',
408
                $name
409
            )
410
        );
411
    }
412
413
    /**
414
     * Query whether or not the system logger with the passed name is available.
415
     *
416
     * @param string $name The name of the requested system logger
417
     *
418
     * @return boolean TRUE if the logger with the passed name exists, else FALSE
419
     */
420
    public function hasSystemLogger($name = LoggerKeys::SYSTEM)
421
    {
422
        return isset($this->systemLoggers[$name]);
423
    }
424
425
    /**
426
     * Return's the array with the system logger instances.
427
     *
428
     * @return \Doctrine\Common\Collections\Collection The logger instance
429
     */
430
    public function getSystemLoggers()
431
    {
432
        return $this->systemLoggers;
433
    }
434
435
    /**
436
     * Return's the unique serial for this import process.
437
     *
438
     * @return string The unique serial
439
     */
440
    public function getSerial()
441
    {
442
        return $this->serial;
443
    }
444
445
    /**
446
     * The shutdown handler to catch fatal errors.
447
     *
448
     * This method is need to make sure, that an existing PID file will be removed
449
     * if a fatal error has been triggered.
450
     *
451
     * @return void
452
     */
453
    public function shutdown()
454
    {
455
456
        // check if there was a fatal error caused shutdown
457
        if ($lastError = error_get_last()) {
458
            // initialize error type and message
459
            $type = 0;
460
            $message = '';
461
            // extract the last error values
462
            extract($lastError);
463
            // query whether we've a fatal/user error
464
            if ($type === E_ERROR || $type === E_USER_ERROR) {
465
                // clean-up the PID file
466
                $this->unlock();
467
                // log the fatal error message
468
                $this->log($message, LogLevel::ERROR);
469
            }
470
        }
471
    }
472
473
    /**
474
     * Persist the UUID of the actual import process to the PID file.
475
     *
476
     * @return void
477
     * @throws \Exception Is thrown, if the PID can not be locked or the PID can not be added
478
     * @throws \TechDivision\Import\Exceptions\ImportAlreadyRunningException Is thrown, if a import process is already running
479
     */
480
    public function lock()
481
    {
482
483
        // query whether or not, the PID has already been set
484
        if ($this->pid === $this->getSerial()) {
485
            return;
486
        }
487
488
        // if not, initialize the PID
489
        $this->pid = $this->getSerial();
490
491
        // open the PID file
492
        $this->fh = fopen($filename = $this->getPidFilename(), 'a+');
493
494
        // try to lock the PID file exclusive
495
        if (!flock($this->fh, LOCK_EX|LOCK_NB)) {
496
            throw new ImportAlreadyRunningException(sprintf('PID file %s is already in use', $filename));
497
        }
498
499
        // append the PID to the PID file
500
        if (fwrite($this->fh, $this->pid . PHP_EOL) === false) {
501
            throw new \Exception(sprintf('Can\'t write PID %s to PID file %s', $this->pid, $filename));
502
        }
503
    }
504
505
    /**
506
     * Remove's the UUID of the actual import process from the PID file.
507
     *
508
     * @return void
509
     * @throws \Exception Is thrown, if the PID can not be removed
510
     */
511
    public function unlock()
512
    {
513
        try {
514
            // remove the PID from the PID file if set
515
            if ($this->pid === $this->getSerial() && is_resource($this->fh)) {
516
                // remove the PID from the file
517
                $this->removeLineFromFile($this->pid, $this->fh);
518
519
                // finally unlock/close the PID file
520
                flock($this->fh, LOCK_UN);
521
                fclose($this->fh);
522
523
                // if the PID file is empty, delete the file
524
                if (filesize($filename = $this->getPidFilename()) === 0) {
525
                    unlink($filename);
526
                }
527
            }
528
529
        } catch (FileNotFoundException $fnfe) {
530
            $this->getSystemLogger()->notice(sprintf('PID file %s doesn\'t exist', $this->getPidFilename()));
531
        } catch (LineNotFoundException $lnfe) {
532
            $this->getSystemLogger()->notice(sprintf('PID %s is can not be found in PID file %s', $this->pid, $this->getPidFilename()));
533
        } catch (\Exception $e) {
534
            throw new \Exception(sprintf('Can\'t remove PID %s from PID file %s', $this->pid, $this->getPidFilename()), null, $e);
535
        }
536
    }
537
538
    /**
539
     * Remove's the passed line from the file with the passed name.
540
     *
541
     * @param string   $line The line to be removed
542
     * @param resource $fh   The file handle of the file the line has to be removed
543
     *
544
     * @return void
545
     * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed
546
     */
547
    public function removeLineFromFile($line, $fh)
548
    {
549
550
        // initialize the array for the PIDs found in the PID file
551
        $lines = array();
552
553
        // initialize the flag if the line has been found
554
        $found = false;
555
556
        // rewind the file pointer
557
        rewind($fh);
558
559
        // read the lines with the PIDs from the PID file
560
        while (($buffer = fgets($fh, 4096)) !== false) {
561
            // remove the new line
562
            $buffer = trim($buffer);
563
            // if the line is the one to be removed, ignore the line
564
            if ($line === $buffer) {
565
                $found = true;
566
                continue;
567
            }
568
569
            // add the found PID to the array
570
            $lines[] = $buffer;
571
        }
572
573
        // query whether or not, we found the line
574
        if (!$found) {
575
            throw new LineNotFoundException(sprintf('Line %s can not be found', $line));
576
        }
577
578
        // empty the file and rewind the file pointer
579
        ftruncate($fh, 0);
580
        rewind($fh);
581
582
        // append the existing lines to the file
583
        foreach ($lines as $ln) {
584
            if (fwrite($fh, $ln . PHP_EOL) === false) {
585
                throw new \Exception(sprintf('Can\'t write %s to file', $ln));
586
            }
587
        }
588
    }
589
590
    /**
591
     * Process the given operation.
592
     *
593
     * @return void
594
     * @throws \Exception Is thrown if the operation can't be finished successfully
595
     */
596
    public function process()
597
    {
598
599
        try {
600
            // track the start time
601
            $startTime = microtime(true);
602
603
            // invoke the event that has to be fired before the application start's the transaction
604
            // (if single transaction mode has been activated)
605
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_START, $this);
606
607
            // start the transaction, if single transaction mode has been configured
608
            if ($this->getConfiguration()->isSingleTransaction()) {
609
                $this->getImportProcessor()->getConnection()->beginTransaction();
610
            }
611
612
            // prepare the global data for the import process
613
            $this->setUp();
614
615
            // process the plugins defined in the configuration
616
            /** @var \TechDivision\Import\Configuration\PluginConfigurationInterface $pluginConfiguration */
617
            foreach ($this->getConfiguration()->getPlugins() as $pluginConfiguration) {
618
                // query whether or not the operation has been stopped
619
                if ($this->isStopped()) {
620
                    break;
621
                }
622
                // process the plugin if not
623
                $this->pluginFactory->createPlugin($pluginConfiguration)->process();
624
            }
625
626
            // tear down the  instance
627
            $this->tearDown();
628
629
            // commit the transaction, if single transation mode has been configured
630
            if ($this->getConfiguration()->isSingleTransaction()) {
631
                $this->getImportProcessor()->getConnection()->commit();
632
            }
633
634
            // track the time needed for the import in seconds
635
            $endTime = microtime(true) - $startTime;
636
637
            // log a message that import has been finished
638
            $this->log(
639
                sprintf(
640
                    'Successfully finished import with serial %s in %f s',
641
                    $this->getSerial(),
642
                    $endTime
643
                ),
644
                LogLevel::INFO
645
            );
646
647
            // invoke the event that has to be fired before the application has the transaction
648
            // committed successfully (if single transaction mode has been activated)
649
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_SUCCESS, $this);
650
651
        } catch (ImportAlreadyRunningException $iare) {
652
            // tear down
653
            $this->tearDown();
654
655
            // rollback the transaction, if single transaction mode has been configured
656
            if ($this->getConfiguration()->isSingleTransaction()) {
657
                $this->getImportProcessor()->getConnection()->rollBack();
658
            }
659
660
            // invoke the event that has to be fired after the application rollbacked the
661
            // transaction (if single transaction mode has been activated)
662
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FAILURE, $this, $iare);
663
664
            // finally, if a PID has been set (because CSV files has been found),
665
            // remove it from the PID file to unlock the importer
666
            $this->unlock();
667
668
            // track the time needed for the import in seconds
669
            $endTime = microtime(true) - $startTime;
670
671
            // log a warning, because another import process is already running
672
            $this->getSystemLogger()->warning($iare->__toString());
673
674
            // log a message that import has been finished
675
            $this->getSystemLogger()->info(
676
                sprintf(
677
                    'Can\'t finish import with serial because another import process is running %s in %f s',
678
                    $this->getSerial(),
679
                    $endTime
680
                )
681
            );
682
683
            // re-throw the exception
684
            throw $iare;
685
686
        } catch (\Exception $e) {
687
            // tear down
688
            $this->tearDown();
689
690
            // rollback the transaction, if single transaction mode has been configured
691
            if ($this->getConfiguration()->isSingleTransaction()) {
692
                $this->getImportProcessor()->getConnection()->rollBack();
693
            }
694
695
            // invoke the event that has to be fired after the application rollbacked the
696
            // transaction (if single transaction mode has been activated)
697
            $this->getEmitter()->emit(EventNames::APP_PROCESS_TRANSACTION_FAILURE, $this, $e);
698
699
            // finally, if a PID has been set (because CSV files has been found),
700
            // remove it from the PID file to unlock the importer
701
            $this->unlock();
702
703
            // track the time needed for the import in seconds
704
            $endTime = microtime(true) - $startTime;
705
706
            // log a message that the file import failed
707
            foreach ($this->systemLoggers as $systemLogger) {
708
                $systemLogger->error($e->__toString());
709
            }
710
711
            // log a message that import has been finished
712
            $this->getSystemLogger()->info(
713
                sprintf(
714
                    'Can\'t finish import with serial %s in %f s',
715
                    $this->getSerial(),
716
                    $endTime
717
                )
718
            );
719
720
            // re-throw the exception
721
            throw $e;
722
        }
723
    }
724
725
    /**
726
     * Stop processing the operation.
727
     *
728
     * @param string $reason The reason why the operation has been stopped
729
     *
730
     * @return void
731
     */
732
    public function stop($reason)
733
    {
734
735
        // log a message that the operation has been stopped
736
        $this->log($reason, LogLevel::INFO);
737
738
        // stop processing the plugins by setting the flag to TRUE
739
        $this->stopped = true;
740
    }
741
742
    /**
743
     * Return's TRUE if the operation has been stopped, else FALSE.
744
     *
745
     * @return boolean TRUE if the process has been stopped, else FALSE
746
     */
747
    public function isStopped()
748
    {
749
        return $this->stopped;
750
    }
751
752
    /**
753
     * Gets a service.
754
     *
755
     * @param string $id The service identifier
756
     *
757
     * @return object The associated service
758
     *
759
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException When a circular reference is detected
760
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException          When the service is not defined
761
     */
762
    public function get($id)
763
    {
764
        return $this->getContainer()->get($id);
765
    }
766
767
    /**
768
     * Returns true if the container can return an entry for the given identifier.
769
     * Returns false otherwise.
770
     *
771
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
772
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
773
     *
774
     * @param string $id Identifier of the entry to look for.
775
     *
776
     * @return bool
777
     */
778
    public function has($id)
779
    {
780
        return $this->getContainer()->has($id);
781
    }
782
783
    /**
784
     * Lifecycle callback that will be inovked before the
785
     * import process has been started.
786
     *
787
     * @return void
788
     */
789
    protected function setUp()
790
    {
791
792
        // generate the serial for the new job
793
        $this->serial = Uuid::uuid4()->__toString();
794
795
        // write the TechDivision ANSI art icon to the console
796
        $this->log($this->ansiArt);
797
798
        // log the debug information, if debug mode is enabled
799
        if ($this->getConfiguration()->isDebugMode()) {
800
            // load the application from the DI container
801
            /** @var TechDivision\Import\App\Application $application */
802
            $application = $this->getContainer()->get(DependencyInjectionKeys::APPLICATION);
803
            // log the system's PHP configuration
804
            $this->log(sprintf('PHP version: %s', phpversion()), LogLevel::DEBUG);
805
            $this->log(sprintf('App version: %s', $application->getVersion()), LogLevel::DEBUG);
806
            $this->log('-------------------- Loaded Extensions -----------------------', LogLevel::DEBUG);
807
            $this->log(implode(', ', $loadedExtensions = get_loaded_extensions()), LogLevel::DEBUG);
808
            $this->log('--------------------------------------------------------------', LogLevel::DEBUG);
809
810
            // write a warning for low performance, if XDebug extension is activated
811
            if (in_array('xdebug', $loadedExtensions)) {
812
                $this->log('Low performance exptected, as result of enabled XDebug extension!', LogLevel::WARNING);
813
            }
814
        }
815
816
        // log a message that import has been started
817
        $this->log(
818
            sprintf(
819
                'Now start import with serial %s [%s => %s]',
820
                $this->getSerial(),
821
                $this->getConfiguration()->getEntityTypeCode(),
822
                $this->getConfiguration()->getOperationName()
823
            ),
824
            LogLevel::INFO
825
        );
826
827
        // initialize the status
828
        $status = array(
829
            RegistryKeys::STATUS => 1,
830
            RegistryKeys::BUNCHES => 0,
831
            RegistryKeys::SOURCE_DIRECTORY => $this->getConfiguration()->getSourceDir(),
832
            RegistryKeys::MISSING_OPTION_VALUES => array()
833
        );
834
835
        // append it to the registry
836
        $this->getRegistryProcessor()->setAttribute($this->getSerial(), $status);
837
    }
838
839
    /**
840
     * Lifecycle callback that will be inovked after the
841
     * import process has been finished.
842
     *
843
     * @return void
844
     */
845
    protected function tearDown()
846
    {
847
        $this->getRegistryProcessor()->removeAttribute($this->getSerial());
848
    }
849
850
    /**
851
     * Simple method that writes the passed method the the console and the
852
     * system logger, if configured and a log level has been passed.
853
     *
854
     * @param string $msg      The message to log
855
     * @param string $logLevel The log level to use
856
     *
857
     * @return void
858
     */
859
    protected function log($msg, $logLevel = null)
860
    {
861
862
        // initialize the formatter helper
863
        $helper = new FormatterHelper();
864
865
        // map the log level to the console style
866
        $style = $this->mapLogLevelToStyle($logLevel);
867
868
        // format the message, according to the passed log level and write it to the console
869
        $this->getOutput()->writeln($logLevel ? $helper->formatBlock($msg, $style) : $msg);
870
871
        // log the message if a log level has been passed
872
        $systemLogger = $this->getSystemLogger()
873
874
        if ($this->shouldBeLogged()) {
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_IF
Loading history...
875
            $systemLogger->log($logLevel, $msg);
876
        }
877
    }
878
879
    /**
880
     * Check if the message should be logged.
881
     *
882
     * @param \Psr\Log\LoggerInterface $logger      The logger instance
883
     * @param string                   $logLevel    The log level to use
884
     *
885
     * @return bool
886
     */
887
    protected function shouldBeLogged($logger, $logLevel)
888
    {
889
        $loggerAvailable = $logLevel && $logger;
890
        $debugMode = $this->getConfiguration()->isDebugMode();
891
        $isCritical = $logLevel === LogLevel::CRITICAL;
892
893
        return $loggerAvailable && (!$debugMode || $isCritical);
894
    }
895
896
    /**
897
     * Map's the passed log level to a valid symfony console style.
898
     *
899
     * @param string $logLevel The log level to map
900
     *
901
     * @return string The apropriate symfony console style
902
     */
903
    protected function mapLogLevelToStyle($logLevel)
904
    {
905
906
        // query whether or not the log level is mapped
907
        if (isset($this->logLevelStyleMapping[$logLevel])) {
908
            return $this->logLevelStyleMapping[$logLevel];
909
        }
910
911
        // return the default style => info
912
        return Simple::DEFAULT_STYLE;
913
    }
914
915
    /**
916
     * Return's the PID filename to use.
917
     *
918
     * @return string The PID filename
919
     */
920
    protected function getPidFilename()
921
    {
922
        return $this->getConfiguration()->getPidFilename();
923
    }
924
}
925