├── .gitignore ├── README.md ├── composer.json ├── composer.lock ├── config └── artisan-maker.php ├── phpunit.xml ├── phpunit.xml.bak ├── src ├── Console │ ├── ActionMakeCommand.php │ ├── FacadeMakeCommand.php │ ├── FileGenerable.php │ ├── InterfaceMakeCommand.php │ ├── ServiceMakeCommand.php │ └── stubs │ │ ├── class-implement-interface.stub │ │ ├── class.stub │ │ ├── facade.stub │ │ └── interface.stub └── LaravelArtisanMakerServiceProvider.php ├── testbench.yaml └── tests └── Feature ├── ActionMakeTest.php ├── FacadeMakeTest.php ├── InterfaceMakeTest.php └── ServiceMakeTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .phpunit.cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Artisan Maker 2 | A simple package that can help you create a boilerplate of a service, action, interface and facade class with artisan command. 3 | 4 | Example usage: 5 | ``` 6 | php artisan make:action UserStoreAction 7 | php artisan make:service UserService 8 | php artisan make:interface UserServiceInterface 9 | php artisan make:facade UserFacade 10 | ``` 11 | 12 | ## Installation 13 | ```bash 14 | composer require silverhand7/laravel-artisan-maker 15 | ``` 16 | 17 | ## Usage 18 | ### Create a service class: 19 | Run the following command: 20 | ``` 21 | php artisan make:service {YourService} 22 | ``` 23 | The service will be created and can be found at app/Services/{YourService}.php \ 24 | For example: `php artisan make:service UserService` 25 | #### Additionally, you can create a service that implements an interface class 26 | ``` 27 | php artisan make:service {YourService} --interface={YourInterface} 28 | ``` 29 | or 30 | ``` 31 | php artisan make:service {YourService} -i {YourInterface} 32 | ``` 33 | 34 | ### Create an action class: 35 | Run the following command: 36 | ``` 37 | php artisan make:action {YourAction} 38 | ``` 39 | The action will be created and can be found at app/Actions/{YourAction}.php \ 40 | For example: `php artisan make:action UserStoreAction` 41 | 42 | ### Create an interface class: 43 | Run the following command: 44 | ``` 45 | php artisan make:interface {YourInterface} 46 | ``` 47 | The interface will be created and can be found at app/Contracts/{YourInterface}.php \ 48 | For example: `php artisan make:interface UserServiceInterface` 49 | 50 | ### Create a facade class: 51 | Run the following command: 52 | ``` 53 | php artisan make:facade {YourFacade} 54 | ``` 55 | The facade will be created and can be found at app/Facades/{YourFacade}.php \ 56 | For example: `php artisan make:facade UserFacade` 57 | 58 | ## Custom your namespace and generated file location 59 | You can easily customize where you want to locate your Service, Action, Interface or Facade class. You can do that by publishing the config file using the following command: 60 | ``` 61 | php artisan vendor:publish --tag=artisan-maker-config 62 | ``` 63 | You can customize it in `config/artisan-maker.php`, for example: 64 | ``` 65 | 'service_interface' => 'App\MyOwnServices' 66 | 'service_directory' => 'app/MyOwnServices' 67 | ``` 68 | Your next generated service will be in the `app/MyOwnServices` folder and your namespace for service will be `App\MyOwnServices`. 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silverhand7/laravel-artisan-maker", 3 | "description": "A simple package that can help you to create a boilerplate of a service or action class.", 4 | "keywords": [ 5 | "laravel", 6 | "silverhand7", 7 | "laravel-artisan-maker" 8 | ], 9 | "autoload": { 10 | "psr-4": { 11 | "Silverhand7\\LaravelArtisanMaker\\": "src/" 12 | } 13 | }, 14 | "authors": [ 15 | { 16 | "name": "silverhand7", 17 | "email": "refojunior5@gmail.com" 18 | } 19 | ], 20 | "license": "MIT", 21 | "require": { 22 | "php": "^8.1", 23 | "spatie/laravel-package-tools": "^1.9.2" 24 | }, 25 | "extra": { 26 | "laravel": { 27 | "providers": [ 28 | "Silverhand7\\LaravelArtisanMaker\\LaravelArtisanMakerServiceProvider" 29 | ] 30 | } 31 | }, 32 | "require-dev": { 33 | "orchestra/testbench": "^8.19" 34 | }, 35 | "scripts": { 36 | "post-autoload-dump": [ 37 | "@clear", 38 | "@prepare" 39 | ], 40 | "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", 41 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 42 | "serve": [ 43 | "Composer\\Config::disableProcessTimeout", 44 | "@build", 45 | "@php vendor/bin/testbench serve" 46 | ], 47 | "test": [ 48 | "@php vendor/bin/phpunit" 49 | ] 50 | } 51 | } -------------------------------------------------------------------------------- /config/artisan-maker.php: -------------------------------------------------------------------------------- 1 | 'App\Services', 8 | 9 | /** 10 | * Set the default directory for your service class location. 11 | */ 12 | 'service_directory' => 'app/Services', 13 | 14 | /** 15 | * Set your default namespace for Action class 16 | */ 17 | 'action_namespace' => 'App\Actions', 18 | 19 | /** 20 | * Set the default directory for your action class location. 21 | */ 22 | 'action_directory' => 'app/Actions', 23 | 24 | /** 25 | * Set your default namespace for Interface class 26 | */ 27 | 'interface_namespace' => 'App\Contracts', 28 | 29 | /** 30 | * Set the default directory for your interface class location. 31 | */ 32 | 'interface_directory' => 'app/Contracts', 33 | 34 | /** 35 | * Set your default namespace for Facade class 36 | */ 37 | 'facade_namespace' => 'App\Facades', 38 | /** 39 | * Set the default directory for your facade class location. 40 | */ 41 | 'facade_directory' => 'app/Facades', 42 | 43 | ]; -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./tests/ 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /phpunit.xml.bak: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Console/ActionMakeCommand.php: -------------------------------------------------------------------------------- 1 | files->get($this->getStub()); 16 | 17 | return $this 18 | ->replaceNamespace($stub, $name) 19 | ->replaceClass($stub, $name); 20 | } 21 | 22 | protected function replaceClass($stub, $name): string 23 | { 24 | $className = Str::replace($this->getNamespace($name).'\\', '', $name); 25 | 26 | $replace = [ 27 | '{{ className }}' => $className, 28 | ]; 29 | 30 | return Str::replace(array_keys($replace), array_values($replace), $stub); 31 | } 32 | 33 | protected function getDefaultNamespace($rootNamespace): string 34 | { 35 | $type = Str::lower($this->type); 36 | $nameSpace = config("artisan-maker.{$type}_namespace"); 37 | 38 | return $nameSpace; 39 | } 40 | 41 | protected function getPath($name) 42 | { 43 | $type = Str::lower($this->type); 44 | return $this->laravel->basePath() . '/' . config("artisan-maker.{$type}_directory") . '/' . $this->getNameInput() .'.php'; 45 | } 46 | } -------------------------------------------------------------------------------- /src/Console/InterfaceMakeCommand.php: -------------------------------------------------------------------------------- 1 | option('interface')) { 27 | $interfaceUseNamespace = config('artisan-maker.interface_namespace') . '\\' . $interfaceName; 28 | 29 | if (!$this->checkInterfaceExists($interfaceUseNamespace)) { 30 | if ($this->confirm("The {$interfaceName} does not exist in " . config('artisan-maker.interface_namespace') . ", do you want to create one?", true)) { 31 | Artisan::call('make:interface', [ 32 | 'name' => $interfaceName 33 | ]); 34 | } 35 | } 36 | 37 | $stub = $this->files->get($this->getClassImplementInterfaceStub()); 38 | 39 | return $this 40 | ->replaceInterfaceUseNamespace($stub, $interfaceUseNamespace) 41 | ->replaceInterfaceClass($stub, $interfaceName) 42 | ->replaceNamespace($stub, $name) 43 | ->replaceClass($stub, $name); 44 | } 45 | 46 | $stub = $this->files->get($this->getStub()); 47 | 48 | return $this 49 | ->replaceNamespace($stub, $name) 50 | ->replaceClass($stub, $name); 51 | } 52 | 53 | protected function replaceInterfaceClass(&$stub, $interfaceName) 54 | { 55 | $stub = Str::replace("{{ interfaceName }}", $interfaceName, $stub); 56 | return $this; 57 | } 58 | 59 | protected function replaceInterfaceUseNamespace(&$stub, $interfaceUseNamespace) 60 | { 61 | $stub = Str::replace("{{ interfaceUseNamespace }}", $interfaceUseNamespace, $stub); 62 | return $this; 63 | } 64 | 65 | protected function checkInterfaceExists($interfaceUseNamespace): bool 66 | { 67 | $paths = explode('\\', $interfaceUseNamespace); 68 | array_shift($paths); 69 | return file_exists($this->laravel['path'] . '/' . implode('/', $paths) . '.php'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Console/stubs/class-implement-interface.stub: -------------------------------------------------------------------------------- 1 | name('laravel-artisan-maker') 18 | ->hasConfigFile() 19 | ->hasCommand(ServiceMakeCommand::class) 20 | ->hasCommand(ActionMakeCommand::class) 21 | ->hasCommand(InterfaceMakeCommand::class) 22 | ->hasCommand(FacadeMakeCommand::class); 23 | } 24 | } -------------------------------------------------------------------------------- /testbench.yaml: -------------------------------------------------------------------------------- 1 | providers: 2 | # - Workbench\App\Providers\WorkbenchServiceProvider 3 | 4 | migrations: 5 | - workbench/database/migrations 6 | 7 | seeders: 8 | - Workbench\Database\Seeders\DatabaseSeeder 9 | 10 | workbench: 11 | start: '/' 12 | install: true 13 | discovers: 14 | web: true 15 | api: false 16 | commands: false 17 | components: false 18 | views: false 19 | build: [] 20 | assets: [] 21 | sync: [] 22 | -------------------------------------------------------------------------------- /tests/Feature/ActionMakeTest.php: -------------------------------------------------------------------------------- 1 | > 13 | */ 14 | protected function getPackageProviders($app) 15 | { 16 | return [ 17 | LaravelArtisanMakerServiceProvider::class, 18 | ]; 19 | } 20 | 21 | public function test_make_action_command() 22 | { 23 | $this->artisan('make:action HelloAction'); 24 | $this->assertTrue(true); 25 | $this->assertFileExists(app_path('Actions/HelloAction.php')); 26 | } 27 | 28 | public function test_make_action_command_customized_directory() 29 | { 30 | $this->app['config']['artisan-maker.action_directory'] = 'app/CustomActionDirectory'; 31 | $this->artisan('make:action HelloAction'); 32 | $this->assertTrue(true); 33 | $this->assertFileExists(app_path('CustomActionDirectory/HelloAction.php')); 34 | } 35 | } -------------------------------------------------------------------------------- /tests/Feature/FacadeMakeTest.php: -------------------------------------------------------------------------------- 1 | > 13 | */ 14 | protected function getPackageProviders($app) 15 | { 16 | return [ 17 | LaravelArtisanMakerServiceProvider::class, 18 | ]; 19 | } 20 | 21 | public function test_make_facade_command() 22 | { 23 | $this->artisan('make:facade HelloFacade'); 24 | $this->assertTrue(true); 25 | $this->assertFileExists(app_path('Facades/HelloFacade.php')); 26 | } 27 | 28 | public function test_make_facade_command_customized_directory() 29 | { 30 | $this->app['config']['artisan-maker.facade_directory'] = 'app/CustomFacadesDirectory'; 31 | $this->artisan('make:facade HelloFacade'); 32 | $this->assertTrue(true); 33 | $this->assertFileExists(app_path('CustomFacadesDirectory/HelloFacade.php')); 34 | } 35 | } -------------------------------------------------------------------------------- /tests/Feature/InterfaceMakeTest.php: -------------------------------------------------------------------------------- 1 | > 13 | */ 14 | protected function getPackageProviders($app) 15 | { 16 | return [ 17 | LaravelArtisanMakerServiceProvider::class, 18 | ]; 19 | } 20 | 21 | public function test_make_interface_command() 22 | { 23 | $this->artisan('make:interface HelloInterface'); 24 | $this->assertTrue(true); 25 | $this->assertFileExists(app_path('Contracts/HelloInterface.php')); 26 | } 27 | 28 | public function test_make_interface_command_customized_directory() 29 | { 30 | $this->app['config']['artisan-maker.interface_directory'] = 'app/CustonInterfaceDirectory'; 31 | $this->artisan('make:interface HelloInterface'); 32 | $this->assertTrue(true); 33 | $this->assertFileExists(app_path('CustonInterfaceDirectory/HelloInterface.php')); 34 | } 35 | } -------------------------------------------------------------------------------- /tests/Feature/ServiceMakeTest.php: -------------------------------------------------------------------------------- 1 | > 13 | */ 14 | protected function getPackageProviders($app) 15 | { 16 | return [ 17 | LaravelArtisanMakerServiceProvider::class, 18 | ]; 19 | } 20 | 21 | public function test_make_service_command() 22 | { 23 | $this->artisan('make:service HelloService'); 24 | $this->assertTrue(true); 25 | $this->assertFileExists(app_path('Services/HelloService.php')); 26 | } 27 | 28 | public function test_make_service_command_customized_directory() 29 | { 30 | $this->app['config']['artisan-maker.service_directory'] = 'app/CustomServiceDirectory'; 31 | $this->artisan('make:service HelloService'); 32 | $this->assertTrue(true); 33 | $this->assertFileExists(app_path('CustomServiceDirectory/HelloService.php')); 34 | } 35 | } --------------------------------------------------------------------------------