Passed
Push — master ( 6f8b1f...142a48 )
by James
25:51 queued 11:45
created

WholePeriodChartGenerator::generate()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 67
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 43
c 1
b 0
f 0
dl 0
loc 67
rs 8.9208
cc 5
nc 12
nop 3

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
 * WholePeriodChartGenerator.php
4
 * Copyright (c) 2019 [email protected]
5
 *
6
 * This file is part of Firefly III.
7
 *
8
 * Firefly III is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Firefly III is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
namespace FireflyIII\Support\Chart\Category;
23
24
use Carbon\Carbon;
25
use FireflyIII\Models\AccountType;
26
use FireflyIII\Models\Category;
27
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
28
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
29
30
/**
31
 * Class WholePeriodChartGenerator
32
 */
33
class WholePeriodChartGenerator
34
{
35
    /**
36
     * @param Category $category
37
     * @param Carbon   $start
38
     * @param Carbon   $end
39
     *
40
     * @return array
41
     */
42
    public function generate(Category $category, Carbon $start, Carbon $end): array
43
    {
44
        /** @var CategoryRepositoryInterface $repository */
45
        $repository = app(CategoryRepositoryInterface::class);
46
47
        /** @var AccountRepositoryInterface $accountRepository */
48
        $accountRepository = app(AccountRepositoryInterface::class);
49
50
        $types     = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
51
        $accounts  = $accountRepository->getAccountsByType($types);
52
        $step      = $this->calculateStep($start, $end);
53
        $chartData = [];
54
        $spent     = [];
55
        $earned    = [];
56
57
        /** @var Carbon $current */
58
        $current = clone $start;
59
60
        while ($current <= $end) {
61
            $key          = $current->format('Y-m-d');
62
            $currentEnd   = app('navigation')->endOfPeriod($current, $step);
63
            $spent[$key]  = $repository->spentInPeriod($category, $accounts, $current, $currentEnd);
0 ignored issues
show
Bug introduced by James Cole
$category of type FireflyIII\Models\Category is incompatible with the type Illuminate\Support\Collection expected by parameter $categories of FireflyIII\Repositories\...erface::spentInPeriod(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
            $spent[$key]  = $repository->spentInPeriod(/** @scrutinizer ignore-type */ $category, $accounts, $current, $currentEnd);
Loading history...
64
            $earned[$key] = $repository->earnedInPeriod($category, $accounts, $current, $currentEnd);
0 ignored issues
show
Bug introduced by James Cole
$category of type FireflyIII\Models\Category is incompatible with the type Illuminate\Support\Collection expected by parameter $categories of FireflyIII\Repositories\...rface::earnedInPeriod(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
            $earned[$key] = $repository->earnedInPeriod(/** @scrutinizer ignore-type */ $category, $accounts, $current, $currentEnd);
Loading history...
65
            $current      = app('navigation')->addPeriod($current, $step, 0);
66
        }
67
        $currencies = $this->extractCurrencies($spent) + $this->extractCurrencies($earned);
68
69
        // generate chart data (for each currency)
70
        /** @var array $currency */
71
        foreach ($currencies as $currency) {
72
            $code                                     = $currency['currency_code'];
73
            $name                                     = $currency['currency_name'];
74
            $chartData[sprintf('spent-in-%s', $code)] = [
75
                'label'           => (string)trans('firefly.box_spent_in_currency', ['currency' => $name]),
76
                'entries'         => [],
77
                'type'            => 'bar',
78
                'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
79
            ];
80
81
            $chartData[sprintf('earned-in-%s', $code)] = [
82
                'label'           => (string)trans('firefly.box_earned_in_currency', ['currency' => $name]),
83
                'entries'         => [],
84
                'type'            => 'bar',
85
                'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
86
            ];
87
        }
88
89
        /** @var Carbon $current */
90
        $current = clone $start;
91
92
        while ($current <= $end) {
93
            $key        = $current->format('Y-m-d');
94
            $label      = app('navigation')->periodShow($current, $step);
95
96
            /** @var array $currency */
97
            foreach ($currencies as $currency) {
98
                $code                                         = $currency['currency_code'];
99
                $spentInfoKey                                 = sprintf('spent-in-%s', $code);
100
                $earnedInfoKey                                = sprintf('earned-in-%s', $code);
101
                $spentAmount                                  = $spent[$key][$code]['spent'] ?? '0';
102
                $earnedAmount                                 = $earned[$key][$code]['earned'] ?? '0';
103
                $chartData[$spentInfoKey]['entries'][$label]  = round($spentAmount, $currency['currency_decimal_places']);
0 ignored issues
show
Bug introduced by James Cole
It seems like $spentAmount can also be of type string; however, parameter $val of round() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
                $chartData[$spentInfoKey]['entries'][$label]  = round(/** @scrutinizer ignore-type */ $spentAmount, $currency['currency_decimal_places']);
Loading history...
104
                $chartData[$earnedInfoKey]['entries'][$label] = round($earnedAmount, $currency['currency_decimal_places']);
105
            }
106
            $current = app('navigation')->addPeriod($current, $step, 0);
107
        }
108
        return $chartData;
109
    }
110
111
    /**
112
     * TODO is a duplicate function.
113
     *
114
     * @param Carbon $start
115
     * @param Carbon $end
116
     *
117
     * @return string
118
     */
119
    protected function calculateStep(Carbon $start, Carbon $end): string
120
    {
121
122
        $step   = '1D';
123
        $months = $start->diffInMonths($end);
124
        if ($months > 3) {
125
            $step = '1W'; // @codeCoverageIgnore
126
        }
127
        if ($months > 24) {
128
            $step = '1M'; // @codeCoverageIgnore
129
        }
130
        if ($months > 100) {
131
            $step = '1Y'; // @codeCoverageIgnore
132
        }
133
134
        return $step;
135
    }
136
137
    /**
138
     * Loop array of spent/earned info, and extract which currencies are present.
139
     * Key is the currency ID.
140
     *
141
     * @param array $array
142
     *
143
     * @return array
144
     */
145
    private function extractCurrencies(array $array): array
146
    {
147
        $return = [];
148
        foreach ($array as $info) {
149
            foreach ($info as $block) {
150
                $currencyId = $block['currency_id'];
151
                if (!isset($return[$currencyId])) {
152
                    $return[$currencyId] = [
153
                        'currency_id'             => $block['currency_id'],
154
                        'currency_code'           => $block['currency_code'],
155
                        'currency_name'           => $block['currency_name'],
156
                        'currency_symbol'         => $block['currency_symbol'],
157
                        'currency_decimal_places' => $block['currency_decimal_places'],
158
                    ];
159
                }
160
            }
161
        }
162
163
        return $return;
164
    }
165
166
}