Completed
Push — develop ( 682ea7...20877f )
by
unknown
11s
created

ValidationCommand::validateFiles()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 33
Code Lines 19

Duplication

Lines 10
Ratio 30.3 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 10
loc 33
ccs 0
cts 25
cp 0
rs 5.3846
cc 8
eloc 19
nc 9
nop 2
crap 72
1
<?php
2
/**
3
 * base abstract for import based commands where a bunch of file must be collected and
4
 * done something with them..
5
 */
6
7
namespace Graviton\ImportExport\Command;
8
9
use Graviton\ImportExport\Exception\MissingTargetException;
10
use Symfony\Component\Console\Command\Command;
11
use Symfony\Component\Console\Helper\ProgressBar;
12
use Symfony\Component\Console\Input\InputArgument;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Input\InputOption;
15
use Symfony\Component\Console\Output\OutputInterface;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Finder\SplFileInfo;
18
use Symfony\Component\Yaml\Exception\ParseException;
19
use Webuni\FrontMatter\FrontMatter;
20
use Webuni\FrontMatter\Document;
21
use Symfony\Component\Yaml\Parser as YmlParser;
22
23
/**
24
 * @author   List of contributors <https://github.com/libgraviton/import-export/graphs/contributors>
25
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
26
 * @link     http://swisscom.ch
27
 */
28
class ValidationCommand extends Command
29
{
30
    /**
31
     * @var FrontMatter
32
     */
33
    private $frontMatter;
34
35
    /**
36
     * @var YmlParser
37
     */
38
    private $ymlParser;
39
40
    /**
41
     * Error array for validation
42
     * @var array
43
     */
44
    private $validationErrors = [];
45
46
    /**
47
     * @param FrontMatter $frontMatter frontmatter parser
48
     * @param YmlParser   $parser      yaml parser
49
     */
50
    public function __construct(
51
        FrontMatter $frontMatter,
52
        YmlParser $parser
53
    ) {
54
        $this->frontMatter = $frontMatter;
55
        $this->ymlParser = $parser;
56
        parent::__construct();
57
    }
58
59
    /**
60
     * Configures the current command.
61
     *
62
     * @return void
63
     */
64
    protected function configure()
65
    {
66
        $this
67
            ->setName('graviton:validate:import')
68
            ->setDescription('Import files from a folder or file.')
69
            ->addArgument(
70
                'file',
71
                InputArgument::REQUIRED + InputArgument::IS_ARRAY,
72
                'Directories or files to load'
73
            );
74
    }
75
76
    /**
77
     * Executes the current command.
78
     *
79
     * @param InputInterface  $input  User input on console
80
     * @param OutputInterface $output Output of the command
81
     *
82
     * @return integer
83
     */
84
    protected function execute(InputInterface $input, OutputInterface $output)
85
    {
86
        $files = $input->getArgument('file');
87
        $finder =  new Finder();
88
        $finder = $finder->files();
89
90
        /**
91
         * @param SplFileInfo $file
92
         * @return bool
93
         */
94 View Code Duplication
        $filter = function (SplFileInfo $file) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
            if (!in_array($file->getExtension(), ['yml','json']) || $file->isDir()) {
96
                return false;
97
            }
98
            return true;
99
        };
100
101 View Code Duplication
        foreach ($files as $file) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
            if (is_file($file)) {
103
                $finder->in(dirname($file))->name(basename($file));
104
            } else {
105
                $finder->in($file);
106
            }
107
        }
108
109
        $finder->ignoreDotFiles(true)->filter($filter);
110
111
        $this->validateFiles($finder, $output);
0 ignored issues
show
Bug introduced by
It seems like $finder defined by $finder->files() on line 88 can also be of type array<integer,object<Sym...nt\Finder\SplFileInfo>>; however, Graviton\ImportExport\Co...ommand::validateFiles() does only seem to accept object<Symfony\Component\Finder\Finder>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
112
113
        $output->writeln("\n".'<info>Finished</info>');
114
115
        if (!empty($this->validationErrors)) {
116
            $output->writeln("\n".'<error>With: '.count($this->validationErrors).' Errors</error>');
117
            foreach ($this->validationErrors as $file => $error) {
118
                $output->writeln('<comment>'.strstr($file, '/initialdata/').': '.$error.'</comment>');
119
            }
120
        } else {
121
            $output->writeln("\n".'<info>You are awesome! No Errors detected.</info>');
122
        }
123
    }
124
125
    /**
126
     * Will check and validate initial file information
127
     *
128
     * @param Finder          $finder File Finder by SF
129
     * @param OutputInterface $output Print to command line
130
     * @return void
131
     */
132
    private function validateFiles(Finder $finder, OutputInterface $output)
133
    {
134
        $count = $finder->count();
135
        $output->writeln("\n".'<info>Validation will be done for: '.$count.' files </info>');
136
137
        $progress = new ProgressBar($output, $count);
138
139
        foreach ($finder->files() as $file) {
140
            $progress->advance();
141
            $path = str_replace('//', '/', $file->getPathname());
142
143
            // To check file core db import structure or for PUT
144
            $fileType = strpos($path, '/data/param/') !== false ? 'param' : 'core';
145
146
            /** @var Document $doc */
147
            $doc = $this->frontMatter->parse($file->getContents());
148
            $docHeader = $doc->getData();
149
150
            if ('core' == $fileType) {
151 View Code Duplication
                if (!array_key_exists('collection', $docHeader) || empty($docHeader['collection'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                    $this->validationErrors[$path] = 'Core import, header "collection" is required';
153
                    continue;
154
                }
155 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
                if (!array_key_exists('target', $docHeader) || empty($docHeader['target'])) {
157
                    $this->validationErrors[$path] = 'Param import, header "target" is required';
158
                    continue;
159
                }
160
            }
161
162
            $this->parseContent($doc->getContent(), $path, $file->getExtension());
163
        }
164
    }
165
166
    /**
167
     * parse contents of a file depending on type
168
     *
169
     * @param string $content   contents part of file
170
     * @param string $path      full path to file
171
     * @param string $extension File extension json or yml
172
     *
173
     * @return void
174
     */
175
    protected function parseContent($content, $path, $extension)
176
    {
177
        switch ($extension) {
178
            case 'json':
179
                $data = json_decode($content);
180
                if (json_last_error() !== JSON_ERROR_NONE) {
181
                    $this->validationErrors[$path] = json_last_error_msg();
182
                }
183
                break;
184
            case 'yml':
185
                try {
186
                    $data = $this->ymlParser->parse($content);
187
                } catch (ParseException $e) {
188
                    $this->validationErrors[$path] = $e->getMessage();
189
                }
190
                break;
191
            default:
192
                $this->validationErrors[$path] = 'UnknownFileTypeException';
193
        };
194
195
        if (empty($data) && !array_key_exists($path, $this->validationErrors)) {
196
            $this->validationErrors[$path] = 'Returned empty yml data';
197
        }
198
    }
199
}
200