├── README.md ├── composer.json ├── config └── module_manager.php ├── helpers ├── file.php └── helpers.php ├── resources └── stubs │ ├── .gitkeep │ ├── _folder-structure │ ├── config │ │ └── .gitkeep │ ├── database │ │ ├── .gitkeep │ │ ├── migrations │ │ │ └── .gitkeep │ │ └── seeds │ │ │ └── .gitkeep │ ├── helpers │ │ ├── .gitkeep │ │ └── helpers.php │ ├── module.json │ ├── resources │ │ ├── .gitkeep │ │ ├── assets │ │ │ ├── js │ │ │ │ └── .gitkeep │ │ │ └── sass │ │ │ │ └── .gitkeep │ │ ├── lang │ │ │ └── .gitkeep │ │ └── views │ │ │ └── .gitkeep │ ├── routes │ │ ├── api.php │ │ └── web.php │ └── src │ │ ├── Http │ │ ├── .gitkeep │ │ └── Controllers │ │ │ └── .gitkeep │ │ ├── Models │ │ └── .gitkeep │ │ └── Providers │ │ ├── BootstrapModuleServiceProvider.php │ │ ├── InstallModuleServiceProvider.php │ │ ├── ModuleProvider.php │ │ ├── RepositoryServiceProvider.php │ │ ├── RouteServiceProvider.php │ │ └── UninstallModuleServiceProvider.php │ ├── console │ └── command.stub │ ├── controllers │ ├── controller.resource.stub │ └── controller.stub │ ├── facades │ └── facade.stub │ ├── middleware │ └── middleware.stub │ ├── models │ ├── model.contract.stub │ └── model.stub │ ├── providers │ └── provider.stub │ ├── repositories │ ├── repository.cache-decorator.stub │ ├── repository.contract.stub │ ├── repository.no-cache.stub │ └── repository.stub │ ├── requests │ └── request.stub │ ├── seeds │ └── seeder.stub │ ├── services │ └── service.stub │ └── support │ └── support.stub ├── src ├── Console │ ├── Commands │ │ ├── DisableModuleCommand.php │ │ ├── EnableModuleCommand.php │ │ ├── InstallModuleCommand.php │ │ ├── ModuleSeedCommand.php │ │ ├── RouteListCommand.php │ │ └── UninstallModuleCommand.php │ ├── Generators │ │ ├── AbstractGenerator.php │ │ ├── MakeCommand.php │ │ ├── MakeController.php │ │ ├── MakeFacade.php │ │ ├── MakeMiddleware.php │ │ ├── MakeMigration.php │ │ ├── MakeModel.php │ │ ├── MakeModule.php │ │ ├── MakeProvider.php │ │ ├── MakeRepository.php │ │ ├── MakeRequest.php │ │ ├── MakeSeeder.php │ │ ├── MakeService.php │ │ ├── MakeSupport.php │ │ └── MakeView.php │ ├── Migrations │ │ ├── ModuleMigrateCommand.php │ │ └── RollbackCommand.php │ └── ModuleInfoTrait.php ├── Events │ ├── ModuleDisabled.php │ ├── ModuleEnabled.php │ └── RemovedModule.php ├── Providers │ ├── ConsoleServiceProvider.php │ ├── LoadModulesServiceProvider.php │ └── ModuleProvider.php ├── Services │ └── ModuleMigrator.php └── Support │ ├── Facades │ └── ModulesManagementFacade.php │ └── ModulesManagement.php └── tests └── Unit └── ModuleManagerTest.php /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Module Manager 2 | - [Introduction](#introduction) 3 | - [Installation](#installation) 4 | - [Folder Structure](#folder-structure) 5 | - Uses 6 | - [Configuration](#configuration) 7 | - [Available Commands](#available-commands) 8 | - [Loading Component](#loading-component) 9 | - [Loading View](#loading-view) 10 | - [Loading Translation](#loading-translation) 11 | - [Loading Config File](#loading-config-file) 12 | - [Register Middleware](#register-middleware) 13 | 14 | # Introduction 15 | When you work on small project, you will feel laravel default structure 16 | is enough. When your project grows up, you will think to divide 17 | your app into modules where each module will contain all of it resources 18 | such as Controllers, Models, Views, Migrations, Config etc. This `laravel-module-manager` 19 | package will help you to manage laravel modular application easily. 20 | 21 | ### Installation 22 | 23 | - laravel 5.4 or 5.5 24 | 25 | composer require mrabbani/laravel-module-manager 26 | 27 | - Laravel 5.3, Add the following line to your `composer.json` file and run `composer install` in your terminal. 28 | 29 | "mrabbani/laravel-module-manager": "^1.4" 30 | 31 | If you are using *Laravel<5.5* you have to add module manager service provider to `config/app.php` file 32 | 33 | `Mrabbani\ModuleManager\Providers\ModuleProvider::class,` 34 | 35 | To create new module run the bellow command: 36 | 37 | php artisan module:create name-of-your-module 38 | php artisan module:install {module_alias_name} 39 | 40 | ### Folder Structure 41 | If your module name is `module1` the module structure will be 42 | 43 | ![Module Structure](https://mrabbani.github.io/public/images/module_structure.png "Module Structure") 44 | 45 | ### Configuration 46 | 47 | By default, all of your module will be placed inside `modules` directory 48 | into your application's base directory. If you want to change publish 49 | `module_manager` config file by 50 | 51 | `php artisan vendor:publish` 52 | 53 | Now you can change the default *modules* directory by changing 54 | `module_directory` value of `config/module_manager.php` file. 55 | 56 | ### Available Commands 57 | 58 | To see all module related commands run `php artisan` into terminal. 59 | Available commands are: 60 | 61 | - `php artisan module:create {alias}` 62 | - `php artisan module:make:controller {alias} {ControllerName}` 63 | - `php artisan module:make:controller {alias} {ControllerName} --resource` 64 | - `php artisan module:make:command {alias} {CommandName}` 65 | - `php artisan module:make:facade {alias} {FacadeName}` 66 | - `php artisan module:make:middleware {alias} {MiddlewareName}` 67 | - `php artisan module:make:migration {alias} {migration_name} --create --table=table_name` 68 | - `php artisan module:make:migration {alias} {migration_name} --table=table_name` 69 | - `php artisan module:make:model {alias} {ModelName}` 70 | - `php artisan module:make:provider {alias} {ProviderName}` 71 | - `php artisan module:make:request {alias} {RequestName}` 72 | - `php artisan module:make:service {alias} {ServiceClassName}` 73 | - `php artisan module:make:support {alias} {SupportClassName}` 74 | - `php artisan module:make:seeder {alias} {SeederClassName}` 75 | - `php artisan module:db:seed {alias}` 76 | - `php artisan module:db:seed {alias} --class={SeederClassName}` 77 | - `php artisan module:migrate {alias}` 78 | - `php artisan module:migrate:rollback {alias}` 79 | - `php artisan module:routes` 80 | - `php artisan module:install {alias}` 81 | - `php artisan module:uninstall {alias}` 82 | - `php artisan module:enable {alias}` 83 | - `php artisan module:disable {alias}` 84 | 85 | > 'alias' is your module's alias name. you can find module's alias name in `module.json` file of module directory 86 | 87 | You must install your module to activate 88 | 89 | ``php artisan module:install {alias}`` 90 | 91 | ### Loading Component 92 | You have to load views, config and translation by following [laravel package](https://laravel.com/docs/5.3/packages#resources) 93 | 94 | ##### Loading View 95 | 96 | view(module_alias::view_file) 97 | 98 | you may load the **module1** module's `index.blade.php` view like so: 99 | 100 | view('module1::index'); 101 | 102 | 103 | ##### Loading Translation 104 | 105 | you may load the **module1** module's `welcome` line from the `messages` file like so: 106 | 107 | trans('module1::messages.welcome'); 108 | ##### Loading Config File 109 | 110 | you may load the **module1** module's `welcome` line from the `messages` file like so: 111 | 112 | `config('messages.welcome');` 113 | 114 | 115 | You have to merge the configurations, use the `mergeConfigFrom` method within your `ModuleServiceProvider` provider's `register` method: 116 | 117 | public function register() 118 | { 119 | $this->mergeConfigFrom( 120 | __DIR__.'/../../config/messages.php', 'messages' 121 | ); 122 | } 123 | ##### Register Middleware 124 | 125 | You should create a `MiddlewareServiceProvider` provider to register your middleware dynamically. 126 | 127 | 128 | ``` 129 | 130 | use Illuminate\Support\ServiceProvider; 131 | 132 | class MiddlewareServiceProvider extends ServiceProvider 133 | { 134 | /** 135 | * Register any application services. 136 | * 137 | * @return void 138 | */ 139 | public function register() 140 | { 141 | /** 142 | * @var Router $router 143 | */ 144 | $router = $this->app['router']; 145 | 146 | $router->aliasMiddleware('middleware-shortname', MiddlewareClassName::class); 147 | } 148 | } 149 | ``` 150 | 151 | >**You should register all of your module's custom provider in *ModuleServiceProvider* provider's *register* method instead application's *config/app.php* file.** 152 | 153 | 154 | #### Credit 155 | [WebEd](https://github.com/sgsoft-studio/webed) 156 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mrabbani/laravel-module-manager", 3 | "description": "Laravel Module Management", 4 | "type": "laravel", 5 | "authors": [ 6 | { 7 | "name": "mrabbani", 8 | "email": "mahbub.rucse@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": "^7.1.3", 13 | "illuminate/console": "5.5.*|5.6.*", 14 | "illuminate/database": "5.5.*|5.6.*" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "Mrabbani\\ModuleManager\\": "src/" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Mrabbani\\Tests\\": "tests/" 24 | } 25 | }, 26 | "extra": { 27 | "laravel": { 28 | "providers": [ 29 | "Mrabbani\\ModuleManager\\Providers\\ModuleProvider" 30 | ] 31 | } 32 | }, 33 | 34 | "license": "MIT" 35 | } 36 | -------------------------------------------------------------------------------- /config/module_manager.php: -------------------------------------------------------------------------------- 1 | 'modules', 10 | 'plugin_directory' => 'modules', 11 | 12 | ]; -------------------------------------------------------------------------------- /helpers/file.php: -------------------------------------------------------------------------------- 1 | $file, 69 | 'type' => $type, 70 | ]); 71 | } 72 | } 73 | return $modulesArr; 74 | } 75 | } 76 | 77 | if (!function_exists('get_module_information')) { 78 | /** 79 | * @param $alias 80 | * @return mixed 81 | */ 82 | function get_module_information($alias) 83 | { 84 | return collect(get_all_module_information()) 85 | ->where('alias', '=', $alias) 86 | ->first(); 87 | } 88 | } 89 | 90 | 91 | if (!function_exists('get_all_module_aliases')) { 92 | 93 | /** 94 | * @return array 95 | */ 96 | function get_all_module_aliases() 97 | { 98 | return collect(get_all_module_information()) 99 | ->pluck('alias')->unique()->all(); 100 | } 101 | } 102 | 103 | 104 | if (!function_exists('get_modules_by_type')) { 105 | /** 106 | * @param $type 107 | * @return mixed 108 | */ 109 | function get_modules_by_type($type) 110 | { 111 | return collect(get_all_module_information()) 112 | ->where('type', '=', $type) 113 | ->first(); 114 | } 115 | } 116 | 117 | if (!function_exists('save_module_information')) { 118 | /** 119 | * @param $alias 120 | * @param array $data 121 | * @return bool 122 | */ 123 | function save_module_information($alias, array $data) 124 | { 125 | $module = is_array($alias) ? $alias : get_module_information($alias); 126 | if (!$module) { 127 | return false; 128 | } 129 | $editableFields = [ 130 | 'name', 'author', 'description', 'image', 'version', 'enabled', 'installed' 131 | ]; 132 | 133 | $count = 0; 134 | foreach ($data as $key => $item) { 135 | if (in_array($key, $editableFields)) { 136 | $module[$key] = $item; 137 | $count++; 138 | } 139 | } 140 | if (\File::exists(array_get($module, 'file'))) { 141 | $file = $module['file']; 142 | unset($module['file']); 143 | if (array_key_exists('type', $module)) { 144 | unset($module['type']); 145 | } 146 | \File::put($file, json_encode_pretify($module)); 147 | } 148 | 149 | if ($count > 0) { 150 | return true; 151 | } 152 | return false; 153 | } 154 | } 155 | 156 | 157 | if (!function_exists('json_encode_pretify')) { 158 | 159 | /** 160 | * @param array $data 161 | * @return string 162 | */ 163 | function json_encode_pretify(array $data) 164 | { 165 | return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 166 | } 167 | } -------------------------------------------------------------------------------- /resources/stubs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/config/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/database/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/database/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/database/migrations/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/database/seeds/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/database/seeds/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/helpers/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/helpers/helpers.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/helpers/helpers.php -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/module.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/resources/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/resources/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/resources/assets/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/resources/assets/js/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/resources/assets/sass/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/resources/assets/sass/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/resources/lang/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/resources/lang/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrabbani/laravel_module_manager/c4aa574d7b57fab808b72c4b183c32170ee4ae20/resources/stubs/_folder-structure/resources/views/.gitkeep -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/routes/api.php: -------------------------------------------------------------------------------- 1 | booted(function () { 17 | $this->booted(); 18 | }); 19 | } 20 | 21 | /** 22 | * Register the application services. 23 | * 24 | * @return void 25 | */ 26 | public function register() 27 | { 28 | 29 | } 30 | 31 | private function booted() 32 | { 33 | /** 34 | * Register dynamic menu or what you want when 35 | * bootstrap your module 36 | */ 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/src/Providers/InstallModuleServiceProvider.php: -------------------------------------------------------------------------------- 1 | booted(function () { 21 | $this->booted(); 22 | }); 23 | } 24 | 25 | /** 26 | * Register the application services. 27 | * 28 | * @return void 29 | */ 30 | public function register() 31 | { 32 | 33 | } 34 | 35 | private function booted() 36 | { 37 | //Resolve your module dependency 38 | 39 | $this->createSchema(); 40 | } 41 | 42 | private function createSchema() 43 | { 44 | \Artisan::call('module:migrate', ['alias' => $this->moduleAlias]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/src/Providers/ModuleProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__ . '/../../resources/views', 'DummyAlias'); 16 | /*Load translations*/ 17 | $this->loadTranslationsFrom(__DIR__ . '/../../resources/lang', 'DummyAlias'); 18 | /*Load migrations*/ 19 | $this->loadMigrationsFrom(__DIR__ . '/../../database/migrations'); 20 | 21 | $this->publishes([ 22 | __DIR__ . '/../../resources/assets' => resource_path('assets'), 23 | __DIR__ . '/../../resources/public' => public_path(), 24 | ], 'assets'); 25 | $this->publishes([ 26 | __DIR__ . '/../../resources/views' => config('view.paths')[0] . '/vendor/DummyAlias', 27 | ], 'views'); 28 | $this->publishes([ 29 | __DIR__ . '/../../resources/lang' => base_path('resources/lang/vendor/DummyAlias'), 30 | ], 'lang'); 31 | $this->publishes([ 32 | __DIR__ . '/../../database' => base_path('database'), 33 | ], 'migrations'); 34 | } 35 | 36 | /** 37 | * Register the application services. 38 | * 39 | * @return void 40 | */ 41 | public function register() 42 | { 43 | //Load helpers 44 | $this->loadHelpers(); 45 | 46 | $this->app->register(RouteServiceProvider::class); 47 | $this->app->register(RepositoryServiceProvider::class); 48 | $this->app->register(BootstrapModuleServiceProvider::class); 49 | } 50 | 51 | protected function loadHelpers() 52 | { 53 | $helpers = $this->app['files']->glob(__DIR__ . '/../../helpers/*.php'); 54 | foreach ($helpers as $helper) { 55 | require_once $helper; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/src/Providers/RepositoryServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 31 | 32 | $this->mapWebRoutes(); 33 | 34 | // 35 | } 36 | 37 | /** 38 | * Define the "web" routes for the application. 39 | * 40 | * These routes all receive session state, CSRF protection, etc. 41 | * 42 | * @return void 43 | */ 44 | protected function mapWebRoutes() 45 | { 46 | Route::group([ 47 | 'middleware' => 'web', 48 | 'namespace' => $this->namespace, 49 | ], function ($router) { 50 | require __DIR__ . '/../../routes/web.php'; 51 | }); 52 | } 53 | 54 | /** 55 | * Define the "api" routes for the application. 56 | * 57 | * These routes are typically stateless. 58 | * 59 | * @return void 60 | */ 61 | protected function mapApiRoutes() 62 | { 63 | Route::group([ 64 | 'middleware' => 'api', 65 | 'namespace' => $this->namespace, 66 | 'prefix' => 'api' 67 | ], function ($router) { 68 | require __DIR__ . '/../../routes/api.php'; 69 | }); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /resources/stubs/_folder-structure/src/Providers/UninstallModuleServiceProvider.php: -------------------------------------------------------------------------------- 1 | booted(function () { 19 | $this->booted(); 20 | }); 21 | } 22 | 23 | /** 24 | * Register the application services. 25 | * 26 | * @return void 27 | */ 28 | public function register() 29 | { 30 | 31 | } 32 | 33 | private function booted() 34 | { 35 | $this->dropSchema(); 36 | } 37 | 38 | private function dropSchema() 39 | { 40 | //If you want to rollback your module migration 41 | // uncomment bellow statement 42 | 43 | // \Artisan::call('module:migrate:rollback', ['alias' => $this->moduleAlias]); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /resources/stubs/console/command.stub: -------------------------------------------------------------------------------- 1 | booted(function () { 15 | $this->booted(); 16 | }); 17 | } 18 | 19 | /** 20 | * Register any application services. 21 | * 22 | * @return void 23 | */ 24 | public function register() 25 | { 26 | 27 | } 28 | 29 | /** 30 | * Callback when app booted 31 | * 32 | * @return void 33 | */ 34 | private function booted() 35 | { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /resources/stubs/repositories/repository.cache-decorator.stub: -------------------------------------------------------------------------------- 1 | composer = $composer; 43 | $this->composer->setWorkingPath(base_path()); 44 | } 45 | 46 | /** 47 | * Execute the console command. 48 | */ 49 | public function handle() 50 | { 51 | $this->getInformation(); 52 | 53 | $count = 0; 54 | 55 | $plugins = get_modules_by_type('plugins'); 56 | 57 | if(!$this->container['alias']) { 58 | foreach ($plugins as $plugin) { 59 | \ModulesManagement::disableModule(array_get($plugin, 'alias')); 60 | $count++; 61 | } 62 | } else { 63 | $plugins = $plugins->where('alias', '=', $this->container['alias']); 64 | foreach ($plugins as $plugin) { 65 | \ModulesManagement::disableModule(array_get($plugin, 'alias')); 66 | $count++; 67 | } 68 | } 69 | 70 | echo PHP_EOL; 71 | 72 | \ModulesManagement::refreshComposerAutoload(); 73 | 74 | $this->info("\n$count module(s) disabled successfully."); 75 | } 76 | 77 | protected function getInformation() 78 | { 79 | if($this->option('all')) { 80 | $this->container['alias'] = null; 81 | } else { 82 | $this->container['alias'] = $this->ask('Plugin alias'); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Console/Commands/EnableModuleCommand.php: -------------------------------------------------------------------------------- 1 | composer = $composer; 42 | $this->composer->setWorkingPath(base_path()); 43 | } 44 | 45 | /** 46 | * Execute the console command. 47 | */ 48 | public function handle() 49 | { 50 | $this->getInformation(); 51 | 52 | $count = 0; 53 | 54 | $plugins = get_modules_by_type('plugins'); 55 | 56 | if(!$this->container['alias']) { 57 | foreach ($plugins as $plugin) { 58 | \ModulesManagement::enableModule(array_get($plugin, 'alias')); 59 | $count++; 60 | } 61 | } else { 62 | $plugins = $plugins->where('alias', '=', $this->container['alias']); 63 | foreach ($plugins as $plugin) { 64 | \ModulesManagement::enableModule(array_get($plugin, 'alias')); 65 | $count++; 66 | } 67 | } 68 | 69 | echo PHP_EOL; 70 | 71 | \ModulesManagement::refreshComposerAutoload(); 72 | 73 | $this->info("\n$count module(s) enabled successfully."); 74 | } 75 | 76 | protected function getInformation() 77 | { 78 | if($this->option('all')) { 79 | $this->container['alias'] = null; 80 | } else { 81 | $this->container['alias'] = $this->ask('Plugin alias'); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Console/Commands/InstallModuleCommand.php: -------------------------------------------------------------------------------- 1 | app = app(); 46 | } 47 | 48 | /** 49 | * Execute the console command. 50 | */ 51 | public function handle() 52 | { 53 | /** 54 | * Migrate tables 55 | */ 56 | \ModulesManagement::enableModule($this->argument('alias')); 57 | \ModulesManagement::modifyModuleAutoload($this->argument('alias')); 58 | 59 | $this->line('Migrate database...'); 60 | \Artisan::call('module:migrate', ['alias' => $this->argument('alias')]); 61 | $this->line('Install module dependencies...'); 62 | $this->registerInstallModuleService(); 63 | 64 | $this->info("\nModule " . $this->argument('alias') . " installed."); 65 | } 66 | 67 | protected function registerInstallModuleService() 68 | { 69 | 70 | $module = get_module_information($this->argument('alias')); 71 | $namespace = str_replace('\\\\', '\\', array_get($module, 'namespace', '') . '\Providers\InstallModuleServiceProvider'); 72 | if(class_exists($namespace)) { 73 | $this->app->register($namespace); 74 | } 75 | save_module_information($module, [ 76 | 'installed' => true 77 | ]); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Console/Commands/ModuleSeedCommand.php: -------------------------------------------------------------------------------- 1 | loadSeederClass(); 33 | $this->runSeeder(); 34 | } 35 | 36 | /** 37 | * Load classes from plugin's database/seeds directory 38 | * 39 | * @return void 40 | */ 41 | 42 | protected function loadSeederClass() 43 | { 44 | $path = $this->getPath(); 45 | $seederClasses = \File::glob($path . '*.php'); 46 | foreach ($seederClasses as $className) { 47 | require_once $className; 48 | } 49 | } 50 | 51 | 52 | 53 | /** 54 | * Get the path of seeder classes 55 | * 56 | * @return string 57 | */ 58 | protected function getPath() 59 | { 60 | $path = $this->getModuleInfo('module-path') . 'database/seeds/'; 61 | 62 | return $path; 63 | } 64 | 65 | /** 66 | * Run the database seeder command. 67 | * 68 | * @param string $database 69 | * @return void 70 | */ 71 | protected function runSeeder() 72 | { 73 | $database = $this->option('database'); 74 | 75 | $alias = $this->argument('alias'); 76 | 77 | $className = $this->option('class') ?: studly_case(preg_replace('/\-/', '_', $alias)) . 'TableSeeder'; 78 | 79 | $this->call('db:seed', [ 80 | '--database' => $database, 81 | '--class' => $className, 82 | '--force' => $this->option('force'), 83 | ]); 84 | } 85 | } -------------------------------------------------------------------------------- /src/Console/Commands/RouteListCommand.php: -------------------------------------------------------------------------------- 1 | router = $router; 76 | $this->routes = $router->getRoutes(); 77 | } 78 | 79 | /** 80 | * Prompt for module's alias name 81 | * 82 | */ 83 | public function handle() 84 | { 85 | $this->module = $this->ask('Module alias name?', 'all'); 86 | $this->setModulesNamespace(); 87 | $this->fire(); 88 | } 89 | 90 | /** 91 | * Set all available module's root namespace to $this->modulesNamespace 92 | * 93 | */ 94 | public function setModulesNamespace() 95 | { 96 | if($this->module !== 'all') { 97 | $modules[] = get_module_information($this->module); 98 | 99 | } else { 100 | $modules = get_all_module_information(); 101 | } 102 | if(! count($modules)){ 103 | $this->error('Module does not exist'); 104 | die(); 105 | } 106 | 107 | $this->modulesNamespace = collect($modules)->pluck('namespace'); 108 | } 109 | 110 | /** 111 | * check route's action namespace is belongs to module's namespace 112 | * 113 | * @param $namespace 114 | * @return bool 115 | */ 116 | public function isBelongsToModule($namespace) 117 | { 118 | 119 | foreach ($this->modulesNamespace as $moduleNamespace) { 120 | if((strpos($namespace, $moduleNamespace)) === 0){ 121 | return true; 122 | } 123 | } 124 | return false; 125 | } 126 | 127 | /** 128 | * Execute the console command. 129 | * 130 | * @return void 131 | */ 132 | public function fire() 133 | { 134 | if (count($this->routes) == 0) { 135 | return $this->error("Your application doesn't have any routes."); 136 | } 137 | 138 | $this->displayRoutes($this->getRoutes()); 139 | } 140 | 141 | /** 142 | * Compile the routes into a displayable format. 143 | * 144 | * @return array 145 | */ 146 | protected function getRoutes() 147 | { 148 | $routes = collect($this->routes)->map(function ($route) { 149 | return $this->getRouteInformation($route); 150 | })->all(); 151 | 152 | if ($sort = $this->option('sort')) { 153 | $routes = $this->sortRoutes($sort, $routes); 154 | } 155 | 156 | if ($this->option('reverse')) { 157 | $routes = array_reverse($routes); 158 | } 159 | 160 | return array_filter($routes); 161 | } 162 | 163 | /** 164 | * Get the route information for a given route. 165 | * 166 | * @param \Illuminate\Routing\Route $route 167 | * @return array 168 | */ 169 | protected function getRouteInformation(Route $route) 170 | { 171 | return $this->filterRoute([ 172 | 'host' => $route->domain(), 173 | 'method' => implode('|', $route->methods()), 174 | 'uri' => $route->uri(), 175 | 'name' => $route->getName(), 176 | 'action' => $route->getActionName(), 177 | 'middleware' => $this->getMiddleware($route), 178 | 'namespace' => $route->getAction()['namespace'] 179 | ]); 180 | } 181 | 182 | /** 183 | * Sort the routes by a given element. 184 | * 185 | * @param string $sort 186 | * @param array $routes 187 | * @return array 188 | */ 189 | protected function sortRoutes($sort, $routes) 190 | { 191 | return Arr::sort($routes, function ($route) use ($sort) { 192 | return $route[$sort]; 193 | }); 194 | } 195 | 196 | /** 197 | * Display the route information on the console. 198 | * 199 | * @param array $routes 200 | * @return void 201 | */ 202 | protected function displayRoutes(array $routes) 203 | { 204 | $this->table($this->headers, $routes); 205 | } 206 | 207 | /** 208 | * Get before filters. 209 | * 210 | * @param \Illuminate\Routing\Route $route 211 | * @return string 212 | */ 213 | protected function getMiddleware($route) 214 | { 215 | return collect($route->gatherMiddleware())->map(function ($middleware) { 216 | return $middleware instanceof Closure ? 'Closure' : $middleware; 217 | })->implode(','); 218 | } 219 | 220 | /** 221 | * Filter the route by URI and / or name. 222 | * 223 | * @param array $route 224 | * @return array|null 225 | */ 226 | protected function filterRoute(array $route) 227 | { 228 | if($this->isBelongsToModule($route['namespace'])) { 229 | return $route; 230 | } 231 | } 232 | 233 | /** 234 | * Get the console command options. 235 | * 236 | * @return array 237 | */ 238 | protected function getOptions() 239 | { 240 | return [ 241 | ['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method.'], 242 | 243 | ['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name.'], 244 | 245 | ['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path.'], 246 | 247 | ['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes.'], 248 | 249 | ['sort', null, InputOption::VALUE_OPTIONAL, 'The column (host, method, uri, name, action, middleware) to sort by.', 'uri'], 250 | ]; 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/Console/Commands/UninstallModuleCommand.php: -------------------------------------------------------------------------------- 1 | app = app(); 46 | } 47 | 48 | /** 49 | * Execute the console command. 50 | */ 51 | public function handle() 52 | { 53 | /** 54 | * Migrate tables 55 | */ 56 | $this->line('Uninstall module dependencies...'); 57 | $this->registerUninstallModuleService(); 58 | 59 | $this->info("\nModule " . $this->argument('alias') . " uninstalled."); 60 | } 61 | 62 | protected function registerUninstallModuleService() 63 | { 64 | 65 | $module = get_module_information($this->argument('alias')); 66 | $namespace = str_replace('\\\\', '\\', array_get($module, 'namespace', '') . '\Providers\UninstallModuleServiceProvider'); 67 | if(class_exists($namespace)) { 68 | $this->app->register($namespace); 69 | 70 | } 71 | save_module_information($module, [ 72 | 'installed' => true 73 | ]); 74 | \ModulesManagement::disableModule($this->argument('alias')); 75 | \ModulesManagement::modifyModuleAutoload($this->argument('alias'), true); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Console/Generators/AbstractGenerator.php: -------------------------------------------------------------------------------- 1 | getDefaultNamespace($name); 22 | } 23 | 24 | /** 25 | * Get the destination class path. 26 | * 27 | * @param string $name 28 | * @return string 29 | */ 30 | protected function getPath($name) 31 | { 32 | $path = $this->getModuleInfo('module-path') . 'src/' . str_replace('\\', '/', $name) . '.php'; 33 | 34 | return $path; 35 | } 36 | 37 | /** 38 | * Get the full namespace name for a given class. 39 | * 40 | * @param string $name 41 | * @return string 42 | */ 43 | protected function getNamespace($name) 44 | { 45 | $namespace = trim(implode('\\', array_slice(explode('\\', $this->getModuleInfo('namespace') . '\\' . str_replace('/', '\\', $name)), 0, -1)), '\\'); 46 | return $namespace; 47 | } 48 | 49 | /** 50 | * Replace the class name for the given stub. 51 | * 52 | * @param string $stub 53 | * @param string $name 54 | * @return string 55 | */ 56 | protected function replaceClass($stub, $name) 57 | { 58 | $class = class_basename($name); 59 | 60 | return str_replace('DummyClass', $class, $stub); 61 | } 62 | 63 | /** 64 | * Replace the namespace for the given stub. 65 | * 66 | * @param string $stub 67 | * @param string $name 68 | * @return $this 69 | */ 70 | protected function replaceNamespace(&$stub, $name) 71 | { 72 | $stub = str_replace( 73 | 'DummyNamespace', $this->getNamespace($name), $stub 74 | ); 75 | 76 | $stub = str_replace( 77 | 'DummyRootNamespace', $this->laravel->getNamespace(), $stub 78 | ); 79 | 80 | if (method_exists($this, 'replaceParameters')) { 81 | $this->replaceParameters($stub); 82 | } 83 | 84 | return $this; 85 | } 86 | protected function qualifyClass($name) 87 | { 88 | $rootNamespace = $this->rootNamespace(); 89 | 90 | return $this->getDefaultNamespace(trim($rootNamespace, '\\')); 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeController.php: -------------------------------------------------------------------------------- 1 | option('resource')) { 37 | return __DIR__ . '/../../../resources/stubs/controllers/controller.resource.stub'; 38 | } 39 | 40 | return __DIR__ . '/../../../resources/stubs/controllers/controller.stub'; 41 | } 42 | 43 | protected function getDefaultNamespace($rootNamespace) 44 | { 45 | // ($this->getNamespace($this->argument('alias'))); 46 | return 'Http\\Controllers\\' . $this->argument('name'); 47 | } 48 | 49 | protected function replaceParameters(&$stub) 50 | { 51 | $stub = str_replace([ 52 | '{alias}', 53 | ], [ 54 | $this->argument('alias'), 55 | ], $stub); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeFacade.php: -------------------------------------------------------------------------------- 1 | argument('name'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeMiddleware.php: -------------------------------------------------------------------------------- 1 | argument('name'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeMigration.php: -------------------------------------------------------------------------------- 1 | creator = $creator; 59 | $this->composer = $composer; 60 | $this->composer->setWorkingPath(base_path()); 61 | } 62 | 63 | public function handle() 64 | { 65 | // It's possible for the developer to specify the tables to modify in this 66 | // schema operation. The developer may also specify if this table needs 67 | // to be freshly created so we can create the appropriate migrations. 68 | $name = trim($this->argument('name')); 69 | 70 | $table = $this->option('table'); 71 | 72 | $create = $this->option('create') ?: false; 73 | 74 | if (! $table && is_string($create)) { 75 | $table = $create; 76 | 77 | $create = true; 78 | } 79 | 80 | // Now we are ready to write the migration out to disk. Once we've written 81 | // the migration out, we will dump-autoload for the entire framework to 82 | // make sure that the migrations are registered by the class loaders. 83 | $this->writeMigration($name, $table, $create); 84 | } 85 | 86 | /** 87 | * Write the migration file to disk. 88 | * 89 | * @param string $name 90 | * @param string $table 91 | * @param bool $create 92 | * @return string 93 | */ 94 | protected function writeMigration($name, $table, $create) 95 | { 96 | $path = $this->getMigrationPath(); 97 | 98 | $file = pathinfo($this->creator->create($name, $path, $table, $create), PATHINFO_FILENAME); 99 | 100 | return $this->line("Created Migration: {$file}"); 101 | } 102 | 103 | /** 104 | * Get the path to the migration directory. 105 | * 106 | * @return string 107 | */ 108 | protected function getMigrationPath() 109 | { 110 | $module = get_module_information($this->argument('alias')); 111 | $baseDir = get_base_folder(array_get($module, 'file')); 112 | $path = $baseDir . 'database/migrations'; 113 | return $path; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeModel.php: -------------------------------------------------------------------------------- 1 | getNameInput(); 40 | 41 | $name = $this->parseName($nameInput); 42 | 43 | $path = $this->getPath($name); 44 | 45 | if ($this->alreadyExists($nameInput)) { 46 | $this->error($this->type . ' already exists!'); 47 | 48 | return false; 49 | } 50 | 51 | $this->makeDirectory($path); 52 | 53 | $this->files->put($path, $this->buildClass($name)); 54 | 55 | /** 56 | * Create model contract 57 | */ 58 | 59 | if($this->option('with-contract')) { 60 | $this->buildContract = true; 61 | 62 | $contractName = 'Contracts/' . get_file_name($path, '.php'); 63 | $contractPath = get_base_folder($path) . $contractName . 'ModelContract.php'; 64 | 65 | $this->makeDirectory($contractPath); 66 | $this->files->put($contractPath, $this->buildClass('Models\\' . $contractName)); 67 | } 68 | 69 | 70 | $this->info($this->type . ' created successfully.'); 71 | } 72 | 73 | /** 74 | * Get the stub file for the generator. 75 | * 76 | * @return string 77 | */ 78 | protected function getStub() 79 | { 80 | if ($this->buildContract === true) { 81 | return __DIR__ . '/../../../resources/stubs/models/model.contract.stub'; 82 | } 83 | return __DIR__ . '/../../../resources/stubs/models/model.stub'; 84 | } 85 | 86 | protected function getDefaultNamespace($rootNamespace) 87 | { 88 | if ($this->buildContract === true) { 89 | return 'Models\\Contracts\\' . $this->argument('name'); 90 | } 91 | return 'Models\\' . $this->argument('name'); 92 | } 93 | 94 | protected function replaceParameters(&$stub) 95 | { 96 | $stub = str_replace([ 97 | '{table}', 98 | ], [ 99 | snake_case(str_plural($this->argument('name'))), 100 | ], $stub); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeModule.php: -------------------------------------------------------------------------------- 1 | 'Module', 39 | 'plugin' => 'Plugins', 40 | ]; 41 | 42 | protected $moduleType; 43 | 44 | protected $moduleFolderName; 45 | 46 | /** 47 | * Create a new command instance. 48 | * 49 | * @return void 50 | */ 51 | public function __construct(Filesystem $filesystem) 52 | { 53 | parent::__construct(); 54 | 55 | $this->files = $filesystem; 56 | } 57 | 58 | /** 59 | * Execute the console command. 60 | */ 61 | public function handle() 62 | { 63 | $this->moduleType = 'module'; //$this->ask('Your modular type. Eccepted: module,plugin. Other types will return "module".', 'module'); 64 | if (!in_array($this->moduleType, array_keys($this->acceptedTypes))) { 65 | $this->moduleType = 'module'; 66 | } 67 | 68 | $this->container['alias'] = snake_case($this->argument('alias')); 69 | 70 | $this->step1(); 71 | } 72 | 73 | private function step1() 74 | { 75 | $this->moduleFolderName = $this->ask('Module folder name:', $this->container['alias']); 76 | $this->container['name'] = $this->ask('Name of module:', config('app.name') . ' '. str_slug($this->container['alias'])); 77 | $this->container['author'] = $this->ask('Author of module:'); 78 | $this->container['description'] = $this->ask('Description of module:', $this->container['name']); 79 | $this->container['namespace'] = $this->ask('Namespace of module:', $this->laravel->getNamespace() . $this->acceptedTypes[$this->moduleType] . '\\' . studly_case($this->container['alias'])); 80 | $this->container['version'] = $this->ask('Module version.', '1.0'); 81 | $this->container['autoload'] = $this->ask('Autoloading type.', 'psr-4'); 82 | 83 | $this->step2(); 84 | } 85 | 86 | private function step2() 87 | { 88 | $this->generatingModule(); 89 | 90 | $this->info("\nYour module generated successfully."); 91 | } 92 | 93 | private function generatingModule() 94 | { 95 | $pathType = $this->makeModuleFolder(); 96 | $directory = $pathType($this->moduleFolderName); 97 | $source = __DIR__ . '/../../../resources/stubs/_folder-structure'; 98 | 99 | /** 100 | * Make directory 101 | */ 102 | $this->files->makeDirectory($directory); 103 | $this->files->copyDirectory($source, $directory, null); 104 | 105 | /** 106 | * Replace files placeholder 107 | */ 108 | $files = $this->files->allFiles($directory); 109 | foreach ($files as $file) { 110 | $contents = $this->replacePlaceholders($file->getContents()); 111 | $filePath = $pathType($this->moduleFolderName . '/' . $file->getRelativePathname()); 112 | 113 | $this->files->put($filePath, $contents); 114 | } 115 | 116 | /** 117 | * Modify the module.json information 118 | */ 119 | \File::put($directory . '/module.json', json_encode_pretify($this->container)); 120 | } 121 | 122 | private function makeModuleFolder() 123 | { 124 | switch ($this->moduleType) { 125 | case 'module': 126 | if (!$this->files->isDirectory(module_base_path())) { 127 | $this->files->makeDirectory(module_base_path()); 128 | } 129 | return 'module_base_path'; 130 | break; 131 | case 'plugin': 132 | default: 133 | if (!$this->files->isDirectory(plugins_base_path())) { 134 | $this->files->makeDirectory(plugins_base_path()); 135 | } 136 | return 'plugins_base_path'; 137 | break; 138 | } 139 | } 140 | 141 | protected function replacePlaceholders($contents) 142 | { 143 | $find = [ 144 | 'DummyNamespace', 145 | 'DummyAlias', 146 | 'DummyName', 147 | ]; 148 | 149 | $replace = [ 150 | $this->container['namespace'], 151 | $this->container['alias'], 152 | $this->container['name'], 153 | ]; 154 | 155 | return str_replace($find, $replace, $contents); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeProvider.php: -------------------------------------------------------------------------------- 1 | argument('name'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeRepository.php: -------------------------------------------------------------------------------- 1 | getNameInput(); 40 | 41 | $name = $this->parseName($nameInput); 42 | 43 | $path = $this->getPath($name); 44 | 45 | if ($this->alreadyExists($nameInput)) { 46 | $this->error($this->type . ' already exists!'); 47 | 48 | return false; 49 | } 50 | 51 | /** 52 | * Make repository 53 | */ 54 | $this->makeDirectory($path); 55 | $this->files->put($path, $this->buildClass($name)); 56 | 57 | /** 58 | * Make cache decorator 59 | */ 60 | $this->buildStep = 'make-cache-decorator'; 61 | $pathCacheDecorator = $this->getPath($name . 'CacheDecorator'); 62 | $this->makeDirectory($pathCacheDecorator); 63 | $this->files->put($pathCacheDecorator, $this->buildClass($name)); 64 | 65 | /** 66 | * Create model contract 67 | */ 68 | $this->buildStep = 'make-contract'; 69 | $contractName = 'Contracts/' . get_file_name($path, '.php'); 70 | $contractPath = get_base_folder($path) . $contractName . 'Contract.php'; 71 | 72 | $this->makeDirectory($contractPath); 73 | 74 | $this->files->put($contractPath, $this->buildClass('Repositories\\' . $contractName)); 75 | 76 | $this->info($this->type . ' created successfully.'); 77 | } 78 | 79 | /** 80 | * Get the stub file for the generator. 81 | * 82 | * @return string 83 | */ 84 | protected function getStub() 85 | { 86 | if ($this->buildStep === 'make-contract') { 87 | return __DIR__ . '/../../../resources/stubs/repositories/repository.contract.stub'; 88 | } 89 | if ($this->buildStep === 'make-cache-decorator' && !$this->option('no-cache')) { 90 | return __DIR__ . '/../../../resources/stubs/repositories/repository.cache-decorator.stub'; 91 | } 92 | if ($this->option('no-cache')) { 93 | return __DIR__ . '/../../../resources/stubs/repositories/repository.no-cache.stub'; 94 | } 95 | return __DIR__ . '/../../../resources/stubs/repositories/repository.stub'; 96 | } 97 | 98 | protected function getDefaultNamespace($rootNamespace) 99 | { 100 | if ($this->buildStep === 'make-contract') { 101 | return 'Repositories\\Contracts\\' . $this->argument('name'); 102 | } 103 | return 'Repositories\\' . $this->argument('name'); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeRequest.php: -------------------------------------------------------------------------------- 1 | argument('name'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeSeeder.php: -------------------------------------------------------------------------------- 1 | createModuleTableSeederIfNotExist(); 40 | $nameInput = $this->getNameInput(); 41 | 42 | if ($this->alreadyExists($nameInput)) { 43 | $this->error($this->type . ' already exists!'); 44 | 45 | return false; 46 | } 47 | 48 | $this->createSeederClass($nameInput); 49 | 50 | $this->info($this->type . ' created successfully.'); 51 | } 52 | 53 | protected function createModuleTableSeederIfNotExist() 54 | { 55 | $moduleSeederClass = studly_case(preg_replace('/\-/', '_', $this->argument('alias'))) . 'TableSeeder'; 56 | 57 | if ($this->alreadyExists($moduleSeederClass)) { 58 | 59 | return false; 60 | } 61 | 62 | $this->createSeederClass($moduleSeederClass); 63 | } 64 | 65 | 66 | protected function createSeederClass($nameInput) 67 | { 68 | 69 | $name = $this->parseName($nameInput); 70 | 71 | $path = $this->getPath($name); 72 | 73 | $this->makeDirectory($path); 74 | 75 | $this->files->put($path, $this->buildClass($name)); 76 | 77 | } 78 | /** 79 | * Get the destination class path. 80 | * 81 | * @param string $name 82 | * @return string 83 | */ 84 | protected function getPath($name) 85 | { 86 | $path = $this->getModuleInfo('module-path') . 'database/seeds/' . str_replace('\\', '/', $name) . '.php'; 87 | 88 | return $path; 89 | } 90 | 91 | protected function replaceParameters(&$stub) 92 | { 93 | $stub = str_replace([ 94 | '{alias}', 95 | ], [ 96 | $this->argument('alias'), 97 | ], $stub); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeService.php: -------------------------------------------------------------------------------- 1 | argument('name'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeSupport.php: -------------------------------------------------------------------------------- 1 | argument('name'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/Generators/MakeView.php: -------------------------------------------------------------------------------- 1 | option('layout') === '2columns') { 37 | return __DIR__ . '/../../../resources/stubs/views/view-2columns.stub'; 38 | } 39 | return __DIR__ . '/../../../resources/stubs/views/view.stub'; 40 | } 41 | 42 | /** 43 | * Execute the console command. 44 | * 45 | * @return bool|null 46 | */ 47 | public function handle() 48 | { 49 | $nameInput = $this->getNameInput(); 50 | 51 | $name = $this->parseName($nameInput); 52 | 53 | $path = $this->getPath($name); 54 | 55 | if ($this->alreadyExists($nameInput)) { 56 | $this->error($this->type . ' already exists!'); 57 | 58 | return false; 59 | } 60 | 61 | $this->makeDirectory($path); 62 | 63 | $this->files->put($path, $this->buildClass($name)); 64 | 65 | $this->info($this->type . ' created successfully.'); 66 | } 67 | 68 | /** 69 | * Get the destination class path. 70 | * 71 | * @param string $name 72 | * @return string 73 | */ 74 | protected function getPath($name) 75 | { 76 | $path = $this->getModuleInfo('module-path') . 'resources/views/' . str_replace('\\', '/', $name) . '.blade.php'; 77 | 78 | return $path; 79 | } 80 | 81 | protected function replaceParameters(&$stub) 82 | { 83 | $stub = str_replace([ 84 | '{alias}', 85 | ], [ 86 | $this->argument('alias'), 87 | ], $stub); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Console/Migrations/ModuleMigrateCommand.php: -------------------------------------------------------------------------------- 1 | getMigrationIfo(); 29 | foreach($requestedMigrations as $migration) { 30 | $this->info($migration['alias']. ' module migrating'); 31 | \Artisan::call('migrate', ['--path' => $migration['path']]); 32 | $this->info($migration['alias']. ' module migrated'); 33 | } 34 | } 35 | 36 | /** 37 | * return alias name and database migration path by module 38 | * 39 | * @return array 40 | * @throws \Exception 41 | */ 42 | protected function getMigrationIfo() 43 | { 44 | $info = []; 45 | $migrationDirectory = 'database' . DIRECTORY_SEPARATOR . 'migrations'; 46 | $alias = $this->argument('alias'); 47 | $allAlias = get_all_module_aliases(); 48 | if ($alias === 'all') { 49 | foreach($allAlias as $alias) { 50 | $info[] = [ 51 | 'alias' => $alias, 52 | 'path' => module_relative_path($alias) . $migrationDirectory 53 | ]; 54 | } 55 | 56 | return $info; 57 | } 58 | if (!in_array($alias, $allAlias)) { 59 | throw new \Exception($alias .' module not found'); 60 | } 61 | $info[] = [ 62 | 'alias' => $alias, 63 | 'path' => module_relative_path($alias) . $migrationDirectory 64 | ]; 65 | 66 | return $info; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Console/Migrations/RollbackCommand.php: -------------------------------------------------------------------------------- 1 | migrator = $migrator; 50 | } 51 | 52 | /** 53 | * Execute the console command. 54 | * 55 | * @return void 56 | */ 57 | public function handle() 58 | { 59 | if (! $this->confirmToProceed()) { 60 | return; 61 | } 62 | 63 | $migrationPath = base_path().'/'. module_relative_path($this->argument('alias')).'database/migrations'; 64 | $this->migrator->setConnection($this->option('database')); 65 | $this->migrator->rollback( 66 | [$migrationPath], ['pretend' => $this->option('pretend'), 'step' => (int) $this->option('step')] 67 | ); 68 | 69 | // Once the migrator has run we will grab the note output and send it out to 70 | // the console screen, since the migrator itself functions without having 71 | // any instances of the OutputInterface contract passed into the class. 72 | foreach ($this->migrator->getNotes() as $note) { 73 | $this->output->writeln($note); 74 | } 75 | } 76 | 77 | /** 78 | * Get the console command options. 79 | * 80 | * @return array 81 | */ 82 | protected function getOptions() 83 | { 84 | return [ 85 | ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], 86 | 87 | ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], 88 | 89 | ['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to be executed.'], 90 | 91 | ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'], 92 | 93 | ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted.'], 94 | ]; 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/Console/ModuleInfoTrait.php: -------------------------------------------------------------------------------- 1 | argument('alias'); 41 | 42 | $module = get_module_information($alias); 43 | 44 | if(!$module) { 45 | $this->error('Module not exists'); 46 | die(); 47 | } 48 | 49 | $moduleRootFolder = $this->resolveModuleRootFolder($module); 50 | 51 | return $this->moduleInformation = array_merge($module, [ 52 | 'module-path' => $moduleRootFolder . basename(str_replace('/module.json', '', $module['file'])) . '/' 53 | ]); 54 | } 55 | 56 | /** 57 | * Get module information by key 58 | * @param $key 59 | * @return array|mixed 60 | */ 61 | protected function getModuleInfo($key = null) 62 | { 63 | if (!$this->moduleInformation) { 64 | $this->getCurrentModule(); 65 | } 66 | if (!$key) { 67 | return $this->moduleInformation; 68 | } 69 | return array_get($this->moduleInformation, $key, null); 70 | } 71 | } -------------------------------------------------------------------------------- /src/Events/ModuleDisabled.php: -------------------------------------------------------------------------------- 1 | module = $module; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/ModuleEnabled.php: -------------------------------------------------------------------------------- 1 | module = $module; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/RemovedModule.php: -------------------------------------------------------------------------------- 1 | module = $module; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Providers/ConsoleServiceProvider.php: -------------------------------------------------------------------------------- 1 | generatorCommands(); 31 | $this->migrationCommands(); 32 | $this->otherCommands(); 33 | } 34 | 35 | /** 36 | * register generator commands 37 | */ 38 | private function generatorCommands() 39 | { 40 | $generators = [ 41 | 'module_manager.console.generator.make-module' => \Mrabbani\ModuleManager\Console\Generators\MakeModule::class, 42 | 'module_manager.console.generator.make-provider' => \Mrabbani\ModuleManager\Console\Generators\MakeProvider::class, 43 | 'module_manager.console.generator.make-controller' => \Mrabbani\ModuleManager\Console\Generators\MakeController::class, 44 | 'module_manager.console.generator.make-middleware' => \Mrabbani\ModuleManager\Console\Generators\MakeMiddleware::class, 45 | 'module_manager.console.generator.make-request' => \Mrabbani\ModuleManager\Console\Generators\MakeRequest::class, 46 | 'module_manager.console.generator.make-model' => \Mrabbani\ModuleManager\Console\Generators\MakeModel::class, 47 | // 'module_manager.console.generator.make-repository' => \Mrabbani\ModuleManager\Console\Generators\MakeRepository::class, 48 | 'module_manager.console.generator.make-facade' => \Mrabbani\ModuleManager\Console\Generators\MakeFacade::class, 49 | 'module_manager.console.generator.make-service' => \Mrabbani\ModuleManager\Console\Generators\MakeService::class, 50 | 'module_manager.console.generator.make-support' => \Mrabbani\ModuleManager\Console\Generators\MakeSupport::class, 51 | // 'module_manager.console.generator.make-view' => \Mrabbani\ModuleManager\Console\Generators\MakeView::class, 52 | 'module_manager.console.generator.make-migration' => \Mrabbani\ModuleManager\Console\Generators\MakeMigration::class, 53 | 'module_manager.console.generator.make-command' => \Mrabbani\ModuleManager\Console\Generators\MakeCommand::class, 54 | 'module_manager.console.generator.make-seeder' => \Mrabbani\ModuleManager\Console\Generators\MakeSeeder::class, 55 | ]; 56 | foreach ($generators as $slug => $class) { 57 | $this->app->singleton($slug, function ($app) use ($slug, $class) { 58 | return $app[$class]; 59 | }); 60 | 61 | $this->commands($slug); 62 | } 63 | } 64 | 65 | /** 66 | * register database migrate related command 67 | */ 68 | private function migrationCommands() 69 | { 70 | $this->registerModuleMigrator(); 71 | $this->registerMigrateCommand(); 72 | } 73 | 74 | private function registerMigrateCommand() 75 | { 76 | $commands = [ 77 | 'module_manager.console.command.module-migrate' => \Mrabbani\ModuleManager\Console\Migrations\ModuleMigrateCommand::class 78 | ]; 79 | foreach ($commands as $slug => $class) { 80 | $this->app->singleton($slug, function ($app) use ($slug, $class) { 81 | return $app[$class]; 82 | }); 83 | 84 | $this->commands($slug); 85 | } 86 | $this->registerRollbackCommand(); 87 | 88 | } 89 | private function otherCommands() 90 | { 91 | $commands = [ 92 | 'module_manager.console.command.module-install' => \Mrabbani\ModuleManager\Console\Commands\InstallModuleCommand::class, 93 | 'module_manager.console.command.module-uninstall' => \Mrabbani\ModuleManager\Console\Commands\UninstallModuleCommand::class, 94 | 'module_manager.console.command.disable-module' => \Mrabbani\ModuleManager\Console\Commands\DisableModuleCommand::class, 95 | 'module_manager.console.command.enable-module' => \Mrabbani\ModuleManager\Console\Commands\EnableModuleCommand::class, 96 | 'module_manager.console.command.module-route-list' => \Mrabbani\ModuleManager\Console\Commands\RouteListCommand::class, 97 | 'module_manager.console.command.module-db-seed' => \Mrabbani\ModuleManager\Console\Commands\ModuleSeedCommand::class, 98 | ]; 99 | foreach ($commands as $slug => $class) { 100 | $this->app->singleton($slug, function ($app) use ($slug, $class) { 101 | return $app[$class]; 102 | }); 103 | 104 | $this->commands($slug); 105 | } 106 | } 107 | /** 108 | * Register the "rollback" migration command. 109 | * 110 | * @return void 111 | */ 112 | protected function registerRollbackCommand() 113 | { 114 | $this->app->singleton('module_manager.console.command.migration-rollback', function ($app) { 115 | return new \Mrabbani\ModuleManager\Console\Migrations\RollbackCommand($app['module.migrator']); 116 | }); 117 | $this->commands('module_manager.console.command.migration-rollback'); 118 | } 119 | 120 | 121 | protected function registerModuleMigrator() 122 | { 123 | // The migrator is responsible for actually running and rollback the migration 124 | // files in the application. We'll pass in our database connection resolver 125 | // so the migrator can resolve any of these connections when it needs to. 126 | $this->app->singleton('module.migrator', function ($app) { 127 | 128 | return new ModuleMigrator($app); 129 | }); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Providers/LoadModulesServiceProvider.php: -------------------------------------------------------------------------------- 1 | modules = get_all_module_information(); 19 | 20 | foreach ($this->modules as $module) { 21 | $needToBootstrap = false; 22 | if (array_get($module, 'installed', null) === true) { 23 | $needToBootstrap = true; 24 | } 25 | if ($needToBootstrap) { 26 | /** 27 | * Register module 28 | */ 29 | $moduleProvider = $module['namespace'] . '\Providers\ModuleProvider'; 30 | 31 | if (class_exists($moduleProvider)) { 32 | $this->app->register($moduleProvider); 33 | } else { 34 | $this->notLoadedModules[] = $moduleProvider; 35 | } 36 | } 37 | } 38 | } 39 | 40 | public function boot() 41 | { 42 | app()->booted(function () { 43 | $this->booted(); 44 | }); 45 | } 46 | 47 | private function booted() 48 | { 49 | \ModulesManagement::setModules($this->modules); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Providers/ModuleProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 16 | __DIR__ . '/../../config' => base_path('config'), 17 | ], 'config'); 18 | } 19 | 20 | /** 21 | * Register the application services. 22 | * 23 | * @return void 24 | */ 25 | public function register() 26 | { 27 | //Load config 28 | $this->mergeConfigFrom( 29 | __DIR__.'/../../config/module_manager.php', 'module_manager' 30 | ); 31 | 32 | //Load helpers 33 | $this->loadHelpers(); 34 | 35 | $this->app->register(ConsoleServiceProvider::class); 36 | $this->app->register(LoadModulesServiceProvider::class); 37 | 38 | //Register related facades 39 | $loader = \Illuminate\Foundation\AliasLoader::getInstance(); 40 | $loader->alias('ModulesManagement', ModulesManagementFacade::class); 41 | } 42 | 43 | protected function loadHelpers() 44 | { 45 | $helpers = $this->app['files']->glob(__DIR__ . '/../../helpers/*.php'); 46 | foreach ($helpers as $helper) { 47 | require_once $helper; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Services/ModuleMigrator.php: -------------------------------------------------------------------------------- 1 | notes = []; 28 | 29 | $rolledBack = []; 30 | 31 | 32 | // We want to pull in the last batch of migrations that ran on the previous 33 | // migration operation. We'll then reverse those migrations and run each 34 | // of them "down" to reverse the last migration "operation" which ran. 35 | if (($steps = Arr::get($options, 'step', 0)) > 0) { 36 | $migrations = $this->repository->getMigrations($steps); 37 | } else { 38 | $migrations = $this->repository->getLast(); 39 | } 40 | 41 | $count = count($migrations); 42 | 43 | $files = $this->getMigrationFiles($paths); 44 | 45 | if ($count === 0) { 46 | $this->note('Nothing to rollback.'); 47 | } else { 48 | // Next we will run through all of the migrations and call the "down" method 49 | // which will reverse each migration in order. This getLast method on the 50 | // repository already returns these migration's names in reverse order. 51 | $this->requireFiles($files); 52 | 53 | foreach ($migrations as $migration) { 54 | $migration = (object) $migration; 55 | if(! isset($files[$migration->migration])) { 56 | continue; 57 | } 58 | 59 | $rolledBack[] = $files[$migration->migration]; 60 | 61 | $this->runDown( 62 | $files[$migration->migration], 63 | $migration, Arr::get($options, 'pretend', false) 64 | ); 65 | } 66 | } 67 | 68 | return $rolledBack; 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /src/Support/Facades/ModulesManagementFacade.php: -------------------------------------------------------------------------------- 1 | composer = $composer; 22 | $this->composer->setWorkingPath(base_path()); 23 | } 24 | 25 | /** 26 | * @param array $modules 27 | * @return $this 28 | */ 29 | public function setModules(array $modules) 30 | { 31 | $this->modules = $modules; 32 | 33 | return $this; 34 | } 35 | 36 | /** 37 | * @param null|string $alias 38 | * @return mixed|null 39 | */ 40 | public function getModule($alias = null) 41 | { 42 | if(! count($this->modules)) { 43 | return get_module_information($alias); 44 | } 45 | 46 | if (!$alias) { 47 | return $this->modules; 48 | } 49 | foreach ($this->modules as $module) { 50 | if (array_get($module, 'alias') === $alias) { 51 | return $module; 52 | } 53 | } 54 | return null; 55 | } 56 | 57 | /** 58 | * @param string $alias 59 | * @param array $data 60 | * @param Closure|null $callback 61 | * @return $this 62 | */ 63 | public function modifyModule($alias, array $data, \Closure $callback = null) 64 | { 65 | $currentModule = $this->getModule($alias); 66 | if (!$currentModule) { 67 | throw new \RuntimeException('Module not found: ' . $alias); 68 | } 69 | 70 | $file = $currentModule['file']; 71 | unset($currentModule['file']); 72 | unset($currentModule['type']); 73 | 74 | File::put($file, json_encode_pretify(array_merge($currentModule, $data))); 75 | 76 | if ($callback) { 77 | call_user_func($callback); 78 | } 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * @param $alias 85 | * @param bool|true $withEvent 86 | * @return $this 87 | */ 88 | public function enableModule($alias, $withEvent = true) 89 | { 90 | $this->modifyModule($alias, ['enabled' => true], function () use ($alias, $withEvent) { 91 | if ($withEvent) { 92 | event(new ModuleEnabled($alias)); 93 | } 94 | }); 95 | // $result = $this->modifyModuleAutoload($alias); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * @param string $alias 102 | * @return ModulesManagement 103 | */ 104 | public function disableModule($alias, $withEvent = true) 105 | { 106 | $this->modifyModule($alias, ['enabled' => false], function () use ($alias, $withEvent) { 107 | if ($withEvent) { 108 | event(new ModuleDisabled($alias)); 109 | } 110 | }); 111 | 112 | // $result = $this->modifyModuleAutoload($alias, true); 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * Determine when module is activated 119 | * @param string $moduleName 120 | * @param \Closure|null $trueCallback 121 | * @param \Closure|null $falseCallback 122 | * @return bool 123 | */ 124 | public function isActivated($moduleName, Closure $trueCallback = null, Closure $falseCallback = null) 125 | { 126 | $module = $this->getModule($moduleName); 127 | if ($module && isset($module['enabled']) && $module['enabled']) { 128 | if ($trueCallback) { 129 | call_user_func($trueCallback); 130 | } 131 | return true; 132 | } 133 | if ($falseCallback) { 134 | call_user_func($falseCallback); 135 | } 136 | return false; 137 | } 138 | 139 | /** 140 | * @param string $type 141 | * @param null|int $page 142 | * @param int $perPage 143 | * @return \Illuminate\Support\Collection 144 | */ 145 | public function export($type = 'base', $page = null, $perPage = 10) 146 | { 147 | $modules = collect($this->modules) 148 | ->where('type', '=', $type); 149 | 150 | if ($page) { 151 | $modules = $modules->forPage($page, $perPage); 152 | } 153 | 154 | return $modules; 155 | } 156 | 157 | /** 158 | * Modify the composer autoload information 159 | * @param $alias 160 | * @param bool $isDisabled 161 | * @return $this 162 | */ 163 | public function modifyModuleAutoload($alias, $isDisabled = false) 164 | { 165 | $module = $this->getModule($alias); 166 | if (!$module) { 167 | return $this; 168 | } 169 | $moduleAutoloadType = array_get($module, 'autoload', 'psr-4'); 170 | $relativePath = str_replace(base_path() . DIRECTORY_SEPARATOR, '', str_replace('module.json', '', array_get($module, 'file', ''))) . 'src'; 171 | 172 | $moduleNamespace = array_get($module, 'namespace'); 173 | 174 | if (!$moduleNamespace) { 175 | return $this; 176 | } 177 | 178 | if (substr($moduleNamespace, -1) !== '\\') { 179 | $moduleNamespace .= '\\'; 180 | } 181 | 182 | /** 183 | * Composer information 184 | */ 185 | $composerContent = json_decode(File::get(base_path('composer.json')), true); 186 | $autoload = array_get($composerContent, 'autoload', []); 187 | 188 | if (!array_get($autoload, $moduleAutoloadType)) { 189 | $autoload[$moduleAutoloadType] = []; 190 | } 191 | 192 | if ($isDisabled === true) { 193 | if (isset($autoload[$moduleAutoloadType][$moduleNamespace])) { 194 | unset($autoload[$moduleAutoloadType][$moduleNamespace]); 195 | } 196 | } else { 197 | if ($moduleAutoloadType === 'classmap') { 198 | $autoload[$moduleAutoloadType][] = $relativePath; 199 | } else { 200 | $autoload[$moduleAutoloadType][$moduleNamespace] = $relativePath; 201 | } 202 | } 203 | $composerContent['autoload'] = $autoload; 204 | 205 | /** 206 | * Save file 207 | */ 208 | File::put(base_path('composer.json'), json_encode_pretify($composerContent)); 209 | $this->refreshComposerAutoload(); 210 | 211 | 212 | return $this; 213 | } 214 | 215 | /** 216 | * Run command composer dump-autoload 217 | * @return $this 218 | */ 219 | public function refreshComposerAutoload() 220 | { 221 | $this->composer->dumpAutoloads(); 222 | 223 | return $this; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /tests/Unit/ModuleManagerTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 22 | } 23 | 24 | public function testAvailableCommands() 25 | { 26 | // Artisan::call('module:create', ['alias'=> $this->module, "\n","\n", 'Mahbub' ]); 27 | Artisan::call('module:make:controller', ['alias'=> $this->module, 'name'=> 'TestController']); 28 | Artisan::call('module:make:command', ['alias'=> $this->module, 'name'=> 'TestCommand']); 29 | Artisan::call('module:make:facade', ['alias'=> $this->module, 'name'=> 'TestFacade']); 30 | Artisan::call('module:make:middleware', ['alias'=> $this->module, 'name'=> 'TestMiddleware']); 31 | Artisan::call('module:make:migration', ['alias'=> $this->module, 'name' => 'create_test_table' , '--table'=>'tests']); 32 | Artisan::call('module:make:model',['alias'=> $this->module, 'name'=> 'TestModel']); 33 | Artisan::call('module:make:provider',['alias'=> $this->module, 'name'=> 'TestProvider']); 34 | Artisan::call('module:make:request',['alias'=> $this->module, 'name'=> 'TestRequest']); 35 | Artisan::call('module:make:service',['alias'=> $this->module, 'name'=> 'TestService']); 36 | Artisan::call('module:migrate',['alias'=> $this->module]); 37 | Artisan::call('module:migrate:rollback',['alias'=> $this->module]); 38 | Artisan::call('module:install',['alias'=> $this->module]); 39 | Artisan::call('module:uninstall',['alias'=> $this->module]); 40 | } 41 | } 42 | --------------------------------------------------------------------------------