├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── service-maker.php ├── laravel-service-maker.png ├── src ├── Actions │ ├── CreateServiceContractFileAction.php │ └── CreateServiceFileAction.php ├── Commands │ ├── Files │ │ ├── Contract │ │ │ └── CreateServiceContractCommand.php │ │ ├── Migration │ │ │ └── CreateServiceMigrationCommand.php │ │ └── Service │ │ │ ├── CreateServiceFileCommand.php │ │ │ └── CreateServiceFileWithNoContractCommand.php │ └── LaravelServiceMakerCommand.php ├── Contracts │ ├── CreateServiceContractFileActionContract.php │ └── CreateServiceFileActionContract.php └── LaravelServiceMakerServiceProvider.php └── stubs ├── service-contract.stub ├── service-with-contract.stub └── service-without-contract.stub /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-service-maker` will be documented in this file. 4 | 5 | ## v1.0.1 - 2022-07-26 6 | 7 | ### Added 8 | 9 | - Artisan make:service command 10 | - Adds --noContract to make:service command 11 | - Adds --service combined with make:model command 12 | - Adds --noContract to make:model command 13 | - Adds aliases -N and -S for make:model command 14 | - Modified the make:model Model --all to generate a service with contract too 15 | - Tests added with Pest 16 | 17 | ## v1.0.0 - 2022-07-25 18 | 19 | ### Added 20 | 21 | - Artisan make:service command 22 | - Adds --noContract to make:service command 23 | - Adds --service combined with make:model command 24 | - Adds --noContract to make:model command 25 | - Adds alias -N and -S for make:model command 26 | - Modified the make:model Model --all to generate a service with contract too 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) nordcoders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Laravel Service Maker

2 | 3 |

4 | 5 | Total Downloads 6 | 7 | 8 | Latest Stable Version 9 | 10 | 11 | License 12 | 13 |

14 | 15 | ## What does it do? 16 | 17 | This package adds a new `php artisan make:service {name} {--N|noContract}` command. It will create a service file and its contract (interface) for saving time while working with Laravel Framework and benefit from the **Service Pattern**. 18 | 19 | ## Installation 20 | 21 | You can install the package via composer: 22 | 23 | ```bash 24 | composer require nordcoders/laravel-service-maker --dev 25 | ``` 26 | 27 | ## How does it work? 28 | 29 | After installation, the command `php artisan make:service {name} {--N|noContract}` will be available. 30 | 31 | ### Create services files 32 | 33 | For example, the command `php artisan make:service createUser` will generate a service file called `CreateUserService.php` located in `app/Services/CreateUser`. 34 | 35 | It will also generate an interface (contract) called `CreateUserContract.php` located in `app/Services/Contracts`. 36 | 37 | ### Create services for models 38 | 39 | Adding a ```--service``` or ```-S``` option is now available when creating a model. 40 | 41 | For example, the command `php artisan make:model Book --service` or `php artisan make:model Book -S` will generate a model with service too. 42 | 43 | The command `php artisan make:model Book --all` or `php artisan make:model Book -a` will now generate a model, migration, factory, seeder, policy, controller, form requests and service. 44 | 45 | ### Contracts 46 | 47 | Adding a ```--noContract``` or ```-N``` option will prevent the commands from implementing any contract and will not create any contract file. 48 | 49 | If you never need any contracts. Publish the config file and then turn the **with_interface** value to false in the config file. 50 | 51 | ## Configuration file 52 | 53 | You can publish the config file with: 54 | 55 | ```bash 56 | php artisan vendor:publish --tag="service-maker-config" 57 | ``` 58 | 59 | This is the content of the published config file: 60 | 61 | ```php 62 | return [ 63 | 'with_interface' => true, 64 | ]; 65 | ``` 66 | 67 | ## Credits 68 | 69 | - [Ludovic Guénet](https://github.com/ludoguenet) 70 | - [All Contributors](../../contributors) 71 | 72 | ## License 73 | 74 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 75 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nordcoders/laravel-service-maker", 3 | "description": "Generate services and contracts in Laravel with the artisan command", 4 | "keywords": [ 5 | "nordcoders", 6 | "laravel", 7 | "laravel-service-maker" 8 | ], 9 | "homepage": "https://github.com/nordcoders/laravel-service-maker", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Ludovic Guénet", 14 | "email": "ludovicguenet@gmx.com", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.1", 20 | "spatie/laravel-package-tools": "^1.9.2", 21 | "illuminate/contracts": "^9.0" 22 | }, 23 | "require-dev": { 24 | "laravel/pint": "^1.0", 25 | "nunomaduro/collision": "^6.0", 26 | "nunomaduro/larastan": "^2.0.1", 27 | "orchestra/testbench": "^7.0", 28 | "pestphp/pest": "^1.21", 29 | "pestphp/pest-plugin-laravel": "^1.1", 30 | "phpstan/extension-installer": "^1.1", 31 | "phpstan/phpstan-deprecation-rules": "^1.0", 32 | "phpstan/phpstan-phpunit": "^1.0", 33 | "phpunit/phpunit": "^9.5", 34 | "spatie/laravel-ray": "^1.26" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "NordCoders\\LaravelServiceMaker\\": "src", 39 | "NordCoders\\LaravelServiceMaker\\Database\\Factories\\": "database/factories" 40 | } 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { 44 | "NordCoders\\LaravelServiceMaker\\Tests\\": "tests" 45 | } 46 | }, 47 | "scripts": { 48 | "analyse": "vendor/bin/phpstan analyse", 49 | "test": "vendor/bin/pest", 50 | "test-coverage": "vendor/bin/pest --coverage", 51 | "format": "vendor/bin/pint" 52 | }, 53 | "config": { 54 | "sort-packages": true, 55 | "allow-plugins": { 56 | "pestphp/pest-plugin": true, 57 | "phpstan/extension-installer": true 58 | } 59 | }, 60 | "extra": { 61 | "laravel": { 62 | "providers": [ 63 | "NordCoders\\LaravelServiceMaker\\LaravelServiceMakerServiceProvider" 64 | ], 65 | "aliases": { 66 | "LaravelServiceMaker": "NordCoders\\LaravelServiceMaker\\Facades\\LaravelServiceMaker" 67 | } 68 | } 69 | }, 70 | "minimum-stability": "dev", 71 | "prefer-stable": true 72 | } 73 | -------------------------------------------------------------------------------- /config/service-maker.php: -------------------------------------------------------------------------------- 1 | true, 5 | ]; 6 | -------------------------------------------------------------------------------- /laravel-service-maker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ludoguenet/laravel-service-maker/76d970fd0429cebacda4eba1ba959f13caa84537/laravel-service-maker.png -------------------------------------------------------------------------------- /src/Actions/CreateServiceContractFileAction.php: -------------------------------------------------------------------------------- 1 | generateContract( 23 | serviceName: $serviceName, 24 | serviceMakerCommand: $serviceMakerCommand, 25 | ); 26 | 27 | return; 28 | } 29 | } 30 | 31 | protected function generateContract(string $serviceName, Command $serviceMakerCommand) 32 | { 33 | $serviceMakerCommand->call('make:servicecontractfile', [ 34 | 'name' => $serviceName, 35 | ]); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Actions/CreateServiceFileAction.php: -------------------------------------------------------------------------------- 1 | withNoContract( 19 | serviceName: $serviceName, 20 | serviceMakerCommand: $serviceMakerCommand, 21 | ); 22 | 23 | return; 24 | } 25 | 26 | if (config('service-maker.with_interface')) { 27 | $this->withContract( 28 | serviceName: $serviceName, 29 | serviceMakerCommand: $serviceMakerCommand, 30 | ); 31 | 32 | return; 33 | } 34 | 35 | $this->withNoContract( 36 | serviceName: $serviceName, 37 | serviceMakerCommand: $serviceMakerCommand, 38 | ); 39 | } 40 | 41 | protected function withContract(string $serviceName, Command $serviceMakerCommand): void 42 | { 43 | $serviceMakerCommand->call('make:servicefile', [ 44 | 'name' => $serviceName, 45 | ]); 46 | } 47 | 48 | protected function withNoContract(string $serviceName, Command $serviceMakerCommand): void 49 | { 50 | $serviceMakerCommand->call('make:servicewithnocontract', [ 51 | 'name' => $serviceName, 52 | ]); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Commands/Files/Contract/CreateServiceContractCommand.php: -------------------------------------------------------------------------------- 1 | files->get($this->getStub()); 54 | 55 | return $this->replaceNamespace($stub, $contractName) 56 | ->replaceClass($stub, $contractName); 57 | } 58 | 59 | /** 60 | * Get the destination class path. 61 | * 62 | * @param string $name 63 | * @return string 64 | */ 65 | protected function getPath($name): string 66 | { 67 | $name = Str::replaceFirst($this->rootNamespace(), '', $name); 68 | 69 | return $this->laravel['path'].'/'.str_replace('\\', '/', $name.'Contract').'.php'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Commands/Files/Migration/CreateServiceMigrationCommand.php: -------------------------------------------------------------------------------- 1 | createServiceFileAction = $createServiceFileAction; 29 | $this->createServiceContractFileAction = $createServiceContractFileAction; 30 | } 31 | 32 | public function handle(): void 33 | { 34 | parent::handle(); 35 | 36 | if ($this->option('all')) { 37 | $this->input->setOption('service', true); 38 | } 39 | 40 | if ($this->option('service')) { 41 | $this->createService(); 42 | } 43 | } 44 | 45 | public function getOptions(): array 46 | { 47 | $options = parent::getOptions(); 48 | 49 | $options[] = ['service', 'S', InputOption::VALUE_NONE, 'Create a service for the model']; 50 | $options[] = ['noContract', 'N', InputOption::VALUE_NONE, 'Create a service without contract']; 51 | 52 | return $options; 53 | } 54 | 55 | protected function createService(): void 56 | { 57 | $this->createServiceFileAction->handle( 58 | serviceName: $this->getFormattedName(), 59 | noContract: $this->option('noContract'), 60 | serviceMakerCommand: $this, 61 | ); 62 | 63 | $this->createServiceContractFileAction->handle( 64 | serviceName: $this->getFormattedName(), 65 | noContract: $this->option('noContract'), 66 | serviceMakerCommand: $this, 67 | ); 68 | } 69 | 70 | protected function getFormattedName(): string 71 | { 72 | return Str::studly($this->getNameInput()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Commands/Files/Service/CreateServiceFileCommand.php: -------------------------------------------------------------------------------- 1 | argument('name') 40 | ) 41 | ->ucfirst(); 42 | 43 | return "{$rootNamespace}\\Services\\{$serviceName}"; 44 | } 45 | 46 | /** 47 | * Build the class with the given name. 48 | * 49 | * @param string $name 50 | * @return string 51 | * 52 | * @throws FileNotFoundException 53 | */ 54 | protected function buildClass($name): string 55 | { 56 | $serviceName = "{$name}Service"; 57 | 58 | $stub = $this->files->get($this->getStub()); 59 | 60 | return $this->replaceNamespace($stub, $serviceName) 61 | ->replaceClass($stub, $name); 62 | } 63 | 64 | /** 65 | * Replace the class name for the given stub. 66 | * 67 | * @param string $stub 68 | * @param string $name 69 | * @return string 70 | */ 71 | protected function replaceClass($stub, $name): string 72 | { 73 | $serviceName = "{$name}Service"; 74 | $class = str_replace($this->getNamespace($serviceName).'\\', '', $serviceName); 75 | $contractName = str_replace($this->getNamespace($serviceName).'\\', '', $name).'Contract'; 76 | $contractNamespace = $this->rootNamespace()."Services\\Contracts\\{$contractName}"; 77 | 78 | $replace = [ 79 | '{{ class }}' => $class, 80 | '{{class}}' => $class, 81 | '{{ contract }}' => $contractName, 82 | '{{contract}}' => $contractName, 83 | '{{ contractNamespace }}' => $contractNamespace, 84 | '{{contractNamespace}}' => $contractNamespace, 85 | ]; 86 | 87 | return str_replace(array_keys($replace), array_values($replace), $stub); 88 | } 89 | 90 | /** 91 | * Get the destination class path. 92 | * 93 | * @param string $name 94 | * @return string 95 | */ 96 | protected function getPath($name): string 97 | { 98 | $name = Str::replaceFirst($this->rootNamespace(), '', $name); 99 | 100 | return $this->laravel['path'].'/'.str_replace('\\', '/', $name.'Service').'.php'; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Commands/Files/Service/CreateServiceFileWithNoContractCommand.php: -------------------------------------------------------------------------------- 1 | argument('name') 40 | ) 41 | ->ucfirst(); 42 | 43 | return "{$rootNamespace}\\Services\\{$serviceName}"; 44 | } 45 | 46 | /** 47 | * Build the class with the given name. 48 | * 49 | * @param string $name 50 | * @return string 51 | * 52 | * @throws FileNotFoundException 53 | */ 54 | protected function buildClass($name): string 55 | { 56 | $serviceName = "{$name}Service"; 57 | 58 | $stub = $this->files->get($this->getStub()); 59 | 60 | return $this->replaceNamespace($stub, $serviceName) 61 | ->replaceClass($stub, $name); 62 | } 63 | 64 | /** 65 | * Replace the class name for the given stub. 66 | * 67 | * @param string $stub 68 | * @param string $name 69 | * @return string 70 | */ 71 | protected function replaceClass($stub, $name): string 72 | { 73 | $serviceName = "{$name}Service"; 74 | $class = str_replace($this->getNamespace($serviceName).'\\', '', $serviceName); 75 | 76 | $replace = [ 77 | '{{ class }}' => $class, 78 | '{{class}}' => $class, 79 | ]; 80 | 81 | return str_replace(array_keys($replace), array_values($replace), $stub); 82 | } 83 | 84 | /** 85 | * Get the destination class path. 86 | * 87 | * @param string $name 88 | * @return string 89 | */ 90 | protected function getPath($name): string 91 | { 92 | $name = Str::replaceFirst($this->rootNamespace(), '', $name); 93 | 94 | return $this->laravel['path'].'/'.str_replace('\\', '/', $name.'Service').'.php'; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Commands/LaravelServiceMakerCommand.php: -------------------------------------------------------------------------------- 1 | argument('name')); 37 | 38 | $createServiceFileAction->handle( 39 | serviceName: $name, 40 | noContract: $this->option('noContract'), 41 | serviceMakerCommand: $this, 42 | ); 43 | 44 | $createServiceContractFileAction->handle( 45 | serviceName: $name, 46 | noContract: $this->option('noContract'), 47 | serviceMakerCommand: $this, 48 | ); 49 | 50 | $this->comment('Service files created with success!'); 51 | 52 | return self::SUCCESS; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Contracts/CreateServiceContractFileActionContract.php: -------------------------------------------------------------------------------- 1 | CreateServiceFileAction::class, 23 | CreateServiceContractFileActionContract::class => CreateServiceContractFileAction::class, 24 | ]; 25 | 26 | public function configurePackage(Package $package): void 27 | { 28 | $package 29 | ->name('laravel-service-maker') 30 | ->hasConfigFile('service-maker') 31 | ->hasCommand(LaravelServiceMakerCommand::class) 32 | ->hasCommand(CreateServiceFileCommand::class) 33 | ->hasCommand(CreateServiceFileWithNoContractCommand::class) 34 | ->hasCommand(CreateServiceContractCommand::class) 35 | ->hasCommand(CreateServiceMigrationCommand::class); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /stubs/service-contract.stub: -------------------------------------------------------------------------------- 1 |