GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 869845...9ac565 )
by James
08:24 queued 03:31
created

Search::applyModifiers()   C

Complexity

Conditions 15
Paths 15

Size

Total Lines 50
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 5.3624
c 0
b 0
f 0
cc 15
eloc 44
nc 15
nop 1

How to fix   Complexity   

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
 * Search.php
4
 * Copyright (c) 2017 [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
declare(strict_types=1);
23
24
namespace FireflyIII\Support\Search;
25
26
27
use Carbon\Carbon;
28
use FireflyIII\Exceptions\FireflyException;
29
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
30
use FireflyIII\Helpers\Filter\InternalTransferFilter;
31
use FireflyIII\Models\Transaction;
32
use FireflyIII\User;
33
use Illuminate\Support\Collection;
34
use Log;
35
36
/**
37
 * Class Search
38
 *
39
 * @package FireflyIII\Search
40
 */
41
class Search implements SearchInterface
42
{
43
    /** @var int */
44
    private $limit = 100;
45
    /** @var Collection */
46
    private $modifiers;
47
    /** @var  string */
48
    private $originalQuery = '';
49
    /** @var User */
50
    private $user;
51
    /** @var array */
52
    private $validModifiers = [];
53
    /** @var  array */
54
    private $words = [];
55
56
    /**
57
     * Search constructor.
58
     */
59
    public function __construct()
60
    {
61
        $this->modifiers      = new Collection;
62
        $this->validModifiers = (array)config('firefly.search_modifiers');
63
    }
64
65
    /**
66
     * @return string
67
     */
68
    public function getWordsAsString(): string
69
    {
70
        $string = join(' ', $this->words);
71
        if (strlen($string) === 0) {
72
            return is_string($this->originalQuery) ? $this->originalQuery : '';
73
        }
74
75
        return $string;
76
    }
77
78
    /**
79
     * @return bool
80
     */
81
    public function hasModifiers(): bool
82
    {
83
        return $this->modifiers->count() > 0;
84
    }
85
86
    /**
87
     * @param string $query
88
     */
89
    public function parseQuery(string $query)
90
    {
91
        $filteredQuery       = $query;
92
        $this->originalQuery = $query;
93
        $pattern             = '/[a-z_]*:[0-9a-z-.]*/i';
94
        $matches             = [];
95
        preg_match_all($pattern, $query, $matches);
96
97
        foreach ($matches[0] as $match) {
98
            $this->extractModifier($match);
99
            $filteredQuery = str_replace($match, '', $filteredQuery);
100
        }
101
        $filteredQuery = trim(str_replace(['"', "'"], '', $filteredQuery));
102
        if (strlen($filteredQuery) > 0) {
103
            $this->words = array_map('trim', explode(' ', $filteredQuery));
104
        }
105
    }
106
107
    /**
108
     * @return Collection
109
     */
110
    public function searchTransactions(): Collection
111
    {
112
        Log::debug('Start of searchTransactions()');
113
        $pageSize  = 100;
114
        $processed = 0;
115
        $page      = 1;
116
        $result    = new Collection();
117
        $startTime = microtime(true);
118
        do {
119
            /** @var JournalCollectorInterface $collector */
120
            $collector = app(JournalCollectorInterface::class);
121
            $collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->withOpposingAccount();
122
            if ($this->hasModifiers()) {
123
                $collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
124
            }
125
126
            // some modifiers can be applied to the collector directly.
127
            $collector = $this->applyModifiers($collector);
128
129
            $collector->removeFilter(InternalTransferFilter::class);
130
            $set = $collector->getPaginatedJournals()->getCollection();
131
132
            Log::debug(sprintf('Found %d journals to check. ', $set->count()));
133
134
            // Filter transactions that match the given triggers.
135
            $filtered = $set->filter(
136
                function (Transaction $transaction) {
137
138
                    if ($this->matchModifiers($transaction)) {
139
                        return $transaction;
140
                    }
141
142
                    // return false:
143
                    return false;
144
                }
145
            );
146
147
            Log::debug(sprintf('Found %d journals that match.', $filtered->count()));
148
149
            // merge:
150
            /** @var Collection $result */
151
            $result = $result->merge($filtered);
152
            Log::debug(sprintf('Total count is now %d', $result->count()));
153
154
            // Update counters
155
            $page++;
156
            $processed += count($set);
157
158
            Log::debug(sprintf('Page is now %d, processed is %d', $page, $processed));
159
160
            // Check for conditions to finish the loop
161
            $reachedEndOfList = $set->count() < 1;
162
            $foundEnough      = $result->count() >= $this->limit;
163
164
            Log::debug(sprintf('reachedEndOfList: %s', var_export($reachedEndOfList, true)));
165
            Log::debug(sprintf('foundEnough: %s', var_export($foundEnough, true)));
166
167
            // break at some point so the script does not crash:
168
            $currentTime = microtime(true) - $startTime;
169
            Log::debug(sprintf('Have been running for %f seconds.', $currentTime));
170
171
        } while (!$reachedEndOfList && !$foundEnough && $currentTime <= 30);
172
173
        $result = $result->slice(0, $this->limit);
174
175
        return $result;
176
    }
177
178
    /**
179
     * @param int $limit
180
     */
181
    public function setLimit(int $limit)
182
    {
183
        $this->limit = $limit;
184
    }
185
186
    /**
187
     * @param User $user
188
     */
189
    public function setUser(User $user)
190
    {
191
        $this->user = $user;
192
    }
193
194
    private function applyModifiers(JournalCollectorInterface $collector): JournalCollectorInterface
195
    {
196
        foreach ($this->modifiers as $modifier) {
197
            switch ($modifier['type']) {
198
                case 'amount_is':
199
                case 'amount':
200
                    $amount = app('steam')->positive(strval($modifier['value']));
201
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
202
                    $collector->amountIs($amount);
203
                    break;
204
                case 'amount_max':
205
                case 'amount_less':
206
                    $amount = app('steam')->positive(strval($modifier['value']));
207
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
208
                    $collector->amountLess($amount);
209
                    break;
210
                case 'amount_min':
211
                case 'amount_more':
212
                    $amount = app('steam')->positive(strval($modifier['value']));
213
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
214
                    $collector->amountMore($amount);
215
                    break;
216
                case 'type':
217
                    $collector->setTypes([ucfirst($modifier['value'])]);
218
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
219
                    break;
220
                case 'date':
221
                case 'on':
222
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
223
                    $start = new Carbon($modifier['value']);
224
                    $collector->setRange($start, $start);
225
                    break;
226
                case 'date_before':
227
                case 'before':
228
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
229
                    $before = new Carbon($modifier['value']);
230
                    $collector->setBefore($before);
231
                    break;
232
                case 'date_after':
233
                case 'after':
234
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
235
                    $after = new Carbon($modifier['value']);
236
                    $collector->setBefore($after);
237
                    break;
238
            }
239
        }
240
241
242
        return $collector;
243
    }
244
245
    /**
246
     * @param string $string
247
     */
248
    private function extractModifier(string $string)
249
    {
250
        $parts = explode(':', $string);
251
        if (count($parts) === 2 && strlen(trim(strval($parts[0]))) > 0 && strlen(trim(strval($parts[1])))) {
252
            $type  = trim(strval($parts[0]));
253
            $value = trim(strval($parts[1]));
254
            if (in_array($type, $this->validModifiers)) {
255
                // filter for valid type
256
                $this->modifiers->push(['type' => $type, 'value' => $value,]);
257
            }
258
        }
259
    }
260
261
    /**
262
     * @param Transaction $transaction
263
     *
264
     * @return bool
265
     * @throws FireflyException
266
     */
267
    private function matchModifiers(Transaction $transaction): bool
268
    {
269
        Log::debug(sprintf('Now at transaction #%d', $transaction->id));
270
        // first "modifier" is always the text of the search:
271
        // check descr of journal:
272
        if (count($this->words) > 0
273
            && !$this->strposArray(strtolower(strval($transaction->description)), $this->words)
274
            && !$this->strposArray(strtolower(strval($transaction->transaction_description)), $this->words)
275
        ) {
276
            Log::debug('Description does not match', $this->words);
277
278
            return false;
279
        }
280
281
        // then a for-each and a switch for every possible other thingie.
282
        foreach ($this->modifiers as $modifier) {
283
            $res = Modifier::apply($modifier, $transaction);
284
            if ($res === false) {
285
                return $res;
286
            }
287
        }
288
289
        return true;
290
291
    }
292
293
    /**
294
     * @param string $haystack
295
     * @param array  $needle
296
     *
297
     * @return bool
298
     */
299
    private function strposArray(string $haystack, array $needle)
300
    {
301
        if (strlen($haystack) === 0) {
302
            return false;
303
        }
304
        foreach ($needle as $what) {
305
            if (stripos($haystack, $what) !== false) {
306
                return true;
307
            }
308
        }
309
310
        return false;
311
    }
312
}
313