Passed
Push — master ( 40d218...d516cb )
by James
09:17 queued 11s
created

AutoImport::getFiles()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 22
rs 8.8333
cc 7
nc 5
nop 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * AutoImport.php
5
 * Copyright (c) 2020 [email protected]
6
 *
7
 * This file is part of the Firefly III CSV importer
8
 * (https://github.com/firefly-iii/csv-importer).
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
22
 */
23
24
namespace App\Console\Commands;
25
26
use App\Console\HaveAccess;
27
use App\Console\StartImport;
28
use App\Console\VerifyJSON;
29
use Illuminate\Console\Command;
30
use JsonException;
31
32
/**
33
 * Class AutoImport
34
 */
35
class AutoImport extends Command
36
{
37
    use HaveAccess, VerifyJSON, StartImport;
38
39
    /** @var array */
40
    private const IGNORE = ['.', '..'];
41
    /**
42
     * The console command description.
43
     *
44
     * @var string
45
     */
46
    protected $description = 'Will automatically import from the given directory and use the JSON and CSV files found.';
47
    /**
48
     * The name and signature of the console command.
49
     *
50
     * @var string
51
     */
52
    protected $signature = 'csv:auto-import {directory : The directory from which to import automatically.}';
53
    /** @var string */
54
    private $directory = './';
55
56
    /**
57
     * Execute the console command.
58
     *
59
     * @throws JsonException
60
     * @return int
61
     */
62
    public function handle(): int
63
    {
64
        $access = $this->haveAccess();
65
        if (false === $access) {
66
            $this->error('Could not connect to your local Firefly III instance.');
67
68
            return 1;
69
        }
70
71
        $this->directory = (string) ($this->argument('directory') ?? './');
72
        $this->line(sprintf('Going to automatically import everything found in %s', $this->directory));
73
74
        $files = $this->getFiles();
75
        if (0 === count($files)) {
76
            $this->info(sprintf('There are no files in directory %s', $this->directory));
77
            $this->info('To learn more about this process, read the docs:');
78
            $this->info('https://firefly-iii.gitbook.io/firefly-iii-csv-importer/installing-and-running/docker');
79
80
            return 1;
81
        }
82
        $this->line(sprintf('Found %d CSV + JSON file sets in %s', count($files), $this->directory));
83
84
        $this->importFiles($files);
85
86
        return 0;
87
    }
88
89
    /**
90
     * @param string $file
91
     *
92
     * @return string
93
     */
94
    private function getExtension(string $file): string
95
    {
96
        $parts = explode('.', $file);
97
        if (1 === count($parts)) {
98
            return '';
99
        }
100
101
        return $parts[count($parts) - 1];
102
    }
103
104
    /**
105
     * @return array
106
     */
107
    private function getFiles(): array
108
    {
109
        if (null === $this->directory || '' === $this->directory) {
110
            $this->error(sprintf('Directory "%s" is empty or invalid.', $this->directory));
111
112
            return [];
113
        }
114
        $array = scandir($this->directory);
115
        if (!is_array($array)) {
116
            $this->error(sprintf('Directory "%s" is empty or invalid.', $this->directory));
117
118
            return [];
119
        }
120
        $files  = array_diff($array, self::IGNORE);
121
        $return = [];
122
        foreach ($files as $file) {
123
            if ('csv' === $this->getExtension($file) && $this->hasJsonConfiguration($file)) {
124
                $return[] = $file;
125
            }
126
        }
127
128
        return $return;
129
    }
130
131
    /**
132
     * @param string $file
133
     *
134
     * @return bool
135
     */
136
    private function hasJsonConfiguration(string $file): bool
137
    {
138
        $short    = substr($file, 0, -4);
139
        $jsonFile = sprintf('%s.json', $short);
140
        $fullJson = sprintf('%s/%s', $this->directory, $jsonFile);
141
        if (!file_exists($fullJson)) {
142
            $this->warn(sprintf('Can\'t find JSON file "%s" expected to go with CSV file "%s". CSV file will be ignored.', $fullJson, $file));
143
144
            return false;
145
        }
146
147
        return true;
148
    }
149
150
    /**
151
     * @param string $file
152
     *
153
     * @throws JsonException
154
     */
155
    private function importFile(string $file): void
156
    {
157
        $csvFile  = sprintf('%s/%s', $this->directory, $file);
158
        $jsonFile = sprintf('%s/%s.json', $this->directory, substr($file, 0, -4));
159
160
        // do JSON check
161
        $jsonResult = $this->verifyJSON($jsonFile);
162
        if (false === $jsonResult) {
163
            $message = sprintf('The importer can\'t import %s: could not decode the JSON in config file %s.', $csvFile, $jsonFile);
164
            $this->error($message);
165
166
            return;
167
        }
168
        $configuration = json_decode(file_get_contents($jsonFile), true, 512, JSON_THROW_ON_ERROR);
169
        $this->line(sprintf('Going to import from file %s using configuration %s.', $csvFile, $jsonFile));
170
        // create importer
171
        $csv    = file_get_contents($csvFile);
172
        $result = $this->startImport($csv, $configuration);
173
        if (0 === $result) {
174
            $this->line('Import complete.');
175
        }
176
        if (0 !== $result) {
177
            $this->warn('The import finished with errors.');
178
        }
179
180
        $this->line(sprintf('Done importing from file %s using configuration %s.', $csvFile, $jsonFile));
181
    }
182
183
    /**
184
     * @param array $files
185
     *
186
     * @throws JsonException
187
     */
188
    private function importFiles(array $files): void
189
    {
190
        /** @var string $file */
191
        foreach ($files as $file) {
192
            $this->importFile($file);
193
        }
194
    }
195
}
196