diff --git a/.DS_Store b/.DS_Store index 73ed4c2..5595c6c 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 0000000..9a4df37 Binary files /dev/null and b/.github/.DS_Store differ diff --git a/README.md b/README.md index cc3db80..a0a4ed1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ -A simple Laravel package that intercepts and help you customize, remove or modify the meta data on your Eloquent API Resource response. +A simple Laravel package that intercepts and help you customize, remove or modify the meta data on your Eloquent API Resource response, as well as automatically convert resource keys to camel case. ## Installation @@ -45,7 +45,7 @@ Run `php artisan vendor:publish --tag="resource-modifier"` ## Generating Resources -To generate a resource class, you may use the `mod:resource` Artisan command. By default, resources will be placed in the `app/Http/Resources` directory of your application. Resources extend the `Illuminate\Http\Resources\Json\JsonResource` class: +To generate a resource class, you may use the `mod:resource` Artisan command. By default, resources will be placed in the `app/Http/Resources` directory of your application. Resources extend the `ToneflixCode\ResourceModifier\Services\Json\JsonResource` class: ```bash artisan mod:resource UserResource @@ -80,7 +80,7 @@ class ResourceMakeCommand extends ToneflixCodeResourceMakeCommand } ``` -This will overide the default `ResourceMakeCommand` as Laravel will prefer user defined commands over built in ones, so the next time you call `php artisan make:resource UserCollection`, your collection will be created with the Laravel Resource Modifier signature. +This will overide the default `ResourceMakeCommand` as Laravel will prefer user defined commands over built in ones, so the next time you call `php artisan make:resource UserCollection`, your collection will be created with the Laravel Resource Modifier signature. ## Testing diff --git a/config/config.php b/config/config.php index 745b426..4b0f1e9 100644 --- a/config/config.php +++ b/config/config.php @@ -60,4 +60,15 @@ 'prev' => 'prev', 'next' => 'next', ], + + /* + |--------------------------------------------------------------------------------- + | Camel Casing + |--------------------------------------------------------------------------------- + | + | When enable, it will try to enforce camel casing for all resource keys + | + */ + + 'prefer_camel_casing' => true ]; diff --git a/src/Commands/stubs/resource.stub b/src/Commands/stubs/resource.stub index ce8ece4..ab107a2 100644 --- a/src/Commands/stubs/resource.stub +++ b/src/Commands/stubs/resource.stub @@ -3,7 +3,7 @@ namespace {{ namespace }}; use Illuminate\Http\Request; -use Illuminate\Http\Resources\Json\JsonResource; +use ToneflixCode\ResourceModifier\Services\Json\JsonResource; class {{ class }} extends JsonResource { diff --git a/src/Services/Json/JsonResource.php b/src/Services/Json/JsonResource.php new file mode 100644 index 0000000..3ee918e --- /dev/null +++ b/src/Services/Json/JsonResource.php @@ -0,0 +1,38 @@ +toArray( + $request ?: Container::getInstance()->make('request') + ); + + if ($data instanceof Arrayable) { + $data = $data->toArray(); + } elseif ($data instanceof JsonSerializable) { + $data = $data->jsonSerialize(); + } + + if (config('resource-modifier.prefer_camel_casing', false) === true) { + return collect($this->filter((array) $data)) + ->mapWithKeys(fn($value, $key) => [str($key)->camel()->toString() => $value]) + ->toArray(); + } + + return $this->filter((array) $data); + } +} diff --git a/tests/Feature/ResourceMakeCommandTest.php b/tests/Feature/ResourceMakeCommandTest.php index ada0c5e..2b772e2 100644 --- a/tests/Feature/ResourceMakeCommandTest.php +++ b/tests/Feature/ResourceMakeCommandTest.php @@ -1,8 +1,10 @@ toBe('App\Http\Resources\XyzCollection'); }); +test('can create modified resource', function () { + + $this->artisan('mod:resource XyzResource')->assertExitCode(0); + + expect(XyzResource::class)->toBe('App\Http\Resources\XyzResource'); +}); + test('can assure that modified resource collection is valid', function () { - $outputPath = realpath(__DIR__.'/../../vendor/orchestra/testbench-core/laravel/app/Http/Resources/XyzCollection.php'); + $outputPath = realpath(__DIR__ . '/../../vendor/orchestra/testbench-core/laravel/app/Http/Resources/XyzCollection.php'); if ($outputPath) { unlink($outputPath); } @@ -30,3 +39,23 @@ expect(stripos($content, ResourceCollection::class) >= 0)->toBeTrue(); }); + + +test('can assure that modified resource is valid', function () { + + $outputPath = realpath(__DIR__ . '/../../vendor/orchestra/testbench-core/laravel/app/Http/Resources/XyzResource.php'); + if ($outputPath) { + unlink($outputPath); + } + $this->artisan('mod:resource XyzResource')->assertExitCode(0); + + User::factory(10)->create(); + + $content = ''; + + if ($outputPath) { + $content = File::get($outputPath); + } + + expect(stripos($content, JsonResource::class) >= 0)->toBeTrue(); +}); diff --git a/tests/Feature/ResourceTest.php b/tests/Feature/ResourceTest.php new file mode 100644 index 0000000..ef4cd25 --- /dev/null +++ b/tests/Feature/ResourceTest.php @@ -0,0 +1,21 @@ +create(); + + Route::get('test/users', function () use ($user) { + return present(fn() => new UserResource($user)); + }); + + $response = $this->get('/test/users'); + + ! json_validate($response->content()) && $response->dump(); + + $response->assertCreated(); + expect($response->collect('data')->keys()[3])->toBeCamelCase(); +}); diff --git a/tests/app/Http/Resources/UserResource.php b/tests/app/Http/Resources/UserResource.php index e98e826..f0d8ac2 100644 --- a/tests/app/Http/Resources/UserResource.php +++ b/tests/app/Http/Resources/UserResource.php @@ -3,7 +3,7 @@ namespace ToneflixCode\ResourceModifier\Tests\App\Http\Resources; use Illuminate\Http\Request; -use Illuminate\Http\Resources\Json\JsonResource; +use ToneflixCode\ResourceModifier\Services\Json\JsonResource; class UserResource extends JsonResource { @@ -18,6 +18,7 @@ public function toArray(Request $request): array 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, + 'name_email' => $this->name . ' ' . $this->email, ]; } }