Artem-Schander/L5Modular

View on GitHub
src/ModuleServiceProvider.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

namespace ArtemSchander\L5Modular;

use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;
use Illuminate\Database\Eloquent\Factory;

use ArtemSchander\L5Modular\Services\L5Modular;

class ModuleServiceProvider extends ServiceProvider
{
    use Traits\RegisteresCommands;

    protected $files;

    /**
     * Bootstrap the application services.
     *
     * @param  \Illuminate\Filesystem\Filesystem  $files
     *
     * @return void
     */
    public function boot(Filesystem $files)
    {
        $this->files = $files;
        if (is_dir(app_path('Modules'))) {

            $modules = array_map('class_basename', $this->files->directories(app_path('Modules')));
            foreach ($modules as $module) {
                // Allow routes to be cached
                $this->registerModule($module);
            }
        }
    }

    /**
     * Register a module by its name
     *
     * @param  string $name
     *
     * @return void
     */
    protected function registerModule(string $name)
    {
        $this->registerConfig($name);

        $enabled = config("{$name}.enabled", true);
        if ($enabled) {
            $this->registerRoutes($name);
            $this->registerHelpers($name);
            $this->registerViews($name);
            $this->registerTranslations($name);
            $this->registerMigrations($name);
            $this->registerFactories($name);
        }
    }

    /**
     * Register the config file for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerConfig(string $module)
    {
        $key = "modules.specific.{$module}";
        $config = $this->app['config']->get($key, []);

        $file = app_path("Modules/{$module}/config.php");
        if ($this->files->exists($file)) {
            $config = array_merge(require $file, $config);
        }

        if ($config) {
            $this->app['config']->set($key, $config);
            if (! $this->app['config']->get($module)) {
                $this->app['config']->set($module, $config);
            }
        }
    }

    /**
     * Register the routes for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerRoutes(string $module)
    {
        if (! $this->app->routesAreCached()) {
            extract($this->getRoutingConfig($module));

            foreach ($types as $type) {
                $this->registerRoute($module, $path, $namespace, $type);
            }
        }
    }

    /**
     * Registeres a simgle route
     *
     * @param  string $module
     * @param  string $path
     * @param  string $namespace
     * @param  string $type
     *
     * @return void
     */
    protected function registerRoute(string $module, string $path, string $namespace, string $type)
    {
        if ($type === 'simple') $file = 'routes.php';
        else $file = "{$type}.php";

        $file = str_replace('//', '/', app_path("Modules/{$module}/{$path}/{$file}"));

        $allowed = [ 'web', 'api', 'simple' ];
        if (in_array($type, $allowed) && $this->files->exists($file)) {
            if ($type === 'simple') Route::namespace($namespace)->group($file);
            else Route::middleware($type)->namespace($namespace)->group($file);
        }
    }

    /**
     * Collect the needed data to register the routes
     *
     * @param  string $module
     *
     * @return array
     */
    protected function getRoutingConfig(string $module)
    {
        $types = config("{$module}.routing", config('modules.default.routing'));
        $path = config("{$module}.structure.routes", config('modules.default.structure.routes'));

        $cp = config("{$module}.structure.controllers", config('modules.default.structure.controllers'));
        $namespace = $this->app->getNamespace() . trim("Modules\\{$module}\\" . implode('\\', explode('/', $cp)), '\\');

        return compact('types', 'path', 'namespace');
    }

    /**
     * Register the helpers file for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerHelpers(string $module)
    {
        if ($file = $this->prepareComponent($module, 'helpers', 'helpers.php')) {
            include_once $file;
        }
    }

    /**
     * Register the views for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerViews(string $module)
    {
        if ($views = $this->prepareComponent($module, 'views')) {
            $this->loadViewsFrom($views, $module);
        }
    }

    /**
     * Register the translations for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerTranslations(string $module)
    {
        if ($translations = $this->prepareComponent($module, 'translations')) {
            $this->loadTranslationsFrom($translations, $module);
        }
    }

    /**
     * Register the migrations for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerMigrations(string $module)
    {
        if ($migrations = $this->prepareComponent($module, 'migrations')) {
            $this->loadMigrationsFrom($migrations);
        }
    }

    /**
     * Register the factories for a module by its name
     *
     * @param  string $module
     *
     * @return void
     */
    protected function registerFactories(string $module)
    {
        if ($factories = $this->prepareComponent($module, 'factories')) {
            $this->app->make(Factory::class)->load($factories);
        }
    }

    /**
     * Prepare component registration
     *
     * @param  string $module
     * @param  string $component
     * @param  string $file
     *
     * @return string
     */
    protected function prepareComponent(string $module, string $component, string $file = '')
    {
        $path = config("{$module}.structure.{$component}", config("modules.default.structure.{$component}"));
        $resource = rtrim(str_replace('//', '/', app_path("Modules/{$module}/{$path}/{$file}")), '/');

        if (! ($file && $this->files->exists($resource)) && ! (!$file && $this->files->isDirectory($resource))) {
            $resource = false;
        }
        return $resource;
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerPublishConfig();
        $this->registerCommands();
        $this->registerService();
    }

    /**
     * register config
     *
     * @return void
     */
    protected function registerPublishConfig()
    {
        $configPath = __DIR__ . '/config/modules.php';
        $publishPath = $this->app->configPath('modules.php');

        $this->mergeConfigFrom($configPath, 'modules');
        $this->publishes([ $configPath => $publishPath ], 'config');
    }

    /**
     * register service
     *
     * @return void
     */
    protected function registerService()
    {
        $this->app->singleton('l5modular', function($app) {
            return new L5Modular($app['config'], $app['files']);
        });
    }
}