Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — add-update-command ( 3eac9b )
by Pedro
15:29
created

UpgradeContext::searchTokens()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 51
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 11
eloc 26
c 1
b 0
f 1
nc 7
nop 2
dl 0
loc 51
rs 7.3166

How to fix   Long Method    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
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4
5
use Composer\InstalledVersions;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Arr;
8
9
class UpgradeContext
10
{
11
    protected Filesystem $files;
12
13
    protected string $basePath;
14
15
    protected array $composerJson = [];
16
17
    protected array $searchCache = [];
18
19
    protected array $fileCache = [];
20
21
    protected array $defaultScanDirectories = [
22
        'app',
23
        'config',
24
        'resources/views',
25
        'resources/lang',
26
        'routes',
27
        'database/factories',
28
        'database/seeders',
29
    ];
30
31
    protected array $searchableExtensions = ['php'];
32
33
    public function __construct(
34
        protected readonly string $targetVersion,
35
        ?Filesystem $filesystem = null,
36
        ?string $basePath = null
37
    ) {
38
        $this->files = $filesystem ?? new Filesystem();
39
        $this->basePath = $this->normalizePath($basePath ?? $this->defaultBasePath());
40
    }
41
42
    public function targetVersion(): string
43
    {
44
        return $this->targetVersion;
45
    }
46
47
    public function basePath(string $path = ''): string
48
    {
49
        $path = ltrim($path, "/\\");
50
51
        return $this->normalizePath($this->basePath.($path !== '' ? '/'.$path : ''));
52
    }
53
54
    public function fileExists(string $relativePath): bool
55
    {
56
        return $this->files->exists($this->basePath($relativePath));
57
    }
58
59
    public function readFile(string $relativePath): ?string
60
    {
61
        if (isset($this->fileCache[$relativePath])) {
62
            return $this->fileCache[$relativePath];
63
        }
64
65
        $fullPath = $this->basePath($relativePath);
66
67
        if (! $this->files->exists($fullPath)) {
68
            return null;
69
        }
70
71
        try {
72
            return $this->fileCache[$relativePath] = $this->files->get($fullPath);
73
        } catch (\Throwable $exception) {
74
            return null;
75
        }
76
    }
77
78
    public function composerJson(): array
79
    {
80
        if (! empty($this->composerJson)) {
81
            return $this->composerJson;
82
        }
83
84
        $content = $this->readFile('composer.json');
85
86
        if (! $content) {
87
            return $this->composerJson = [];
88
        }
89
90
        return $this->composerJson = json_decode($content, true) ?? [];
91
    }
92
93
    public function composerRequirement(string $package): ?string
94
    {
95
        $composer = $this->composerJson();
96
97
        return Arr::get($composer, "require.$package") ?? Arr::get($composer, "require-dev.$package");
98
    }
99
100
    public function composerRequirementSection(string $package): ?string
101
    {
102
        $composer = $this->composerJson();
103
104
        if (array_key_exists($package, $composer['require'] ?? [])) {
105
            return 'require';
106
        }
107
108
        if (array_key_exists($package, $composer['require-dev'] ?? [])) {
109
            return 'require-dev';
110
        }
111
112
        return null;
113
    }
114
115
    public function hasComposerPackage(string $package): bool
116
    {
117
        return $this->composerRequirement($package) !== null;
118
    }
119
120
    public function composerMinimumStability(): ?string
121
    {
122
        $composer = $this->composerJson();
123
124
        return $composer['minimum-stability'] ?? null;
125
    }
126
127
    public function installedPackageVersion(string $package): ?string
128
    {
129
        if (! InstalledVersions::isInstalled($package)) {
130
            return null;
131
        }
132
133
        return InstalledVersions::getVersion($package) ?? InstalledVersions::getPrettyVersion($package);
134
    }
135
136
    public function installedPackagePrettyVersion(string $package): ?string
137
    {
138
        if (! InstalledVersions::isInstalled($package)) {
139
            return null;
140
        }
141
142
        return InstalledVersions::getPrettyVersion($package);
143
    }
144
145
    public function packageMajorVersion(string $package): ?int
146
    {
147
        $pretty = $this->installedPackagePrettyVersion($package);
148
149
        if (! $pretty) {
150
            return null;
151
        }
152
153
        if (preg_match('/(\d+)/', $pretty, $matches)) {
154
            return (int) $matches[1];
155
        }
156
157
        return null;
158
    }
159
160
    public function searchTokens(array $tokens, array $directories = null): array
161
    {
162
        sort($tokens);
163
164
        $directories = $directories ?? $this->defaultScanDirectories;
165
166
        $cacheKey = md5(json_encode([$tokens, $directories]));
167
168
        if (isset($this->searchCache[$cacheKey])) {
169
            return $this->searchCache[$cacheKey];
170
        }
171
172
        $results = array_fill_keys($tokens, []);
173
174
        foreach ($directories as $directory) {
175
            $absoluteDirectory = $this->resolvePath($directory);
176
177
            if (! $this->files->isDirectory($absoluteDirectory)) {
178
                continue;
179
            }
180
181
            foreach ($this->files->allFiles($absoluteDirectory) as $file) {
182
                $path = $file->getRealPath();
183
184
                if ($path === false) {
185
                    continue;
186
                }
187
188
                if ($this->shouldSkipFile($file->getFilename())) {
189
                    continue;
190
                }
191
192
                try {
193
                    $contents = $this->files->get($path);
194
                } catch (\Throwable $exception) {
195
                    continue;
196
                }
197
198
                foreach ($tokens as $token) {
199
                    if (str_contains($contents, $token)) {
200
                        $results[$token][] = $this->relativePath($path);
201
                    }
202
                }
203
            }
204
        }
205
206
        foreach ($results as $token => $paths) {
207
            $results[$token] = array_values(array_unique($paths));
208
        }
209
210
        return $this->searchCache[$cacheKey] = $results;
211
    }
212
213
    public function defaultScanDirectories(): array
214
    {
215
        return $this->defaultScanDirectories;
216
    }
217
218
    public function writeFile(string $relativePath, string $contents): bool
219
    {
220
        $fullPath = $this->basePath($relativePath);
221
222
        try {
223
            $this->files->ensureDirectoryExists(dirname($fullPath));
224
            $this->files->put($fullPath, $contents);
225
            $this->fileCache[$relativePath] = $contents;
226
227
            if ($relativePath === 'composer.json') {
228
                $this->composerJson = json_decode($contents, true) ?? [];
229
            }
230
231
            return true;
232
        } catch (\Throwable $exception) {
233
            return false;
234
        }
235
    }
236
237
    public function updateComposerJson(callable $callback): bool
238
    {
239
        $composer = $this->composerJson();
240
241
        $updatedComposer = $composer;
242
243
        $callback($updatedComposer);
244
245
        if ($updatedComposer === $composer) {
246
            return true;
247
        }
248
249
        $encoded = json_encode($updatedComposer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
250
251
        if ($encoded === false) {
252
            return false;
253
        }
254
255
        return $this->writeFile('composer.json', $encoded.PHP_EOL);
256
    }
257
258
    public function relativePath(string $absolutePath): string
259
    {
260
        $normalized = $this->normalizePath($absolutePath);
261
262
        if (str_starts_with($normalized, $this->basePath.'/')) {
263
            return substr($normalized, strlen($this->basePath) + 1);
264
        }
265
266
        return $normalized;
267
    }
268
269
    protected function resolvePath(string $path): string
270
    {
271
        if ($this->files->isDirectory($path) || $this->files->exists($path)) {
272
            return $this->normalizePath($path);
273
        }
274
275
        return $this->basePath($path);
276
    }
277
278
    protected function shouldSkipFile(string $filename): bool
279
    {
280
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
0 ignored issues
show
Bug introduced by
It seems like pathinfo($filename, Back...ade\PATHINFO_EXTENSION) can also be of type array; however, parameter $string of strtolower() 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

280
        $extension = strtolower(/** @scrutinizer ignore-type */ pathinfo($filename, PATHINFO_EXTENSION));
Loading history...
281
282
        if (! in_array($extension, $this->searchableExtensions, true)) {
283
            return true;
284
        }
285
286
        return false;
287
    }
288
289
    protected function normalizePath(string $path): string
290
    {
291
        $path = str_replace(['\\', '//'], '/', $path);
292
293
        return rtrim($path, '/');
294
    }
295
296
    protected function defaultBasePath(): string
297
    {
298
        return $this->normalizePath(base_path());
299
    }
300
}
301