diff --git a/src/Commands/MakeAbstractStateCommand.php b/src/Commands/MakeAbstractStateCommand.php new file mode 100644 index 0000000..32ea04c --- /dev/null +++ b/src/Commands/MakeAbstractStateCommand.php @@ -0,0 +1,24 @@ +type)], + ['parent', InputArgument::REQUIRED, 'The name of the parent abstract state'], + ]; + } + + protected function buildClass($name) + { + $stub = $this->files->get($this->getStub()); + $parent = $this->getParent(); + + return $this + ->replaceNamespace($stub, $name) + ->replaceParent($stub, $parent) + ->replaceClass($stub, $name); + } + + protected function replaceParent(&$stub, $name): self + { + $class = str_replace($this->getNamespace($name).'\\', '', $name); + + $stub = str_replace(['DummyParent', '{{ parent }}', '{{parent}}'], $class, $stub); + + return $this; + } + + protected function getParent(): string + { + return trim($this->argument('parent')); + } +} diff --git a/src/Commands/MakeTransitionCommand.php b/src/Commands/MakeTransitionCommand.php new file mode 100644 index 0000000..c200932 --- /dev/null +++ b/src/Commands/MakeTransitionCommand.php @@ -0,0 +1,60 @@ +type)], + ['parent', InputArgument::REQUIRED, 'The name of the model'], + ]; + } + + protected function buildClass($name) + { + $stub = $this->files->get($this->getStub()); + $parent = $this->getParent(); + + return $this + ->replaceNamespace($stub, $name) + ->replaceParent($stub, $parent) + ->replaceClass($stub, $name); + } + + protected function replaceParent(&$stub, $name): self + { + $class = str_replace($this->getNamespace($name).'\\', '', $name); + + $stub = str_replace(['DummyParent', '{{ parent }}', '{{parent}}'], $class, $stub); + $stub = str_replace('model', Str::camel($class), $stub); + + return $this; + } + + protected function getParent(): string + { + return trim($this->argument('parent')); + } +} diff --git a/src/ModelStatesServiceProvider.php b/src/ModelStatesServiceProvider.php index 42a66c8..4c0f934 100644 --- a/src/ModelStatesServiceProvider.php +++ b/src/ModelStatesServiceProvider.php @@ -4,6 +4,9 @@ use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; +use Spatie\ModelStates\Commands\MakeAbstractStateCommand; +use Spatie\ModelStates\Commands\MakeStateCommand; +use Spatie\ModelStates\Commands\MakeTransitionCommand; class ModelStatesServiceProvider extends PackageServiceProvider { @@ -11,6 +14,11 @@ public function configurePackage(Package $package): void { $package ->name('laravel-model-states') + ->hasCommands([ + MakeAbstractStateCommand::class, + MakeStateCommand::class, + MakeTransitionCommand::class, + ]) ->hasConfigFile(); } } diff --git a/stubs/abstract-state.stub b/stubs/abstract-state.stub new file mode 100644 index 0000000..2c0ea4a --- /dev/null +++ b/stubs/abstract-state.stub @@ -0,0 +1,10 @@ +model; + } + + public function canTransition(): bool + { + // + } +} diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php new file mode 100644 index 0000000..4565b52 --- /dev/null +++ b/tests/CommandsTest.php @@ -0,0 +1,43 @@ +app->basePath('app/Models/States') . '/AbstractState.php'; + + $this->artisan('make:abstract-state AbstractState')->assertExitCode(0); + + expect($file) + ->toBeFile() + ->toContainAsFile('class AbstractState extends State'); + + unlink($file); +}); + +it('can generate states', function () { + $file = $this->app->basePath('app/Models/States') . '/State.php'; + + $this->artisan('make:state State') + ->expectsQuestion('What is the name of the parent abstract state?', 'AbstractState') + ->assertExitCode(0); + + expect($file) + ->toBeFile() + ->toContainAsFile('class State extends AbstractState'); + + unlink($file); +}); + +it('can generate transitions', function () { + $file = $this->app->basePath('app/Models/States') . '/CustomTransition.php'; + + $this->artisan('make:transition CustomTransition') + ->expectsQuestion('What is the name of the model?', 'Model') + ->assertExitCode(0); + + expect($file) + ->toBeFile() + ->toContainAsFile('class CustomTransition extends Transition') + ->toContainAsFile('private readonly Model $model,') + ->toContainAsFile('return $this->model;'); + + unlink($file); +}); diff --git a/tests/Pest.php b/tests/Pest.php index 0a69b25..8f61220 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -16,6 +16,13 @@ |-------------------------------------------------------------------------- */ +expect()->extend('toContainAsFile', function ($needle) { + expect(file_get_contents($this->value)) + ->toContain($needle); + + return $this; +}); + /* |-------------------------------------------------------------------------- | Functions diff --git a/tests/TestCase.php b/tests/TestCase.php index 8447801..f2d37b2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,6 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Orchestra\Testbench\TestCase as Orchestra; +use Spatie\ModelStates\ModelStatesServiceProvider; abstract class TestCase extends Orchestra { @@ -14,6 +15,13 @@ protected function setUp(): void $this->setUpDatabase(); } + protected function getPackageProviders($app) + { + return [ + ModelStatesServiceProvider::class, + ]; + } + protected function getEnvironmentSetUp($app) { $app['config']->set('database.default', 'sqlite');