diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ba7c5..168869a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. This projec ## Unreleased +## [3.3.0] - 2024-03-03 + +### Added + +- [#272](https://github.com/laravel-json-api/laravel/pull/272) Added a model property type-hint to the resource stub and + allowed it to be replaced via a model option on the command. + ## [3.2.0] - 2024-02-14 ### Added diff --git a/src/Console/Concerns/ReplacesModel.php b/src/Console/Concerns/ReplacesModel.php new file mode 100644 index 0000000..753fc86 --- /dev/null +++ b/src/Console/Concerns/ReplacesModel.php @@ -0,0 +1,58 @@ +qualifyModel($model); + } + + $model = class_basename($model); + + $replace = [ + '{{ namespacedModel }}' => $namespacedModel, + '{{namespacedModel}}' => $namespacedModel, + '{{ model }}' => $model, + '{{model}}' => $model, + ]; + + return str_replace( + array_keys($replace), array_values($replace), $stub + ); + } +} diff --git a/src/Console/MakeResource.php b/src/Console/MakeResource.php index efb53cc..7c1d996 100644 --- a/src/Console/MakeResource.php +++ b/src/Console/MakeResource.php @@ -19,10 +19,12 @@ namespace LaravelJsonApi\Laravel\Console; +use LaravelJsonApi\Laravel\Console\Concerns\ReplacesModel; use Symfony\Component\Console\Input\InputOption; class MakeResource extends GeneratorCommand { + use ReplacesModel; /** * @var string @@ -52,6 +54,18 @@ protected function getStub() return $this->resolveStubPath('resource.stub'); } + /** + * @inheritDoc + */ + protected function buildClass($name) + { + $stub = parent::buildClass($name); + + $model = $this->option('model') ?: $this->guessModel(); + + return $this->replaceModel($stub, $model); + } + /** * @inheritDoc */ @@ -59,8 +73,8 @@ protected function getOptions() { return [ ['force', null, InputOption::VALUE_NONE, 'Create the class even if the resource already exists'], + ['model', 'm', InputOption::VALUE_REQUIRED, 'The model that the resource applies to.'], ['server', 's', InputOption::VALUE_REQUIRED, 'The JSON:API server the resource exists in.'], ]; } - } diff --git a/src/Console/MakeSchema.php b/src/Console/MakeSchema.php index d371e8b..79b83a4 100644 --- a/src/Console/MakeSchema.php +++ b/src/Console/MakeSchema.php @@ -19,7 +19,7 @@ namespace LaravelJsonApi\Laravel\Console; -use Illuminate\Support\Str; +use LaravelJsonApi\Laravel\Console\Concerns\ReplacesModel; use Symfony\Component\Console\Input\InputOption; use function array_keys; use function array_values; @@ -27,6 +27,7 @@ class MakeSchema extends GeneratorCommand { + use ReplacesModel; /** * @var string @@ -47,7 +48,7 @@ class MakeSchema extends GeneratorCommand * @var string */ protected $classType = 'Schema'; - + /** * @inheritDoc */ @@ -65,7 +66,7 @@ protected function getStub() */ protected function buildClass($name) { - $stub = parent::buildClass($name); + $stub = $this->replaceSchema(parent::buildClass($name)); $model = $this->option('model') ?: $this->guessModel(); @@ -77,24 +78,11 @@ protected function buildClass($name) * @param string $model * @return string */ - protected function replaceModel(string $stub, string $model): string + protected function replaceSchema(string $stub): string { - $model = str_replace('/', '\\', $model); - - if (Str::startsWith($model, '\\')) { - $namespacedModel = trim($model, '\\'); - } else { - $namespacedModel = $this->qualifyModel($model); - } - - $model = class_basename($model); $schema = $this->option('proxy') ? 'ProxySchema' : 'Schema'; $replace = [ - '{{ namespacedModel }}' => $namespacedModel, - '{{namespacedModel}}' => $namespacedModel, - '{{ model }}' => $model, - '{{model}}' => $model, '{{ schema }}' => $schema, '{{schema}}' => $schema, ]; @@ -117,5 +105,4 @@ protected function getOptions() ['server', 's', InputOption::VALUE_REQUIRED, 'The JSON:API server the schema exists in.'], ]; } - } diff --git a/stubs/resource.stub b/stubs/resource.stub index 0263f81..b8ab023 100644 --- a/stubs/resource.stub +++ b/stubs/resource.stub @@ -2,9 +2,13 @@ namespace {{ namespace }}; +use {{ namespacedModel }}; use Illuminate\Http\Request; use LaravelJsonApi\Core\Resources\JsonApiResource; +/** + * @property {{ model }} $resource + */ class {{ class }} extends JsonApiResource { @@ -17,8 +21,8 @@ class {{ class }} extends JsonApiResource public function attributes($request): iterable { return [ - 'createdAt' => $this->created_at, - 'updatedAt' => $this->updated_at, + 'createdAt' => $this->resource->created_at, + 'updatedAt' => $this->resource->updated_at, ]; } diff --git a/tests/lib/Integration/Console/MakeResourceTest.php b/tests/lib/Integration/Console/MakeResourceTest.php index 6cd48e0..0abc975 100644 --- a/tests/lib/Integration/Console/MakeResourceTest.php +++ b/tests/lib/Integration/Console/MakeResourceTest.php @@ -25,7 +25,6 @@ class MakeResourceTest extends TestCase { - /** * @return void */ @@ -60,6 +59,33 @@ public function test(): void $this->assertResourceCreated(); } + public function testModelWithoutNamespace(): void + { + config()->set('jsonapi.servers', [ + 'v1' => Server::class, + ]); + + $result = $this->artisan('jsonapi:resource posts --model BlogPost'); + + $this->assertSame(0, $result); + $this->assertResourceCreated('App\Models\BlogPost', 'BlogPost'); + } + + public function testModelWithNamespace(): void + { + config()->set('jsonapi.servers', [ + 'v1' => Server::class, + ]); + + $result = $this->artisan('jsonapi:resource', [ + 'name' => 'posts', + '--model' => '\App\Foo\Bar\BlogPost', + ]); + + $this->assertSame(0, $result); + $this->assertResourceCreated('App\Foo\Bar\BlogPost', 'BlogPost'); + } + public function testServer(): void { config()->set('jsonapi.servers', [ @@ -104,9 +130,14 @@ public function testInvalidServer(): void } /** + * @param string $namespacedModel + * @param string $model * @return void */ - private function assertResourceCreated(): void + private function assertResourceCreated( + string $namespacedModel = 'App\Models\Post', + string $model = 'Post' + ): void { $this->assertFileExists($path = app_path('JsonApi/V1/Posts/PostResource.php')); $content = file_get_contents($path); @@ -115,6 +146,8 @@ private function assertResourceCreated(): void 'namespace App\JsonApi\V1\Posts;', 'use LaravelJsonApi\Core\Resources\JsonApiResource;', 'class PostResource extends JsonApiResource', + "use {$namespacedModel};", + "@property {$model} \$resource", ]; foreach ($tests as $expected) {