Completed
Push — master ( 39a3ca...d8a67a )
by Tim
10s
created

AbstractImportCommand::execute()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 84
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 84
ccs 0
cts 56
cp 0
rs 8.35
cc 5
eloc 43
nc 9
nop 2
crap 30

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * TechDivision\Import\Cli\Command\ImportCommandTrait
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-cli-simple
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Cli\Command;
22
23
use Rhumsaa\Uuid\Uuid;
24
use Psr\Log\LogLevel;
25
use Monolog\Logger;
26
use Monolog\Handler\ErrorLogHandler;
27
use Monolog\Handler\NativeMailerHandler;
28
use JMS\Serializer\SerializerBuilder;
29
use TechDivision\Import\Utils\LoggerKeys;
30
use TechDivision\Import\Cli\Simple;
31
use TechDivision\Import\Cli\Configuration;
32
use TechDivision\Import\Cli\Configuration\Database;
33
use TechDivision\Import\Cli\Configuration\LoggerFactory;
34
use TechDivision\Import\Cli\Services\ImportProcessorFactory;
35
use TechDivision\Import\Cli\Services\RegistryProcessorFactory;
36
use Symfony\Component\Console\Command\Command;
37
use Symfony\Component\Console\Input\InputOption;
38
use Symfony\Component\Console\Input\InputInterface;
39
use Symfony\Component\Console\Output\OutputInterface;
40
use Symfony\Component\Console\Input\InputArgument;
41
42
/**
43
 * The abstract import command implementation.
44
 *
45
 * @author    Tim Wagner <[email protected]>
46
 * @copyright 2016 TechDivision GmbH <[email protected]>
47
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
48
 * @link      https://github.com/techdivision/import-cli-simple
49
 * @link      http://www.techdivision.com
50
 */
51
abstract class AbstractImportCommand extends Command
52
{
53
54
    /**
55
     * Configures the current command.
56
     *
57
     * @return void
58
     * @see \Symfony\Component\Console\Command\Command::configure()
59
     */
60
    protected function configure()
61
    {
62
63
        // initialize the command with the required/optional options
64
        $this->addArgument(
65
            InputArgumentKeys::OPERATION_NAME,
66
            InputArgument::OPTIONAL,
67
            'The operation that has to be used for the import, one of "add-update", "replace" or "delete"'
68
        )
69
        ->addOption(
70
            InputOptionKeys::CONFIGURATION,
71
            null,
72
            InputOption::VALUE_REQUIRED,
73
            'Specify the pathname to the configuration file to use',
74
            sprintf('%s/techdivision-import.json', getcwd())
75
        )
76
        ->addOption(
77
            InputOptionKeys::INSTALLATION_DIR,
78
            null,
79
            InputOption::VALUE_REQUIRED,
80
            'The Magento installation directory to which the files has to be imported'
81
        )
82
        ->addOption(
83
            InputOptionKeys::SOURCE_DIR,
84
            null,
85
            InputOption::VALUE_REQUIRED,
86
            'The directory that has to be watched for new files'
87
        )
88
        ->addOption(
89
            InputOptionKeys::TARGET_DIR,
90
            null,
91
            InputOption::VALUE_REQUIRED,
92
            'The target directory with the files that has been imported'
93
        )
94
        ->addOption(
95
            InputOptionKeys::UTILITY_CLASS_NAME,
96
            null,
97
            InputOption::VALUE_REQUIRED,
98
            'The utility class name with the SQL statements'
99
        )
100
        ->addOption(
101
            InputOptionKeys::PREFIX,
102
            null,
103
            InputOption::VALUE_REQUIRED,
104
            'The prefix of the CSV source file(s) that has/have to be imported'
105
        )
106
        ->addOption(
107
            InputOptionKeys::MAGENTO_EDITION,
108
            null,
109
            InputOption::VALUE_REQUIRED,
110
            'The Magento edition to be used, either one of CE or EE'
111
        )
112
        ->addOption(
113
            InputOptionKeys::MAGENTO_VERSION,
114
            null,
115
            InputOption::VALUE_REQUIRED,
116
            'The Magento version to be used, e. g. 2.1.2'
117
        )
118
        ->addOption(
119
            InputOptionKeys::SOURCE_DATE_FORMAT,
120
            null,
121
            InputOption::VALUE_REQUIRED,
122
            'The date format used in the CSV file(s)'
123
        )
124
        ->addOption(
125
            InputOptionKeys::USE_DB_ID,
126
            null,
127
            InputOption::VALUE_REQUIRED,
128
            'The explicit database ID used for the actual import process'
129
        )
130
        ->addOption(
131
            InputOptionKeys::DB_PDO_DSN,
132
            null,
133
            InputOption::VALUE_REQUIRED,
134
            'The DSN used to connect to the Magento database where the data has to be imported, e. g. mysql:host=127.0.0.1;dbname=magento'
135
        )
136
        ->addOption(
137
            InputOptionKeys::DB_USERNAME,
138
            null,
139
            InputOption::VALUE_REQUIRED,
140
            'The username used to connect to the Magento database'
141
        )
142
        ->addOption(
143
            InputOptionKeys::DB_PASSWORD,
144
            null,
145
            InputOption::VALUE_REQUIRED,
146
            'The password used to connect to the Magento database'
147
        )
148
        ->addOption(
149
            InputOptionKeys::LOG_LEVEL,
150
            null,
151
            InputOption::VALUE_REQUIRED,
152
            'The log level to use'
153
        )
154
        ->addOption(
155
            InputOptionKeys::IGNORE_PID,
156
            null,
157
            InputOption::VALUE_REQUIRED,
158
            'Whether or not an existing PID should be ignored or not'
159
        )
160
        ->addOption(
161
            InputOptionKeys::DEBUG_MODE,
162
            null,
163
            InputOption::VALUE_REQUIRED,
164
            'Whether use the debug mode or not'
165
        )
166
        ->addOption(
167
            InputOptionKeys::PID_FILENAME,
168
            null,
169
            InputOption::VALUE_REQUIRED,
170
            'The explicit PID filename to use',
171
            sprintf('%s/%s', sys_get_temp_dir(), Configuration::PID_FILENAME)
172
        );
173
    }
174
175
    /**
176
     * Factory implementation to create a new initialized configuration instance.
177
     *
178
     * If command line options are specified, they will always override the
179
     * values found in the configuration file.
180
     *
181
     * @param \Symfony\Component\Console\Input\InputInterface $input The Symfony console input instance
182
     *
183
     * @return \TechDivision\Import\Cli\Configuration The configuration instance
184
     * @throws \Exception Is thrown, if the specified configuration file doesn't exist
185
     */
186
    protected function configurationFactory(InputInterface $input)
187
    {
188
189
        // load the configuration filename we want to use
190
        $filename = $input->getOption(InputOptionKeys::CONFIGURATION);
191
192
        // load the JSON data
193
        if (!$jsonData = file_get_contents($filename)) {
194
            throw new \Exception(sprintf('Can\'t load configuration file %s', $filename));
195
        }
196
197
        // initialize the JMS serializer and load the configuration
198
        $serializer = SerializerBuilder::create()->build();
199
        /** @var \TechDivision\Import\Cli\Configuration $instance */
200
        $instance = $serializer->deserialize($jsonData, 'TechDivision\Import\Cli\Configuration', 'json');
201
202
        // query whether or not an operation name has been specified as command line
203
        // option, if yes override the value from the configuration file
204
        if ($operationName = $input->getArgument(InputArgumentKeys::OPERATION_NAME)) {
205
            $instance->setOperationName($operationName);
206
        }
207
208
        // query whether or not a Magento installation directory has been specified as command line
209
        // option, if yes override the value from the configuration file
210
        if ($installationDir = $input->getOption(InputOptionKeys::INSTALLATION_DIR)) {
211
            $instance->setInstallationDir($installationDir);
212
        }
213
214
        // query whether or not a directory for the source files has been specified as command line
215
        // option, if yes override the value from the configuration file
216
        if ($sourceDir = $input->getOption(InputOptionKeys::SOURCE_DIR)) {
217
            $instance->setSourceDir($sourceDir);
218
        }
219
220
        // query whether or not a directory containing the imported files has been specified as command line
221
        // option, if yes override the value from the configuration file
222
        if ($targetDir = $input->getOption(InputOptionKeys::TARGET_DIR)) {
223
            $instance->setTargetDir($targetDir);
224
        }
225
226
        // query whether or not a source date format has been specified as command
227
        // line  option, if yes override the value from the configuration file
228
        if ($sourceDateFormat = $input->getOption(InputOptionKeys::SOURCE_DATE_FORMAT)) {
229
            $instance->setSourceDateFormat($sourceDateFormat);
230
        }
231
232
        // query whether or not a Magento edition has been specified as command line
233
        // option, if yes override the value from the configuration file
234
        if ($magentoEdition = $input->getOption(InputOptionKeys::MAGENTO_EDITION)) {
235
            $instance->setMagentoEdition($magentoEdition);
236
        }
237
238
        // query whether or not a Magento version has been specified as command line
239
        // option, if yes override the value from the configuration file
240
        if ($magentoVersion = $input->getOption(InputOptionKeys::MAGENTO_VERSION)) {
241
            $instance->setMagentoVersion($magentoVersion);
242
        }
243
244
        // query whether or not a DB ID has been specified as command line
245
        // option, if yes override the value from the configuration file
246
        if ($useDbId = $input->getOption(InputOptionKeys::USE_DB_ID)) {
247
            $instance->setUseDbId($useDbId);
248
        } else {
249
            // query whether or not a PDO DSN has been specified as command line
250
            // option, if yes override the value from the configuration file
251
            if ($dsn = $input->getOption(InputOptionKeys::DB_PDO_DSN)) {
252
                // first REMOVE all other database configurations
253
                $instance->clearDatabases();
254
255
                // initialize a new database configuration
256
                $database = new Database();
257
                $database->setId(Uuid::uuid4()->__toString());
258
                $database->setDefault(true);
259
                $database->setDsn($dsn);
260
261
                // query whether or not a DB username has been specified as command line
262
                // option, if yes override the value from the configuration file
263
                if ($username = $input->getOption(InputOptionKeys::DB_USERNAME)) {
264
                    $database->setUsername($username);
265
                }
266
267
                // query whether or not a DB password has been specified as command line
268
                // option, if yes override the value from the configuration file
269
                if ($password = $input->getOption(InputOptionKeys::DB_PASSWORD)) {
270
                    $database->setPassword($password);
271
                }
272
273
                // add the database configuration
274
                $instance->addDatabase($database);
275
            }
276
        }
277
278
        // query whether or not the debug mode has been specified as command line
279
        // option, if yes override the value from the configuration file
280
        if ($debugMode = $input->getOption(InputOptionKeys::DEBUG_MODE)) {
281
            $instance->setDebugMode($instance->mapBoolean($debugMode));
282
        }
283
284
        // query whether or not the ignore PID flag has been specified as command line
285
        // option, if yes override the value from the configuration file
286
        if ($ignorePid = $input->getOption(InputOptionKeys::IGNORE_PID)) {
287
            $instance->setIgnorePid($instance->mapBoolean($ignorePid));
288
        }
289
290
        // query whether or not the log level has been specified as command line
291
        // option, if yes override the value from the configuration file
292
        if ($logLevel = $input->getOption(InputOptionKeys::LOG_LEVEL)) {
293
            $instance->setLogLevel($logLevel);
294
        }
295
296
        // query whether or not a PID filename has been specified as command line
297
        // option, if yes override the value from the configuration file
298
        if ($pidFilename = $input->getOption(InputOptionKeys::PID_FILENAME)) {
299
            $instance->setPidFilename($pidFilename);
300
        }
301
302
        // extend the plugins with the main configuration instance
303
        /** @var \TechDivision\Import\Cli\Configuration\Subject $subject */
304
        foreach ($instance->getPlugins() as $plugin) {
305
            // set the configuration instance on the plugin
306
            $plugin->setConfiguration($instance);
307
308
            // query whether or not the plugin has subjects configured
309
            if ($subjects = $plugin->getSubjects()) {
310
                // extend the plugin's subjects with the main configuration instance
311
                /** @var \TechDivision\Import\Cli\Configuration\Subject $subject */
312
                foreach ($subjects as $subject) {
313
                    // set the configuration instance on the subject
314
                    $subject->setConfiguration($instance);
315
                }
316
            }
317
        }
318
319
        // query whether or not the debug mode is enabled and log level
320
        // has NOT been overwritten with a commandline option
321
        if ($instance->isDebugMode() && !$input->getOption(InputOptionKeys::LOG_LEVEL)) {
322
            // set debug log level, if log level has NOT been overwritten on command line
323
            $instance->setLogLevel(LogLevel::DEBUG);
324
        }
325
326
        // return the initialized configuration instance
327
        return $instance;
328
    }
329
330
    /**
331
     * Executes the current command.
332
     *
333
     * This method is not abstract because you can use this class
334
     * as a concrete class. In this case, instead of defining the
335
     * execute() method, you set the code to execute by passing
336
     * a Closure to the setCode() method.
337
     *
338
     * @param \Symfony\Component\Console\Input\InputInterface   $input  An InputInterface instance
339
     * @param \Symfony\Component\Console\Output\OutputInterface $output An OutputInterface instance
340
     *
341
     * @return null|int null or 0 if everything went fine, or an error code
342
     * @throws \LogicException When this abstract method is not implemented
343
     * @see \Symfony\Component\Console\Command\Command::execute()
344
     */
345
    protected function execute(InputInterface $input, OutputInterface $output)
346
    {
347
348
        // initialize the flag, whether the JMS annotations has been loaded or not
349
        $loaded = false;
350
351
        // the possible paths to the JMS annotations
352
        $annotationDirectories = array(
353
            dirname(__DIR__) . '/../../../jms/serializer/src',
354
            dirname(__DIR__) . '/../vendor/jms/serializer/src'
355
        );
356
357
        // register the JMS Serializer annotations
358
        foreach ($annotationDirectories as $annotationDirectory) {
359
            if (file_exists($annotationDirectory)) {
360
                \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
361
                    'JMS\Serializer\Annotation',
362
                    $annotationDirectory
363
                );
364
                $loaded = true;
365
                break;
366
            }
367
        }
368
369
        // stop processing, if the JMS annotations can't be loaded
370
        if (!$loaded) {
371
            throw new \Exception(
372
                sprintf(
373
                    'The JMS annotations can not be found in one of paths %s',
374
                    implode(', ', $annotationDirectories)
375
                )
376
            );
377
        }
378
379
        // load the specified configuration
380
        $configuration = $this->configurationFactory($input);
381
382
        // initialize the PDO connection
383
        $dsn = $configuration->getDatabase()->getDsn();
384
        $username = $configuration->getDatabase()->getUsername();
385
        $password = $configuration->getDatabase()->getPassword();
386
        $connection = new \PDO($dsn, $username, $password);
387
        $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
388
389
        // initialize the system logger
390
        $loggers = array();
391
392
        // initialize the default system logger
393
        $systemLogger = new Logger('techdivision/import');
394
        $systemLogger->pushHandler(
395
            new ErrorLogHandler(
396
                ErrorLogHandler::OPERATING_SYSTEM,
397
                $configuration->getLogLevel()
398
            )
399
        );
400
401
        // add it to the array
402
        $loggers[LoggerKeys::SYSTEM] = $systemLogger;
403
404
        // append the configured loggers or override the default one
405
        foreach ($configuration->getLoggers() as $loggerConfiguration) {
406
            // load the factory class that creates the logger instance
407
            $loggerFactory = $loggerConfiguration->getFactory();
408
            // create the logger instance and add it to the available loggers
409
            $loggers[$loggerConfiguration->getName()] = $loggerFactory::factory($loggerConfiguration);
410
        }
411
412
        // initialize the registry/import processor
413
        $registryProcessor = RegistryProcessorFactory::factory($connection, $configuration);
414
        $importProcessor = ImportProcessorFactory::factory($connection, $configuration);
415
416
        // initialize the importer
417
        $importer = new Simple(
418
            $registryProcessor,
419
            $importProcessor,
420
            $configuration,
421
            $input,
422
            $output,
423
            $loggers
424
        );
425
426
        // start the process
427
        $importer->process();
428
    }
429
}
430