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.
Passed
Push — master ( d550a6...996863 )
by James
24:09 queued 11:56
created

Search::setPage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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
declare(strict_types=1);
22
23
namespace FireflyIII\Support\Search;
24
25
use Carbon\Carbon;
26
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
27
use FireflyIII\Models\AccountType;
28
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
29
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
30
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
31
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
32
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
33
use FireflyIII\User;
34
use Illuminate\Pagination\LengthAwarePaginator;
35
use Illuminate\Support\Collection;
36
use Log;
37
38
/**
39
 * Class Search.
40
 */
41
class Search implements SearchInterface
42
{
43
    /** @var AccountRepositoryInterface */
44
    private $accountRepository;
45
    /** @var BillRepositoryInterface */
46
    private $billRepository;
47
    /** @var BudgetRepositoryInterface */
48
    private $budgetRepository;
49
    /** @var CategoryRepositoryInterface */
50
    private $categoryRepository;
51
    /** @var int */
52
    private $limit = 100;
53
    /** @var Collection */
54
    private $modifiers;
55
    /** @var string */
56
    private $originalQuery = '';
57
    /** @var float */
58
    private $startTime;
59
    /** @var TagRepositoryInterface */
60
    private $tagRepository;
61
    /** @var User */
62
    private $user;
63
    /** @var array */
64
    private $validModifiers;
65
    /** @var array */
66
    private $words = [];
67
    /** @var int */
68
    private $page;
69
70
    /**
71
     * Search constructor.
72
     */
73
    public function __construct()
74
    {
75
        $this->page               = 1;
76
        $this->modifiers          = new Collection;
77
        $this->validModifiers     = (array)config('firefly.search_modifiers');
78
        $this->startTime          = microtime(true);
79
        $this->accountRepository  = app(AccountRepositoryInterface::class);
80
        $this->categoryRepository = app(CategoryRepositoryInterface::class);
81
        $this->budgetRepository   = app(BudgetRepositoryInterface::class);
82
        $this->billRepository     = app(BillRepositoryInterface::class);
83
        $this->tagRepository      = app(TagRepositoryInterface::class);
84
85
        if ('testing' === config('app.env')) {
86
            Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
87
        }
88
    }
89
90
    /**
91
     * @return Collection
92
     */
93
    public function getModifiers(): Collection
94
    {
95
        return $this->modifiers;
96
    }
97
98
    /**
99
     * @return string
100
     */
101
    public function getWordsAsString(): string
102
    {
103
        $string = implode(' ', $this->words);
104
        if ('' === $string) {
105
            return \is_string($this->originalQuery) ? $this->originalQuery : '';
0 ignored issues
show
introduced by
The condition is_string($this->originalQuery) is always true.
Loading history...
106
        }
107
108
        return $string;
109
    }
110
111
    /**
112
     * @return bool
113
     */
114
    public function hasModifiers(): bool
115
    {
116
        return $this->modifiers->count() > 0;
117
    }
118
119
    /**
120
     * @param string $query
121
     */
122
    public function parseQuery(string $query): void
123
    {
124
        $filteredQuery       = $query;
125
        $this->originalQuery = $query;
126
        $pattern             = '/[a-z_]*:[0-9a-z-.]*/i';
127
        $matches             = [];
128
        preg_match_all($pattern, $query, $matches);
129
130
        foreach ($matches[0] as $match) {
131
            $this->extractModifier($match);
132
            $filteredQuery = str_replace($match, '', $filteredQuery);
133
        }
134
        $filteredQuery = trim(str_replace(['"', "'"], '', $filteredQuery));
135
        if ('' !== $filteredQuery) {
136
            $this->words = array_map('trim', explode(' ', $filteredQuery));
137
        }
138
    }
139
140
    /**
141
     * @return float
142
     */
143
    public function searchTime(): float
144
    {
145
        return microtime(true) - $this->startTime;
146
    }
147
148
    /**
149
     * @return LengthAwarePaginator
150
     */
151
    public function searchTransactions(): LengthAwarePaginator
152
    {
153
        Log::debug('Start of searchTransactions()');
154
        $pageSize = 50;
155
156
        /** @var GroupCollectorInterface $collector */
157
        $collector = app(GroupCollectorInterface::class);
158
159
        $collector->setLimit($pageSize)->setPage($this->page)->withAccountInformation();
160
        $collector->withCategoryInformation()->withBudgetInformation();
161
        $collector->setSearchWords($this->words);
162
163
        // Most modifiers can be applied to the collector directly.
164
        $collector = $this->applyModifiers($collector);
165
166
        return $collector->getPaginatedGroups();
167
168
    }
169
170
    /**
171
     * @param int $limit
172
     */
173
    public function setLimit(int $limit): void
174
    {
175
        $this->limit = $limit;
176
    }
177
178
    /**
179
     * @param User $user
180
     */
181
    public function setUser(User $user): void
182
    {
183
        $this->user = $user;
184
        $this->accountRepository->setUser($user);
185
        $this->billRepository->setUser($user);
186
        $this->categoryRepository->setUser($user);
187
        $this->budgetRepository->setUser($user);
188
    }
189
190
    /**
191
     * @param GroupCollectorInterface $collector
192
     *
193
     * @return GroupCollectorInterface
194
     *
195
     */
196
    private function applyModifiers(GroupCollectorInterface $collector): GroupCollectorInterface
197
    {
198
        /*
199
         * TODO:
200
         * 'bill'?
201
         */
202
        $totalAccounts = new Collection;
203
204
        foreach ($this->modifiers as $modifier) {
205
            switch ($modifier['type']) {
206
                default:
207
                    die(sprintf('unsupported modifier: "%s"', $modifier['type']));
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
208
                case 'from':
209
                case 'source':
210
                    // source can only be asset, liability or revenue account:
211
                    $searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::REVENUE];
212
                    $accounts    = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
213
                    if ($accounts->count() > 0) {
214
                        $totalAccounts = $accounts->merge($totalAccounts);
215
                    }
216
                    break;
217
                case 'to':
218
                case 'destination':
219
                    // source can only be asset, liability or expense account:
220
                    $searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::EXPENSE];
221
                    $accounts    = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
222
                    if ($accounts->count() > 0) {
223
                        $totalAccounts = $accounts->merge($totalAccounts);
224
                    }
225
                    break;
226
                case 'category':
227
                    $result = $this->categoryRepository->searchCategory($modifier['value']);
228
                    if ($result->count() > 0) {
229
                        $collector->setCategories($result);
230
                    }
231
                    break;
232
                case 'bill':
233
                    $result = $this->billRepository->searchBill($modifier['value']);
234
                    if ($result->count() > 0) {
235
                        $collector->setBills($result);
236
                    }
237
                    break;
238
                case 'tag':
239
                    $result = $this->tagRepository->searchTag($modifier['value']);
240
                    if ($result->count() > 0) {
241
                        $collector->setTags($result);
242
                    }
243
                    break;
244
                    break;
245
                case 'budget':
246
                    $result = $this->budgetRepository->searchBudget($modifier['value']);
247
                    if ($result->count() > 0) {
248
                        $collector->setBudgets($result);
249
                    }
250
                    break;
251
                case 'amount_is':
252
                case 'amount':
253
                    $amount = app('steam')->positive((string)$modifier['value']);
254
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
255
                    $collector->amountIs($amount);
256
                    break;
257
                case 'amount_max':
258
                case 'amount_less':
259
                    $amount = app('steam')->positive((string)$modifier['value']);
260
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
261
                    $collector->amountLess($amount);
262
                    break;
263
                case 'amount_min':
264
                case 'amount_more':
265
                    $amount = app('steam')->positive((string)$modifier['value']);
266
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $amount));
267
                    $collector->amountMore($amount);
268
                    break;
269
                case 'type':
270
                    $collector->setTypes([ucfirst($modifier['value'])]);
271
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
272
                    break;
273
                case 'date':
274
                case 'on':
275
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
276
                    $start = new Carbon($modifier['value']);
277
                    $collector->setRange($start, $start);
278
                    break;
279
                case 'date_before':
280
                case 'before':
281
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
282
                    $before = new Carbon($modifier['value']);
283
                    $collector->setBefore($before);
284
                    break;
285
                case 'date_after':
286
                case 'after':
287
                    Log::debug(sprintf('Set "%s" using collector with value "%s"', $modifier['type'], $modifier['value']));
288
                    $after = new Carbon($modifier['value']);
289
                    $collector->setAfter($after);
290
                    break;
291
            }
292
        }
293
        $collector->setAccounts($totalAccounts);
294
295
        return $collector;
296
    }
297
298
    /**
299
     * @param string $string
300
     */
301
    private function extractModifier(string $string): void
302
    {
303
        $parts = explode(':', $string);
304
        if (2 === count($parts) && '' !== trim((string)$parts[1]) && '' !== trim((string)$parts[0])) {
305
            $type  = trim((string)$parts[0]);
306
            $value = trim((string)$parts[1]);
307
            if (in_array($type, $this->validModifiers, true)) {
308
                // filter for valid type
309
                $this->modifiers->push(['type' => $type, 'value' => $value]);
310
            }
311
        }
312
    }
313
314
    /**
315
     * @param int $page
316
     */
317
    public function setPage(int $page): void
318
    {
319
        $this->page = $page;
320
    }
321
}
322