TwillServiceProvider   B
last analyzed

Complexity

Total Complexity 46

Size/Duplication

Total Lines 463
Duplicated Lines 0 %

Test Coverage

Coverage 98.12%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 213
c 6
b 0
f 0
dl 0
loc 463
rs 8.72
wmc 46
ccs 209
cts 213
cp 0.9812

19 Methods

Rating   Name   Duplication   Size   Complexity  
A setLocalDiskUrl() 0 8 1
A registerAndPublishViews() 0 6 1
A publishConfigs() 0 31 4
A registerAndPublishTranslations() 0 6 1
A publishAssets() 0 5 1
A check2FA() 0 10 4
A registerAliases() 0 10 3
A mergeConfigs() 0 28 5
A publishOptionalMigration() 0 8 2
A registerProviders() 0 15 4
A addViewComposers() 0 26 4
A version() 0 3 1
A publishMigrations() 0 12 2
A requireHelpers() 0 8 1
A register() 0 15 1
A boot() 0 17 1
A includeView() 0 16 3
B extendBlade() 0 75 6
A registerCommands() 0 20 1

How to fix   Complexity   

Complex Class

Complex classes like TwillServiceProvider 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 TwillServiceProvider, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace A17\Twill;
4
5
use Exception;
6
use A17\Twill\Commands\BlockMake;
7
use A17\Twill\Commands\Build;
8
use A17\Twill\Commands\CapsuleInstall;
9
use A17\Twill\Commands\CreateSuperAdmin;
10
use A17\Twill\Commands\Dev;
11
use A17\Twill\Commands\GenerateBlocks;
12
use A17\Twill\Commands\Install;
13
use A17\Twill\Commands\ListBlocks;
14
use A17\Twill\Commands\ListIcons;
15
use A17\Twill\Commands\MakeCapsule;
16
use A17\Twill\Commands\MakeSingleton;
17
use A17\Twill\Commands\ModuleMake;
18
use A17\Twill\Commands\ModuleMakeDeprecated;
19
use A17\Twill\Commands\RefreshLQIP;
20
use A17\Twill\Commands\RefreshCrops;
21
use A17\Twill\Commands\SyncLang;
22
use A17\Twill\Commands\Update;
23
use A17\Twill\Http\ViewComposers\ActiveNavigation;
24
use A17\Twill\Http\ViewComposers\CurrentUser;
25
use A17\Twill\Http\ViewComposers\FilesUploaderConfig;
26
use A17\Twill\Http\ViewComposers\Localization;
27
use A17\Twill\Http\ViewComposers\MediasUploaderConfig;
28
use A17\Twill\Models\Block;
29
use A17\Twill\Models\File;
30
use A17\Twill\Models\Media;
31
use A17\Twill\Models\User;
32
use A17\Twill\Services\Capsules\HasCapsules;
33
use A17\Twill\Services\FileLibrary\FileService;
34
use A17\Twill\Services\MediaLibrary\ImageService;
35
use Astrotomic\Translatable\TranslatableServiceProvider;
36
use Cartalyst\Tags\TagsServiceProvider;
37
use Illuminate\Database\Eloquent\Relations\Relation;
38
use Illuminate\Foundation\AliasLoader;
39
use Illuminate\Support\Facades\View;
40
use Illuminate\Support\ServiceProvider;
41
use Illuminate\Support\Str;
42
use Spatie\Activitylog\ActivitylogServiceProvider;
43
use PragmaRX\Google2FAQRCode\Google2FA as Google2FAQRCode;
44
45
class TwillServiceProvider extends ServiceProvider
46
{
47
    use HasCapsules;
0 ignored issues
show
Bug introduced by
The trait A17\Twill\Services\Capsules\HasCapsules requires the property $command which is not provided by A17\Twill\TwillServiceProvider.
Loading history...
48
49
    /**
50
     * The Twill version.
51
     *
52
     * @var string
53
     */
54
    const VERSION = '2.7.0';
55
56
    /**
57
     * Service providers to be registered.
58
     *
59
     * @var string[]
60
     */
61
    protected $providers = [
62
        RouteServiceProvider::class,
63
        AuthServiceProvider::class,
64
        ValidationServiceProvider::class,
65
        TranslatableServiceProvider::class,
66
        TagsServiceProvider::class,
67
        ActivitylogServiceProvider::class,
68
        CapsulesServiceProvider::class,
69 73
    ];
70
71 73
    private $migrationsCounter = 0;
0 ignored issues
show
introduced by
The private property $migrationsCounter is not used, and could be removed.
Loading history...
72
73 73
    /**
74 73
     * Bootstraps the package services.
75 73
     *
76
     * @return void
77 73
     */
78
    public function boot()
79 73
    {
80 73
        $this->requireHelpers();
81
82 73
        $this->publishConfigs();
83 73
        $this->publishMigrations();
84 73
        $this->publishAssets();
85
86
        $this->registerCommands();
87
88
        $this->registerAndPublishViews();
89 73
        $this->registerAndPublishTranslations();
90
91 73
        $this->extendBlade();
92 73
        $this->addViewComposers();
93 73
94 73
        $this->check2FA();
95 73
    }
96 73
97 73
    /**
98
     * @return void
99
     */
100
    private function requireHelpers()
101
    {
102
        require_once __DIR__ . '/Helpers/routes_helpers.php';
103
        require_once __DIR__ . '/Helpers/i18n_helpers.php';
104 73
        require_once __DIR__ . '/Helpers/media_library_helpers.php';
105
        require_once __DIR__ . '/Helpers/frontend_helpers.php';
106 73
        require_once __DIR__ . '/Helpers/migrations_helpers.php';
107
        require_once __DIR__ . '/Helpers/helpers.php';
108 73
    }
109 73
110
    /**
111 73
     * Registers the package services.
112 73
     *
113
     * @return void
114
     */
115
    public function register()
116
    {
117
        $this->mergeConfigs();
118 73
119 73
        $this->registerProviders();
120
        $this->registerAliases();
121
122
        Relation::morphMap([
123
            'users' => User::class,
124
            'media' => Media::class,
125
            'files' => File::class,
126 73
            'blocks' => Block::class,
127
        ]);
128 73
129 73
        config(['twill.version' => $this->version()]);
130
    }
131
132 73
    /**
133 73
     * Registers the package service providers.
134 8
     *
135 73
     * @return void
136
     */
137
    private function registerProviders()
138 73
    {
139 73
        foreach ($this->providers as $provider) {
140 3
            $this->app->register($provider);
141 73
        }
142
143 73
        if (config('twill.enabled.media-library')) {
144
            $this->app->singleton('imageService', function () {
145
                return $this->app->make(config('twill.media_library.image_service'));
146
            });
147
        }
148
149
        if (config('twill.enabled.file-library')) {
150 73
            $this->app->singleton('fileService', function () {
151
                return $this->app->make(config('twill.file_library.file_service'));
152 73
            });
153
        }
154 73
    }
155 73
156
    /**
157
     * Registers the package facade aliases.
158 73
     *
159 73
     * @return void
160
     */
161
    private function registerAliases()
162 73
    {
163
        $loader = AliasLoader::getInstance();
164
165
        if (config('twill.enabled.media-library')) {
166
            $loader->alias('ImageService', ImageService::class);
167
        }
168
169 73
        if (config('twill.enabled.file-library')) {
170
            $loader->alias('FileService', FileService::class);
171 73
        }
172 73
173 73
    }
174
175
    /**
176
     * Defines the package configuration files for publishing.
177 73
     *
178 73
     * @return void
179
     */
180
    private function publishConfigs()
181
    {
182 73
        if (config('twill.enabled.users-management')) {
183 73
            config(['auth.providers.twill_users' => [
184 73
                'driver' => 'eloquent',
185 73
                'model' => User::class,
186
            ]]);
187
188
            config(['auth.guards.twill_users' => [
189 73
                'driver' => 'session',
190 73
                'provider' => 'twill_users',
191
            ]]);
192 73
193
            if (blank(config('auth.passwords.twill_users'))) {
194 73
                config(['auth.passwords.twill_users' => [
195 73
                    'provider' => 'twill_users',
196 73
                    'table' => config('twill.password_resets_table', 'twill_password_resets'),
197 73
                    'expire' => 60,
198
                    'throttle' => 60,
199
                ]]);
200
            }
201
        }
202
203
        config(['activitylog.enabled' => config('twill.enabled.dashboard') ? true : config('twill.enabled.activitylog')]);
204 73
        config(['activitylog.subject_returns_soft_deleted_models' => true]);
205
206 73
        config(['analytics.service_account_credentials_json' => config('twill.dashboard.analytics.service_account_credentials_json', storage_path('app/analytics/service-account-credentials.json'))]);
207 73
208 73
        $this->publishes([__DIR__ . '/../config/twill-publish.php' => config_path('twill.php')], 'config');
209 73
        $this->publishes([__DIR__ . '/../config/twill-navigation.php' => config_path('twill-navigation.php')], 'config');
210 73
        $this->publishes([__DIR__ . '/../config/translatable.php' => config_path('translatable.php')], 'config');
211 73
    }
212 73
213 73
    /**
214 73
     * Merges the package configuration files into the given configuration namespaces.
215 73
     *
216 73
     * @return void
217 73
     */
218 73
    private function mergeConfigs()
219
    {
220 73
        $this->mergeConfigFrom(__DIR__ . '/../config/twill.php', 'twill');
221 73
        $this->mergeConfigFrom(__DIR__ . '/../config/frontend.php', 'twill.frontend');
222 73
        $this->mergeConfigFrom(__DIR__ . '/../config/debug.php', 'twill.debug');
223
        $this->mergeConfigFrom(__DIR__ . '/../config/seo.php', 'twill.seo');
224
        $this->mergeConfigFrom(__DIR__ . '/../config/blocks.php', 'twill.block_editor');
225 73
        $this->mergeConfigFrom(__DIR__ . '/../config/enabled.php', 'twill.enabled');
226 73
        $this->mergeConfigFrom(__DIR__ . '/../config/file-library.php', 'twill.file_library');
227 73
        $this->mergeConfigFrom(__DIR__ . '/../config/media-library.php', 'twill.media_library');
228
        $this->mergeConfigFrom(__DIR__ . '/../config/imgix.php', 'twill.imgix');
229
        $this->mergeConfigFrom(__DIR__ . '/../config/glide.php', 'twill.glide');
230 73
        $this->mergeConfigFrom(__DIR__ . '/../config/twicpics.php', 'twill.twicpics');
231 73
        $this->mergeConfigFrom(__DIR__ . '/../config/dashboard.php', 'twill.dashboard');
232
        $this->mergeConfigFrom(__DIR__ . '/../config/oauth.php', 'twill.oauth');
233 73
        $this->mergeConfigFrom(__DIR__ . '/../config/disks.php', 'filesystems.disks');
234
235 73
        if (config('twill.media_library.endpoint_type') === 'local'
236 73
            && config('twill.media_library.disk') === 'twill_media_library') {
237 73
            $this->setLocalDiskUrl('media');
238 73
        }
239 73
240 73
        if (config('twill.file_library.endpoint_type') === 'local'
241
            && config('twill.file_library.disk') === 'twill_file_library') {
242 73
            $this->setLocalDiskUrl('file');
243
        }
244 73
245
        $this->mergeConfigFrom(__DIR__ . '/../config/services.php', 'services');
246 73
    }
247 73
248
    private function setLocalDiskUrl($type)
249
    {
250 73
        config([
251 73
            'filesystems.disks.twill_' . $type . '_library.url' => request()->getScheme()
252 73
            . '://'
253
            . str_replace(['http://', 'https://'], '', config('app.url'))
254 73
            . '/storage/'
255 73
            . trim(config('twill.' . $type . '_library.local_path'), '/ '),
256 73
        ]);
257
    }
258 73
259
    private function publishMigrations()
260 73
    {
261 69
        if (config('twill.load_default_migrations', true)) {
262
            $this->loadMigrationsFrom(__DIR__ . '/../migrations/default');
263 69
        }
264 69
265 69
        $this->publishes([
266
            __DIR__ . '/../migrations/default' => database_path('migrations'),
267 73
        ], 'migrations');
268
269
        $this->publishOptionalMigration('users-2fa');
270
        $this->publishOptionalMigration('users-oauth');
271
    }
272 73
273
    private function publishOptionalMigration($feature)
274 73
    {
275 73
        if (config('twill.enabled.' . $feature, false)) {
276 73
            $this->loadMigrationsFrom(__DIR__ . '/../migrations/optional/' . $feature);
277 73
278
            $this->publishes([
279
                __DIR__ . '/../migrations/optional/' . $feature => database_path('migrations'),
280
            ], 'migrations');
281
        }
282 73
    }
283
284 73
    /**
285
     * @return void
286 73
     */
287 73
    private function publishAssets()
288 73
    {
289
        $this->publishes([
290
            __DIR__ . '/../dist' => public_path(),
291
        ], 'assets');
292
    }
293 73
294
    /**
295 73
     * @return void
296 73
     */
297
    private function registerAndPublishViews()
298
    {
299
        $viewPath = __DIR__ . '/../views';
300
301
        $this->loadViewsFrom($viewPath, 'twill');
302
        $this->publishes([$viewPath => resource_path('views/vendor/twill')], 'views');
303
    }
304
305
    /**
306
     * @return void
307
     */
308
    private function registerCommands()
309
    {
310 73
        $this->commands([
311
            Install::class,
312
            ModuleMake::class,
313
            MakeCapsule::class,
314
            MakeSingleton::class,
315
            ModuleMakeDeprecated::class,
316
            BlockMake::class,
317 5
            ListIcons::class,
318
            ListBlocks::class,
319 5
            CreateSuperAdmin::class,
320
            RefreshLQIP::class,
321 5
            RefreshCrops::class,
322
            GenerateBlocks::class,
323 5
            Build::class,
324
            Update::class,
325 5
            Dev::class,
326 5
            SyncLang::class,
327 5
            CapsuleInstall::class,
328 5
        ]);
329 4
    }
330
331
    /**
332 5
     * @param string $view
333
     * @param string $expression
334
     * @return string
335
     */
336
    private function includeView($view, $expression)
337
    {
338
        [$name] = str_getcsv($expression, ',', '\'');
339
340 73
        $partialNamespace = view()->exists('admin.' . $view . $name) ? 'admin.' : 'twill::';
341
342 73
        $view = $partialNamespace . $view . $name;
343
344 73
        $expression = explode(',', $expression);
345
        array_shift($expression);
346 73
        $expression = "(" . implode(',', $expression) . ")";
347
        if ($expression === "()") {
348 73
            $expression = '([])';
349
        }
350
351 73
        return "<?php echo \$__env->make('{$view}', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render(); ?>";
352
    }
353 73
354 5
    /**
355 73
     * Defines the package additional Blade Directives.
356
     *
357 73
     * @return void
358
     */
359 3
    private function extendBlade()
360
    {
361 3
        $blade = $this->app['view']->getEngineResolver()->resolve('blade')->getCompiler();
362 3
363
        $blade->directive('dd', function ($param) {
364 3
            return "<?php dd({$param}); ?>";
365 3
        });
366 3
367 3
        $blade->directive('dumpData', function ($data) {
368
            return sprintf("<?php (new Symfony\Component\VarDumper\VarDumper)->dump(%s); exit; ?>",
369 3
                null != $data ? $data : "get_defined_vars()");
370
        });
371
372
        $blade->directive('formField', function ($expression) {
373 3
            return $this->includeView('partials.form._', $expression);
374 3
        });
375 3
376 3
        $blade->directive('partialView', function ($expression) {
377 2
378
            $expressionAsArray = str_getcsv($expression, ',', '\'');
379
380 3
            [$moduleName, $viewName] = $expressionAsArray;
381 3
            $partialNamespace = 'twill::partials';
382 3
383 3
            $viewModule = "twillViewName($moduleName, '{$viewName}')";
384 3
            $viewApplication = "'admin.partials.{$viewName}'";
385 3
            $viewModuleTwill = "'twill::'.$moduleName.'.{$viewName}'";
386 3
            $view = $partialNamespace . "." . $viewName;
387 3
388 3
            if (!isset($moduleName) || is_null($moduleName)) {
389
                $viewModule = $viewApplication;
390
            }
391 73
392
            $expression = explode(',', $expression);
393 73
            $expression = array_slice($expression, 2);
394 1
            $expression = "(" . implode(',', $expression) . ")";
395 1
            if ($expression === "()") {
396 1
                $expression = '([])';
397 73
            }
398
399 73
            return "<?php
400 1
            if( view()->exists($viewModule)) {
401 73
                echo \$__env->make($viewModule, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
402
            } elseif( view()->exists($viewApplication)) {
403 73
                echo \$__env->make($viewApplication, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
404 73
            } elseif( view()->exists($viewModuleTwill)) {
405 73
                echo \$__env->make($viewModuleTwill, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
406 73
            } elseif( view()->exists('$view')) {
407 73
                echo \$__env->make('$view', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
408
            }
409 73
            ?>";
410 73
        });
411 73
412 73
        $blade->directive('pushonce', function ($expression) {
413 73
            [$pushName, $pushSub] = explode(':', trim(substr($expression, 1, -1)));
414 73
            $key = '__pushonce_' . $pushName . '_' . str_replace('-', '_', $pushSub);
415
            return "<?php if(! isset(\$__env->{$key})): \$__env->{$key} = 1; \$__env->startPush('{$pushName}'); ?>";
416
        });
417 73
418
        $blade->directive('endpushonce', function () {
419
            return '<?php $__env->stopPush(); endif; ?>';
420
        });
421
422
        $blade->component('twill::partials.form.utils._fieldset', 'formFieldset');
423
        $blade->component('twill::partials.form.utils._columns', 'formColumns');
424 73
        $blade->component('twill::partials.form.utils._collapsed_fields', 'formCollapsedFields');
425
        $blade->component('twill::partials.form.utils._connected_fields', 'formConnectedFields');
426 73
        $blade->component('twill::partials.form.utils._inline_checkboxes', 'formInlineCheckboxes');
427 73
428
        if (method_exists($blade, 'aliasComponent')) {
429
            $blade->aliasComponent('twill::partials.form.utils._fieldset', 'formFieldset');
430 73
            $blade->aliasComponent('twill::partials.form.utils._columns', 'formColumns');
431 73
            $blade->aliasComponent('twill::partials.form.utils._collapsed_fields', 'formCollapsedFields');
432
            $blade->aliasComponent('twill::partials.form.utils._connected_fields', 'formConnectedFields');
433
            $blade->aliasComponent('twill::partials.form.utils._inline_checkboxes', 'formInlineCheckboxes');
434 73
        }
435 73
436
    }
437
438 73
    /**
439
     * Registers the package additional View Composers.
440 73
     *
441 52
     * @return void
442 52
     */
443
    private function addViewComposers()
444 52
    {
445
        if (config('twill.enabled.users-management')) {
446 52
            View::composer(['admin.*', 'twill::*'], CurrentUser::class);
447 73
        }
448
449 73
        if (config('twill.enabled.media-library')) {
450 73
            View::composer('twill::layouts.main', MediasUploaderConfig::class);
451
        }
452
453
        if (config('twill.enabled.file-library')) {
454
            View::composer('twill::layouts.main', FilesUploaderConfig::class);
455
        }
456
457 73
        View::composer('twill::partials.navigation.*', ActiveNavigation::class);
458
459 73
        View::composer(['admin.*', 'templates.*', 'twill::*'], function ($view) {
460
            $with = array_merge([
461 73
                'renderForBlocks' => false,
462 73
                'renderForModal' => false,
463 73
            ], $view->getData());
464
465
            return $view->with($with);
466
        });
467
468
        View::composer(['admin.*', 'twill::*'], Localization::class);
469
    }
470 73
471
    /**
472 73
     * Registers and publishes the package additional translations.
473
     *
474
     * @return void
475
     */
476
    private function registerAndPublishTranslations()
477
    {
478
        $translationPath = __DIR__ . '/../lang';
479
480
        $this->loadTranslationsFrom($translationPath, 'twill');
481
        $this->publishes([$translationPath => resource_path('lang/vendor/twill')], 'translations');
482
    }
483
484
    /**
485
     * Get the version number of Twill.
486
     *
487
     * @return string
488
     */
489
    public function version()
490
    {
491
        return static::VERSION;
492
    }
493
494
    /**
495
     * In case 2FA is enabled, we need to check if a QRCode compatible package is
496
     * installed.
497
     */
498
    public function check2FA()
499
    {
500
        if (!$this->app->runningInConsole() || !config('twill.enabled.users-2fa')) {
501
            return;
502
        }
503
504
        if (blank((new Google2FAQRCode())->getQrCodeService()))
505
        {
506
            throw new Exception(
507
                "Twill ERROR: As you have 2FA enabled, you also need to install a QRCode service package, please check https://github.com/antonioribeiro/google2fa-qrcode#built-in-qrcode-rendering-services"
508
            );
509
        }
510
    }
511
}
512