Configuration   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 388
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 43
eloc 152
c 2
b 0
f 0
dl 0
loc 388
rs 8.96

26 Methods

Rating   Name   Duplication   Size   Complexity  
B fromRequest() 0 50 11
A getDateRange() 0 3 1
A getDateRangeUnit() 0 3 1
A isDoMapping() 0 3 1
A getAccounts() 0 3 1
A __construct() 0 14 1
A setAccounts() 0 3 1
A calcDateNotBefore() 0 18 2
A isSkipForm() 0 3 1
A getDateNotBefore() 0 10 3
A fromArray() 0 21 1
A isRules() 0 3 1
A setDateNotAfter() 0 3 1
A getAccountTypes() 0 3 1
A toArray() 0 15 1
A fromFile() 0 8 2
A setDateRangeNumber() 0 3 1
A setDateRangeUnit() 0 3 1
A setDateRange() 0 3 1
A getDateNotAfter() 0 10 3
A getDateRangeNumber() 0 3 1
A getMapping() 0 3 1
A fromDefaultFile() 0 23 2
A setDateNotBefore() 0 3 1
A setAccountTypes() 0 3 1
A setMapping() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Configuration often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Configuration, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Configuration.php
4
 * Copyright (c) 2020 [email protected].
5
 *
6
 * This file is part of the Firefly III bunq importer
7
 * (https://github.com/firefly-iii/bunq-importer).
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace App\Services\Configuration;
26
27
use Carbon\Carbon;
28
use RuntimeException;
29
30
/**
31
 * Class Configuration.
32
 */
33
class Configuration
34
{
35
    /** @var int */
36
    public const VERSION = 1;
37
    /** @var array */
38
    private $accountTypes;
39
    /** @var array */
40
    private $accounts;
41
    /** @var string */
42
    private $dateNotAfter;
43
    /** @var string */
44
    private $dateNotBefore;
45
    /** @var string */
46
    private $dateRange;
47
    /** @var int */
48
    private $dateRangeNumber;
49
    /** @var string */
50
    private $dateRangeUnit;
51
    /** @var bool */
52
    private $doMapping;
53
    /** @var array */
54
    private $mapping;
55
    /** @var bool */
56
    private $rules;
57
    /** @var bool */
58
    private $skipForm;
59
    /** @var int */
60
    private $version;
61
62
    /**
63
     * Configuration constructor.
64
     */
65
    private function __construct()
66
    {
67
        $this->rules           = true;
68
        $this->skipForm        = false;
69
        $this->doMapping       = false;
70
        $this->accounts        = [];
71
        $this->version         = self::VERSION;
72
        $this->mapping         = [];
73
        $this->accountTypes    = [];
74
        $this->dateRange       = 'all';
75
        $this->dateRangeNumber = 30;
76
        $this->dateRangeUnit   = 'd';
77
        $this->dateNotBefore   = '';
78
        $this->dateNotAfter    = '';
79
    }
80
81
    /**
82
     * @param array $array
83
     *
84
     * @return static
85
     */
86
    public static function fromArray(array $array): self
87
    {
88
        $version = $array['version'] ?? 1;
89
90
        // TODO now have room to do version based array parsing.
91
92
        $object                  = new self;
93
        $object->rules           = $array['rules'] ?? false;
94
        $object->skipForm        = $array['skip_form'] ?? false;
95
        $object->accounts        = $array['accounts'] ?? [];
96
        $object->mapping         = $array['mapping'] ?? [];
97
        $object->accountTypes    = $array['account_types'] ?? [];
98
        $object->dateRange       = $array['date_range'] ?? 'all';
99
        $object->dateRangeNumber = $array['date_range_number'] ?? 30;
100
        $object->dateRangeUnit   = $array['date_range_unit'] ?? 'd';
101
        $object->dateNotBefore   = $array['date_not_before'] ?? '';
102
        $object->dateNotAfter    = $array['date_not_after'] ?? '';
103
        $object->doMapping       = $array['do_mapping'] ?? false;
104
        $object->version         = $version;
105
106
        return $object;
107
    }
108
109
    /**
110
     * @param array $data
111
     *
112
     * @return $this
113
     */
114
    public static function fromFile(array $data): self
115
    {
116
        app('log')->debug('Now in Configuration::fromClassic', $data);
117
        $version = $data['version'] ?? 1;
118
        if (1 === $version) {
119
            return self::fromDefaultFile($data);
120
        }
121
        throw new RuntimeException(sprintf('Configuration file version "%s" cannot be parsed.', $version));
122
    }
123
124
    /**
125
     * @param array $array
126
     *
127
     * @return $this
128
     */
129
    public static function fromRequest(array $array): self
130
    {
131
        $object           = new self;
132
        $object->version  = self::VERSION;
133
        $object->rules    = $array['rules'];
134
        $object->skipForm = $array['skip_form'];
135
136
        $object->mapping         = $array['mapping'];
137
        $object->accountTypes    = $array['account_types'] ?? [];
138
        $object->dateRange       = $array['date_range'];
139
        $object->dateRangeNumber = $array['date_range_number'];
140
        $object->dateRangeUnit   = $array['date_range_unit'];
141
        $object->dateNotBefore   = $array['date_not_before'];
142
        $object->dateNotAfter    = $array['date_not_after'];
143
        $object->doMapping       = $array['do_mapping'];
144
145
        $doImport = $array['do_import'] ?? [];
146
        $accounts = [];
147
        foreach ($doImport as $bunqId => $selected) {
148
            $selected = (int) $selected;
149
            if (1 === $selected) {
150
                $accounts[(int) $bunqId] = (int) ($array['accounts'][$bunqId] ?? 0);
151
            }
152
        }
153
        $object->accounts = $accounts;
154
155
        switch ($object->dateRange) {
156
            case 'all':
157
                $object->dateRangeUnit   = null;
158
                $object->dateRangeNumber = null;
159
                $object->dateNotBefore   = null;
160
                $object->dateNotAfter    = null;
161
                break;
162
            case 'partial':
163
                $object->dateNotAfter  = null;
164
                $object->dateNotBefore = self::calcDateNotBefore($object->dateRangeUnit, $object->dateRangeNumber);
165
                break;
166
            case 'range':
167
                $before = $object->dateNotBefore;
168
                $after  = $object->dateNotAfter;
169
170
                if (null !== $before && null !== $after && $object->dateNotBefore > $object->dateNotAfter) {
171
                    [$before, $after] = [$after, $before];
172
                }
173
174
                $object->dateNotBefore = null === $before ? null : $before->format('Y-m-d');
175
                $object->dateNotAfter  = null === $after ? null : $after->format('Y-m-d');
176
        }
177
178
        return $object;
179
    }
180
181
    /**
182
     * @param string $unit
183
     * @param int    $number
184
     *
185
     * @return string|null
186
     */
187
    private static function calcDateNotBefore(string $unit, int $number): ?string
188
    {
189
        $functions = [
190
            'd' => 'subDays',
191
            'w' => 'subWeeks',
192
            'm' => 'subMonths',
193
            'y' => 'subYears',
194
        ];
195
        if (isset($functions[$unit])) {
196
            $today    = Carbon::now();
197
            $function = $functions[$unit];
198
            $today->$function($number);
199
200
            return $today->format('Y-m-d');
201
        }
202
        app('log')->error(sprintf('Could not parse date setting. Unknown key "%s"', $unit));
203
204
        return null;
205
    }
206
207
    /**
208
     * @param array $data
209
     *
210
     * @return static
211
     */
212
    private static function fromDefaultFile(array $data): self
213
    {
214
        $object                  = new self;
215
        $object->rules           = $data['rules'] ?? true;
216
        $object->skipForm        = $data['skip_form'] ?? false;
217
        $object->dateRange       = $data['date_range'] ?? 'all';
218
        $object->dateRangeNumber = $data['date_range_number'] ?? 30;
219
        $object->dateRangeUnit   = $data['date_range_unit'] ?? 'd';
220
        $object->dateNotBefore   = $data['date_not_before'] ?? '';
221
        $object->accountTypes    = $data['account_types'] ?? [];
222
        $object->dateNotAfter    = $data['date_not_after'] ?? '';
223
        $object->doMapping       = $data['do_mapping'] ?? false;
224
        $object->mapping         = $data['mapping'] ?? [];
225
        $object->accounts        = $data['accounts'] ?? [];
226
227
        // TODO recalculate the date if 'partial'
228
        if ('partial' === $data['date_range']) {
229
            $object->dateNotBefore = self::calcDateNotBefore($object->dateRangeUnit, $object->dateRangeNumber);
230
        }
231
        // set version to "1" and return.
232
        $object->version = 1;
233
234
        return $object;
235
    }
236
237
    /**
238
     * @return array
239
     */
240
    public function getAccountTypes(): array
241
    {
242
        return $this->accountTypes;
243
    }
244
245
    /**
246
     * @param array $accountTypes
247
     */
248
    public function setAccountTypes(array $accountTypes): void
249
    {
250
        $this->accountTypes = $accountTypes;
251
    }
252
253
    /**
254
     * @return array
255
     */
256
    public function getAccounts(): array
257
    {
258
        return $this->accounts;
259
    }
260
261
    /**
262
     * @param array $accounts
263
     */
264
    public function setAccounts(array $accounts): void
265
    {
266
        $this->accounts = $accounts;
267
    }
268
269
    /**
270
     * @return string
271
     */
272
    public function getDateNotAfter(): ?string
273
    {
274
        if (null === $this->dateNotAfter) {
275
            return null;
276
        }
277
        if ('' === $this->dateNotAfter) {
278
            return null;
279
        }
280
281
        return $this->dateNotAfter;
282
    }
283
284
    /**
285
     * @param string $dateNotAfter
286
     */
287
    public function setDateNotAfter(string $dateNotAfter): void
288
    {
289
        $this->dateNotAfter = $dateNotAfter;
290
    }
291
292
    /**
293
     * @return string|null
294
     */
295
    public function getDateNotBefore(): ?string
296
    {
297
        if (null === $this->dateNotBefore) {
298
            return null;
299
        }
300
        if ('' === $this->dateNotBefore) {
301
            return null;
302
        }
303
304
        return $this->dateNotBefore;
305
    }
306
307
    /**
308
     * @param string $dateNotBefore
309
     */
310
    public function setDateNotBefore(string $dateNotBefore): void
311
    {
312
        $this->dateNotBefore = $dateNotBefore;
313
    }
314
315
    /**
316
     * @return string
317
     */
318
    public function getDateRange(): string
319
    {
320
        return $this->dateRange;
321
    }
322
323
    /**
324
     * @param string $dateRange
325
     */
326
    public function setDateRange(string $dateRange): void
327
    {
328
        $this->dateRange = $dateRange;
329
    }
330
331
    /**
332
     * @return int
333
     */
334
    public function getDateRangeNumber(): int
335
    {
336
        return $this->dateRangeNumber;
337
    }
338
339
    /**
340
     * @param int $dateRangeNumber
341
     */
342
    public function setDateRangeNumber(int $dateRangeNumber): void
343
    {
344
        $this->dateRangeNumber = $dateRangeNumber;
345
    }
346
347
    /**
348
     * @return string
349
     */
350
    public function getDateRangeUnit(): string
351
    {
352
        return $this->dateRangeUnit;
353
    }
354
355
    /**
356
     * @param string $dateRangeUnit
357
     */
358
    public function setDateRangeUnit(string $dateRangeUnit): void
359
    {
360
        $this->dateRangeUnit = $dateRangeUnit;
361
    }
362
363
    /**
364
     * @return array
365
     */
366
    public function getMapping(): array
367
    {
368
        return $this->mapping;
369
    }
370
371
    /**
372
     * @param array $mapping
373
     */
374
    public function setMapping(array $mapping): void
375
    {
376
        $this->mapping = $mapping;
377
    }
378
379
    /**
380
     * @return bool
381
     */
382
    public function isDoMapping(): bool
383
    {
384
        return $this->doMapping;
385
    }
386
387
    /**
388
     * @return bool
389
     */
390
    public function isRules(): bool
391
    {
392
        return $this->rules;
393
    }
394
395
    /**
396
     * @return bool
397
     */
398
    public function isSkipForm(): bool
399
    {
400
        return $this->skipForm;
401
    }
402
403
    /**
404
     * @return array
405
     */
406
    public function toArray(): array
407
    {
408
        return [
409
            'rules'             => $this->rules,
410
            'skip_form'         => $this->skipForm,
411
            'accounts'          => $this->accounts,
412
            'version'           => $this->version,
413
            'mapping'           => $this->mapping,
414
            'account_types'     => $this->accountTypes,
415
            'date_range'        => $this->dateRange,
416
            'date_range_number' => $this->dateRangeNumber,
417
            'date_range_unit'   => $this->dateRangeUnit,
418
            'date_not_before'   => $this->dateNotBefore,
419
            'date_not_after'    => $this->dateNotAfter,
420
            'do_mapping'        => $this->doMapping,
421
        ];
422
    }
423
}
424