Passed
Push — master ( ae3f18...b8bba4 )
by Darko
10:59
created

CollectionHandler::insertOrGetCollection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 38
rs 9.568
c 0
b 0
f 0
cc 2
nc 2
nop 11

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Services\Binaries;
6
7
use App\Models\Collection;
8
use App\Services\XrefService;
9
use Blacklight\CollectionsCleaning;
0 ignored issues
show
Bug introduced by
The type Blacklight\CollectionsCleaning was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Illuminate\Support\Facades\DB;
11
use Illuminate\Support\Facades\Log;
12
13
/**
14
 * Handles collection record creation and retrieval during header storage.
15
 */
16
final class CollectionHandler
17
{
18
    private CollectionsCleaning $collectionsCleaning;
19
20
    private XrefService $xrefService;
21
22
    /** @var array<string, int> Cached collection IDs by key */
23
    private array $collectionIds = [];
24
25
    /** @var array<int, true> IDs of collections created in this batch */
26
    private array $insertedCollectionIds = [];
27
28
    /** @var array<string, true> Collection hashes touched in this batch */
29
    private array $batchCollectionHashes = [];
30
31
    public function __construct(
32
        ?CollectionsCleaning $collectionsCleaning = null,
33
        ?XrefService $xrefService = null
34
    ) {
35
        $this->collectionsCleaning = $collectionsCleaning ?? new CollectionsCleaning;
36
        $this->xrefService = $xrefService ?? new XrefService;
37
    }
38
39
    /**
40
     * Reset state for a new batch.
41
     */
42
    public function reset(): void
43
    {
44
        $this->collectionIds = [];
45
        $this->insertedCollectionIds = [];
46
        $this->batchCollectionHashes = [];
47
    }
48
49
    /**
50
     * Get or create a collection for the given header.
51
     *
52
     * @return int|null Collection ID or null on failure
53
     */
54
    public function getOrCreateCollection(
55
        array $header,
56
        int $groupId,
57
        string $groupName,
58
        int $totalFiles,
59
        string $batchNoise
60
    ): ?int {
61
        $collMatch = $this->collectionsCleaning->collectionsCleaner(
62
            $header['matches'][1],
63
            $groupName
64
        );
65
66
        $collectionKey = $collMatch['name'].$totalFiles;
67
68
        // Return cached ID if already processed this batch
69
        if (isset($this->collectionIds[$collectionKey])) {
70
            return $this->collectionIds[$collectionKey];
71
        }
72
73
        $collectionHash = sha1($collectionKey);
74
        $this->batchCollectionHashes[$collectionHash] = true;
75
76
        $headerDate = is_numeric($header['Date']) ? (int) $header['Date'] : strtotime($header['Date']);
77
        $now = now()->timestamp;
78
        $unixtime = min($headerDate, $now) ?: $now;
79
80
        $existingXref = Collection::whereCollectionhash($collectionHash)->value('xref');
81
        $headerTokens = $this->xrefService->extractTokens($header['Xref'] ?? '');
82
        $newTokens = $this->xrefService->diffNewTokens($existingXref, $header['Xref'] ?? '');
83
        $finalXrefAppend = implode(' ', $newTokens);
84
85
        $subject = substr(mb_convert_encoding($header['matches'][1], 'UTF-8', mb_list_encodings()), 0, 255);
0 ignored issues
show
Bug introduced by
It seems like mb_convert_encoding($hea...', mb_list_encodings()) can also be of type array; however, parameter $string of substr() does only seem to accept string, 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

85
        $subject = substr(/** @scrutinizer ignore-type */ mb_convert_encoding($header['matches'][1], 'UTF-8', mb_list_encodings()), 0, 255);
Loading history...
86
        $fromName = mb_convert_encoding($header['From'], 'UTF-8', mb_list_encodings());
87
88
        $driver = DB::getDriverName();
89
90
        try {
91
            $collectionId = $this->insertOrGetCollection(
92
                $driver,
93
                $subject,
94
                $fromName,
0 ignored issues
show
Bug introduced by
It seems like $fromName can also be of type array; however, parameter $fromName of App\Services\Binaries\Co...insertOrGetCollection() does only seem to accept string, 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

94
                /** @scrutinizer ignore-type */ $fromName,
Loading history...
95
                $unixtime,
96
                $headerTokens,
97
                $finalXrefAppend,
98
                $groupId,
99
                $totalFiles,
100
                $collectionHash,
101
                $collMatch['id'],
102
                $batchNoise
103
            );
104
105
            if ($collectionId > 0) {
106
                $this->collectionIds[$collectionKey] = $collectionId;
107
108
                return $collectionId;
109
            }
110
        } catch (\Throwable $e) {
111
            if (config('app.debug') === true) {
112
                Log::error('Collection insert failed: '.$e->getMessage());
113
            }
114
        }
115
116
        return null;
117
    }
118
119
    private function insertOrGetCollection(
120
        string $driver,
121
        string $subject,
122
        string $fromName,
123
        int $unixtime,
124
        array $headerTokens,
125
        string $finalXrefAppend,
126
        int $groupId,
127
        int $totalFiles,
128
        string $collectionHash,
129
        int $regexId,
130
        string $batchNoise
131
    ): int {
132
        if ($driver === 'sqlite') {
133
            return $this->insertCollectionSqlite(
134
                $subject,
135
                $fromName,
136
                $unixtime,
137
                $headerTokens,
138
                $groupId,
139
                $totalFiles,
140
                $collectionHash,
141
                $regexId,
142
                $batchNoise
143
            );
144
        }
145
146
        return $this->insertCollectionMysql(
147
            $subject,
148
            $fromName,
149
            $unixtime,
150
            $headerTokens,
151
            $finalXrefAppend,
152
            $groupId,
153
            $totalFiles,
154
            $collectionHash,
155
            $regexId,
156
            $batchNoise
157
        );
158
    }
159
160
    private function insertCollectionSqlite(
161
        string $subject,
162
        string $fromName,
163
        int $unixtime,
164
        array $headerTokens,
165
        int $groupId,
166
        int $totalFiles,
167
        string $collectionHash,
168
        int $regexId,
169
        string $batchNoise
170
    ): int {
171
        DB::statement(
172
            'INSERT OR IGNORE INTO collections (subject, fromname, date, xref, groups_id, totalfiles, collectionhash, collection_regexes_id, dateadded, noise) VALUES (?, ?, datetime(?, "unixepoch"), ?, ?, ?, ?, datetime("now"), ?)',
173
            [
174
                $subject,
175
                $fromName,
176
                $unixtime,
177
                implode(' ', $headerTokens),
178
                $groupId,
179
                $totalFiles,
180
                $collectionHash,
181
                $regexId,
182
                $batchNoise,
183
            ]
184
        );
185
186
        $lastId = (int) DB::connection()->getPdo()->lastInsertId();
187
        if ($lastId > 0) {
188
            $this->insertedCollectionIds[$lastId] = true;
189
190
            return $lastId;
191
        }
192
193
        return (int) (Collection::whereCollectionhash($collectionHash)->value('id') ?? 0);
194
    }
195
196
    private function insertCollectionMysql(
197
        string $subject,
198
        string $fromName,
199
        int $unixtime,
200
        array $headerTokens,
201
        string $finalXrefAppend,
202
        int $groupId,
203
        int $totalFiles,
204
        string $collectionHash,
205
        int $regexId,
206
        string $batchNoise
207
    ): int {
208
        $insertSql = 'INSERT INTO collections '
209
            .'(subject, fromname, date, xref, groups_id, totalfiles, collectionhash, collection_regexes_id, dateadded, noise) '
210
            .'VALUES (?, ?, FROM_UNIXTIME(?), ?, ?, ?, ?, ?, NOW(), ?) '
211
            .'ON DUPLICATE KEY UPDATE dateadded = NOW()';
212
213
        $bindings = [
214
            $subject,
215
            $fromName,
216
            $unixtime,
217
            implode(' ', $headerTokens),
218
            $groupId,
219
            $totalFiles,
220
            $collectionHash,
221
            $regexId,
222
            $batchNoise,
223
        ];
224
225
        if ($finalXrefAppend !== '') {
226
            $insertSql .= ', xref = CONCAT(xref, "\\n", ?)';
227
            $bindings[] = $finalXrefAppend;
228
        }
229
230
        DB::statement($insertSql, $bindings);
231
232
        $lastId = (int) DB::connection()->getPdo()->lastInsertId();
233
        if ($lastId > 0) {
234
            $this->insertedCollectionIds[$lastId] = true;
235
236
            return $lastId;
237
        }
238
239
        return (int) (Collection::whereCollectionhash($collectionHash)->value('id') ?? 0);
240
    }
241
242
    /**
243
     * Get IDs created in this batch.
244
     */
245
    public function getInsertedIds(): array
246
    {
247
        return array_keys($this->insertedCollectionIds);
248
    }
249
250
    /**
251
     * Get all collection IDs processed this batch.
252
     */
253
    public function getAllIds(): array
254
    {
255
        return array_values(array_unique(array_map('intval', $this->collectionIds)));
256
    }
257
258
    /**
259
     * Get all collection hashes processed this batch.
260
     */
261
    public function getBatchHashes(): array
262
    {
263
        return array_keys($this->batchCollectionHashes);
264
    }
265
}
266
267