HasCapsules   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 373
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 164
dl 0
loc 373
rs 9.0399
c 5
b 0
f 0
wmc 42

28 Methods

Rating   Name   Duplication   Size   Complexity  
A getCapsuleByModel() 0 5 1
A getCapsulesPath() 0 3 1
A capsuleExists() 0 3 1
A getCapsulesSubdir() 0 3 1
A capsuleNamespaceToPath() 0 12 2
A namespaceToPath() 0 6 1
A autoloadConfigFiles() 0 11 3
A getManager() 0 3 1
A bootstrapCapsule() 0 5 1
A registerServiceProvider() 0 9 2
A getCapsuleRepositoryClass() 0 3 1
A getCapsuleList() 0 15 2
A getCapsuleSlugClass() 0 3 1
A getCapsuleViewPrefix() 0 3 1
A getCapsuleTranslationClass() 0 3 1
A getCapsuleRevisionClass() 0 3 1
A getCapsuleFormRequestClass() 0 3 1
A getCapsuleByModule() 0 7 1
A capsuleRootPath() 0 3 1
A registerPsr4Autoloader() 0 15 1
A makeCapsuleSeeder() 0 9 2
A loadCapsuleConfig() 0 18 2
A seedCapsules() 0 12 2
A capsule() 0 11 3
A getCapsuleByPath() 0 18 2
A getCapsuleByClass() 0 20 2
A getAutoloader() 0 5 2
B makeCapsule() 0 95 2

How to fix   Complexity   

Complex Class

Complex classes like HasCapsules often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use HasCapsules, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace A17\Twill\Services\Capsules;
4
5
use Illuminate\Support\Facades\File;
6
use Illuminate\Support\Str;
7
8
trait HasCapsules
9
{
10
    protected function getAutoloader()
11
    {
12
        return app()->bound('autoloader')
13
            ? app('autoloader')
14
            : require base_path('vendor/autoload.php');
15
    }
16
17
    public function getCapsuleList()
18
    {
19
        $path = $this->getCapsulesPath();
20
21
        $list = collect(config('twill.capsules.list'));
22
23
        if (!config('twill.capsules.loaded')) {
24
            $list = $list
25
                ->where('enabled', true)
26
                ->map(function ($capsule) use ($path) {
27
                    return $this->makeCapsule($capsule, $path);
28
                });
29
        }
30
31
        return $list;
32
    }
33
34
    public function getCapsuleByModel($model)
35
    {
36
        return $this->getCapsuleList()
37
            ->where('singular', Str::studly($model))
38
            ->first();
39
    }
40
41
    public function getCapsuleByModule($module)
42
    {
43
        return $this->getCapsuleList()
44
            ->filter(function ($capsule) use ($module) {
45
                return Str::lower($capsule['plural']) == Str::lower($module);
46
            })
47
            ->first();
48
    }
49
50
    /**
51
     * @return \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
52
     */
53
    public function getCapsulesPath()
54
    {
55
        return config('twill.capsules.path');
56
    }
57
58
    /**
59
     * @return \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
60
     */
61
    public function getCapsulesSubdir()
62
    {
63
        return config('twill.capsules.namespaces.subdir');
64
    }
65
66
    public function makeCapsule($capsule, $basePath = null): array
67
    {
68
        $basePath = $basePath ?? $this->getCapsulesPath();
69
70
        $capsule['name'] = Str::studly($capsule['name']);
71
72
        $capsule['module'] = Str::camel($capsule['name']);
73
74
        $capsule['plural'] = $name = $capsule['name'];
75
76
        $capsule['singular'] = $singular =
77
            $capsule['singular'] ?? Str::singular($name);
78
79
        $twillNamespace = config('twill.namespace');
0 ignored issues
show
Unused Code introduced by
The assignment to $twillNamespace is dead and can be removed.
Loading history...
80
81
        $capsule['base_namespace'] = config('twill.capsules.namespaces.base');
82
83
        $capsule['namespace'] = $capsuleNamespace = $this->getManager()->capsuleNamespace(
0 ignored issues
show
Bug introduced by
The method capsuleNamespace() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

83
        $capsule['namespace'] = $capsuleNamespace = $this->getManager()->/** @scrutinizer ignore-call */ capsuleNamespace(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
84
            $capsule['name']
85
        );
86
87
        $capsule['database_namespace'] = "$capsuleNamespace\Database";
88
89
        $capsule['seeds_namespace'] = "{$capsule['database_namespace']}\Seeds";
90
91
        $capsule['model'] = $capsule['models'] = $models =
92
            "{$capsuleNamespace}\\" .
93
            config('twill.capsules.namespaces.models');
94
        $capsule['repositories'] = $repositories =
95
            "{$capsuleNamespace}\\" .
96
            config('twill.capsules.namespaces.repositories');
97
        $capsule['controllers'] = $controllers =
98
            "{$capsuleNamespace}\\" .
99
            config('twill.capsules.namespaces.controllers');
100
        $capsule['requests'] = $requests =
101
            "{$capsuleNamespace}\\" .
102
            config('twill.capsules.namespaces.requests');
103
104
        $capsule['psr4_path'] =
105
            "$basePath/{$name}" .
106
            (filled($this->getCapsulesSubdir())
107
                ? $this->getCapsulesSubdir() . '/'
0 ignored issues
show
Bug introduced by
Are you sure $this->getCapsulesSubdir() of type Illuminate\Config\Reposi...ation\Application|mixed can be used in concatenation? ( Ignorable by Annotation )

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

107
                ? /** @scrutinizer ignore-type */ $this->getCapsulesSubdir() . '/'
Loading history...
108
                : '');
109
110
        $capsule['base_path'] = $basePath;
111
112
        $capsule['database_psr4_path'] = "$basePath/{$name}/database";
113
114
        $capsule['seeds_psr4_path'] = "{$capsule['database_psr4_path']}/seeds";
115
116
        $capsule['root_path'] = $root = $this->capsuleRootPath($capsule);
0 ignored issues
show
Unused Code introduced by
The assignment to $root is dead and can be removed.
Loading history...
117
118
        $capsule['migrations_dir'] = "{$capsule['root_path']}/database/migrations";
119
120
        $capsule['lang_dir'] = "{$capsule['root_path']}/resources/lang";
121
122
        $capsule['views_dir'] = "{$capsule['root_path']}/resources/views";
123
124
        $capsule['view_prefix'] = "{$name}.resources.views.admin";
125
126
        $capsule['routes_file'] = "{$capsule['root_path']}/routes/admin.php";
127
128
        $capsule['model'] = "{$models}\\{$singular}";
129
130
        $capsule['models_dir'] = $this->namespaceToPath($capsule, $models);
131
132
        $capsule['translation'] = "{$models}\\{$singular}Translation";
133
134
        $capsule['slug'] = "{$models}\\{$singular}Slug";
135
136
        $capsule['revision'] = "{$models}\\{$singular}Revision";
137
138
        $capsule['repository'] = "{$repositories}\\{$singular}Repository";
139
140
        $capsule['repositories_dir'] = $this->namespaceToPath(
141
            $capsule,
142
            $repositories
143
        );
144
145
        $capsule['controller'] = "{$controllers}\\{$singular}Controller";
146
147
        $capsule['controllers_dir'] = $this->namespaceToPath(
148
            $capsule,
149
            $controllers
150
        );
151
152
        $capsule['formRequest'] = "{$requests}\\{$singular}Request";
153
154
        $capsule['requests_dir'] = $this->namespaceToPath($capsule, $requests);
155
156
        $capsule['config_file'] = "$basePath/{$name}/config.php";
157
158
        $capsule['config'] = $this->loadCapsuleConfig($capsule);
159
160
        return $capsule;
161
    }
162
163
    public function bootstrapCapsule($capsule): void
164
    {
165
        $this->registerPsr4Autoloader($capsule);
166
        $this->autoloadConfigFiles($capsule);
167
        $this->registerServiceProvider($capsule);
168
    }
169
170
    public function registerPsr4Autoloader($capsule)
171
    {
172
        $this->getAutoloader()->setPsr4(
0 ignored issues
show
Bug introduced by
The method setPsr4() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

172
        $this->getAutoloader()->/** @scrutinizer ignore-call */ setPsr4(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
173
            $capsule['namespace'] . '\\',
174
            $capsule['psr4_path']
175
        );
176
177
        $this->getAutoloader()->setPsr4(
178
            $capsule['database_namespace'] . '\\',
179
            $capsule['database_psr4_path']
180
        );
181
182
        $this->getAutoloader()->setPsr4(
183
            $capsule['database_namespace'] . '\\Seeds\\',
184
            $capsule['database_psr4_path'] . '/seeds'
185
        );
186
    }
187
188
    public function registerServiceProvider($capsule): void
189
    {
190
        $rootPath = $this->capsuleRootPath($capsule);
191
        $capsuleName = $capsule['name'];
192
193
        $serviceProviderName = $capsuleName . 'CapsuleServiceProvider';
194
195
        if (File::exists($rootPath . '/' . $serviceProviderName . '.php')) {
196
            $this->app->register($capsule['namespace'] . '\\' . $serviceProviderName);
197
        }
198
    }
199
200
    public function capsuleRootPath($capsule)
201
    {
202
        return config('twill.capsules.path') . '/' . $capsule['name'] ?? null;
203
    }
204
205
    public function getCapsuleRepositoryClass($model)
206
    {
207
        return $this->getCapsuleByModel($model)['repository'] ?? null;
208
    }
209
210
    public function getCapsuleTranslationClass($model)
211
    {
212
        return $this->getCapsuleByModel($model)['translation'] ?? null;
213
    }
214
215
    public function getCapsuleSlugClass($model)
216
    {
217
        return $this->getCapsuleByModel($model)['slug'] ?? null;
218
    }
219
220
    public function getCapsuleRevisionClass($model)
221
    {
222
        return $this->getCapsuleByModel($model)['revision'] ?? null;
223
    }
224
225
    public function getCapsuleFormRequestClass($model)
226
    {
227
        return $this->getCapsuleByModel($model)['formRequest'] ?? null;
228
    }
229
230
    public function getCapsuleViewPrefix($capsule)
231
    {
232
        return $this->getCapsuleByModule(Str::studly($capsule))['view_prefix'] ?? null;
233
    }
234
235
    public function namespaceToPath($capsule, $namespace)
236
    {
237
        return $this->capsuleNamespaceToPath(
238
            $namespace,
239
            $capsule['namespace'],
240
            $capsule['root_path']
241
        );
242
    }
243
244
    public function capsuleNamespaceToPath(
245
        $namespace,
246
        $capsuleNamespace,
247
        $rootPath
248
    ) {
249
        $namespace = Str::after($namespace, $capsuleNamespace . '\\');
250
251
        $subdir = $this->getCapsulesSubdir();
252
253
        $subdir = filled($subdir) ? "{$subdir}/" : '';
254
255
        return "{$rootPath}/{$subdir}" . str_replace('\\', '/', $namespace);
256
    }
257
258
    public function getManager()
259
    {
260
        return $this->manager = $this->manager ?? app('twill.capsules.manager');
0 ignored issues
show
Bug Best Practice introduced by
The property manager does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
261
    }
262
263
    public function seedCapsules($illuminateSeeder)
264
    {
265
        $twillSeeder = app(CapsuleSeeder::class);
266
267
        $this->getCapsuleList()->each(function ($capsule) use (
268
            $twillSeeder,
269
            $illuminateSeeder
270
        ) {
271
            if (filled($capsuleSeeder = $this->makeCapsuleSeeder($capsule))) {
272
                $twillSeeder->setCommand($illuminateSeeder->command);
273
274
                $twillSeeder->call($capsuleSeeder);
275
            }
276
        });
277
    }
278
279
    public function makeCapsuleSeeder($capsule)
280
    {
281
        $seeder = "{$capsule['database_namespace']}\\Seeds\DatabaseSeeder";
282
283
        if (class_exists($seeder)) {
284
            return $seeder;
285
        }
286
287
        return null;
288
    }
289
290
    public function capsuleExists($module)
291
    {
292
        return filled($this->getCapsuleByModule($module));
293
    }
294
295
    public function capsule($string)
296
    {
297
        if (file_exists($string)) {
298
            return $this->getCapsuleByPath($string);
299
        }
300
301
        if (class_exists($string)) {
302
            return $this->getCapsuleByClass($string);
303
        }
304
305
        return $this->getCapsuleByModule($string);
306
    }
307
308
    public function getCapsuleByPath($path)
309
    {
310
        $capsule = $this->getCapsuleList()->first();
311
312
        if (!Str::startsWith($path, $capsule['base_path'])) {
313
            return null;
314
        }
315
316
        $name = Str::before(
317
            Str::after(Str::after($path, $capsule['base_path']), '/'),
318
            '/'
319
        );
320
321
        $name = "{$capsule['base_path']}/$name";
322
323
        return $this->getCapsuleList()
324
            ->where('root_path', $name)
325
            ->first();
326
    }
327
328
    public function getCapsuleByClass($class)
329
    {
330
        $capsule = $this->getCapsuleList()->first();
331
332
        $namespace = Str::beforeLast($class, '\\');
0 ignored issues
show
Unused Code introduced by
The assignment to $namespace is dead and can be removed.
Loading history...
333
334
        if (!Str::startsWith($class, $capsule['base_namespace'])) {
335
            return null;
336
        }
337
338
        $name = Str::before(
339
            Str::after(Str::after($class, $capsule['base_namespace']), '\\'),
340
            '\\'
341
        );
342
343
        $name = "{$capsule['base_namespace']}\\$name";
344
345
        return $this->getCapsuleList()
346
            ->where('namespace', $name)
347
            ->first();
348
    }
349
350
    public function loadCapsuleConfig($capsule)
351
    {
352
        $config = file_exists($file = $capsule['config_file'] ?? 'MISSING-CONFIG-FILE')
353
            ? require $file
354
            : [];
355
356
        $key =
357
            config('twill.capsules.capsule_config_prefix') .
358
            ".{$capsule['module']}";
359
360
        config([
361
            $key => array_replace_recursive(
362
                $config ?? [],
363
                $capsule['config'] ?? []
364
            ),
365
        ]);
366
367
        return $config;
368
    }
369
370
    public function autoloadConfigFiles($capsule)
371
    {
372
        $files = $capsule['config']['autoload']['files'] ?? null;
373
374
        if (blank($files)) {
375
            return;
376
        }
377
378
        collect($files)->each(function ($file) {
379
            if (file_exists($file)) {
380
                require_once $file;
381
            }
382
        });
383
    }
384
}
385