From 8dabc42e6489419321cfd5af77139ca38a2db1f2 Mon Sep 17 00:00:00 2001 From: Eduard Lupacescu Date: Wed, 20 May 2020 13:58:24 +0300 Subject: [PATCH 1/2] Hiddeen appendable fields --- src/Fields/Field.php | 76 ++++++++++++++++++- src/Fields/OrganicField.php | 21 +++++ .../RepositoryShowControllerTest.php | 35 +++++++++ .../Post/PostWithHiddenFieldRepository.php | 27 +++++++ tests/IntegrationTest.php | 2 + tests/Unit/FieldTest.php | 51 +++++++++++++ 6 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 tests/Fixtures/Post/PostWithHiddenFieldRepository.php diff --git a/src/Fields/Field.php b/src/Fields/Field.php index fa15d98c7..c201872c3 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -97,6 +97,13 @@ class Field extends OrganicField implements JsonSerializable */ protected $defaultCallback; + /** + * Closure be used for the field's default value when store/update. + * + * @var callable + */ + protected $appendCallback; + /** * Closure be used to be called after the field value stored. */ @@ -190,12 +197,22 @@ public function fillAttribute(RestifyRequest $request, $model) { $this->resolveValueBeforeUpdate($request, $model); - if (isset($this->fillCallback)) { + if ($this->isHidden($request)) { + if (!isset($this->appendCallback)) { + return; + } + } + + if (!$this->isHidden($request) && isset($this->fillCallback)) { return call_user_func( $this->fillCallback, $request, $model, $this->attribute ); } + if (isset($this->appendCallback)) { + return $this->fillAttributeFromAppend($request, $model, $this->attribute); + } + if ($request->isStoreRequest() && is_callable($this->storeCallback)) { return call_user_func( $this->storeCallback, $request, $model, $this->attribute @@ -227,6 +244,28 @@ protected function fillAttributeFromRequest(RestifyRequest $request, $model, $at } } + /** + * Fill the model with the default value. + * + * @param RestifyRequest $request + * @param $model + * @param $attribute + */ + protected function fillAttributeFromAppend(RestifyRequest $request, $model, $attribute) + { + if (!isset($this->appendCallback)) { + return; + } + + if (is_callable($this->appendCallback)) { + return $model->{$attribute} = call_user_func( + $this->appendCallback, $request, $model, $attribute + ); + } + + $model->{$attribute} = $this->appendCallback; + } + /** * @return callable|string|null */ @@ -317,7 +356,7 @@ public function resolveForShow($repository, $attribute = null) return; } - if (! $this->showCallback) { + if (!$this->showCallback) { $this->resolve($repository, $attribute); } elseif (is_callable($this->showCallback)) { tap($this->value ?? $this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { @@ -340,7 +379,7 @@ public function resolveForIndex($repository, $attribute = null) return; } - if (! $this->indexCallback) { + if (!$this->indexCallback) { $this->resolve($repository, $attribute); } elseif (is_callable($this->indexCallback)) { tap($this->value ?? $this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { @@ -360,7 +399,7 @@ public function resolve($repository, $attribute = null) return; } - if (! $this->resolveCallback) { + if (!$this->resolveCallback) { $this->value = $this->resolveAttribute($repository, $attribute); } elseif (is_callable($this->resolveCallback)) { tap($this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { @@ -477,4 +516,33 @@ public function invokeAfter(RestifyRequest $request, $repository) call_user_func($this->afterUpdateCallback, $this->resolveAttribute($repository, $this->attribute), $this->valueBeforeUpdate, $repository, $request); } } + + /** + * Indicate whatever the input is hidden or not. + * + * @param bool $callback + * @return $this + */ + public function hidden($callback = true) + { + $this->hideFromIndex($callback) + ->hideFromShow($callback); + + $this->hiddenCallback = $callback; + + return $this; + } + + /** + * Append values when store/update. + * + * @param callable|string $value + * @return $this + */ + public function append($value) + { + $this->appendCallback = $value; + + return $this; + } } diff --git a/src/Fields/OrganicField.php b/src/Fields/OrganicField.php index a6c03b3f9..e41cfedfe 100644 --- a/src/Fields/OrganicField.php +++ b/src/Fields/OrganicField.php @@ -16,6 +16,8 @@ abstract class OrganicField extends BaseField public $readonlyCallback; + public $hiddenCallback; + public array $rules = []; public array $storingRules = []; @@ -64,6 +66,10 @@ public function hideFromIndex($callback = true) public function isShownOnShow(RestifyRequest $request, $repository): bool { + if ($this->isHidden($request)) { + return false; + } + if (is_callable($this->showOnShow)) { $this->showOnShow = call_user_func($this->showOnShow, $request, $repository); } @@ -78,6 +84,10 @@ public function isHiddenOnShow(RestifyRequest $request, $repository): bool public function isShownOnIndex(RestifyRequest $request, $repository): bool { + if ($this->isHidden($request)) { + return false; + } + return false === $this->isHiddenOnIndex($request, $repository); } @@ -158,4 +168,15 @@ public function isShownOnStore(RestifyRequest $request, $repository): bool { return ! $this->isReadonly($request); } + + public function isHidden(RestifyRequest $request) + { + return with($this->hiddenCallback, function ($callback) use ($request) { + if ($callback === true || (is_callable($callback) && call_user_func($callback, $request))) { + return true; + } + + return false; + }); + } } diff --git a/tests/Controllers/RepositoryShowControllerTest.php b/tests/Controllers/RepositoryShowControllerTest.php index 84ad5b51a..103287fb9 100644 --- a/tests/Controllers/RepositoryShowControllerTest.php +++ b/tests/Controllers/RepositoryShowControllerTest.php @@ -95,4 +95,39 @@ public function test_show_mergeable_repository_containes_model_attributes_and_lo ], ]); } + + public function test_repository_hidden_fields_are_not_visible() + { + factory(Post::class)->create(['title' => 'Eduard']); + + $response = $this->getJson('/restify-api/post-with-hidden-fields/1'); + + $this->assertArrayNotHasKey('user_id', $response->json('data.attributes')); + } + + public function test_repository_hidden_fields_could_not_be_updated() + { + $post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard']); + + $oldUserId = $post->user_id; + + $this->putJson('/restify-api/post-with-hidden-fields/1', [ + 'title' => 'Updated title', + 'user_id' => 1, + ]); + + $this->assertEquals($oldUserId, Post::find($post->id)->user_id); + } + + public function test_repository_hidden_fields_could_be_updated_through_append() + { + $post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard', 'category' => 'Hidden category before update.',]); + + $this->putJson('/restify-api/post-with-hidden-fields/1', [ + 'title' => 'Updated title', + 'category' => 'Trying to update hidden category.' + ]); + + $this->assertEquals('Append category for a hidden field.', $post->fresh()->category); + } } diff --git a/tests/Fixtures/Post/PostWithHiddenFieldRepository.php b/tests/Fixtures/Post/PostWithHiddenFieldRepository.php new file mode 100644 index 000000000..482ccf69e --- /dev/null +++ b/tests/Fixtures/Post/PostWithHiddenFieldRepository.php @@ -0,0 +1,27 @@ +hidden(), + + Field::new('category')->hidden()->append('Append category for a hidden field.'), + + Field::new('title'), + ]; + } +} diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index 6c083d20e..17c1c7213 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -11,6 +11,7 @@ use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostMergeableRepository; use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostRepository; use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostUnauthorizedFieldRepository; +use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostWithHiddenFieldRepository; use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostWithUnauthorizedFieldsRepository; use Binaryk\LaravelRestify\Tests\Fixtures\User\User; use Binaryk\LaravelRestify\Tests\Fixtures\User\UserRepository; @@ -184,6 +185,7 @@ public function loadRepositories() PostAuthorizeRepository::class, PostWithUnauthorizedFieldsRepository::class, PostUnauthorizedFieldRepository::class, + PostWithHiddenFieldRepository::class, ]); } diff --git a/tests/Unit/FieldTest.php b/tests/Unit/FieldTest.php index d4cdda291..ec7a0ae9c 100644 --- a/tests/Unit/FieldTest.php +++ b/tests/Unit/FieldTest.php @@ -3,6 +3,7 @@ namespace Binaryk\LaravelRestify\Tests\Unit; use Binaryk\LaravelRestify\Fields\Field; +use Binaryk\LaravelRestify\Http\Requests\RepositoryIndexRequest; use Binaryk\LaravelRestify\Http\Requests\RepositoryStoreRequest; use Binaryk\LaravelRestify\Http\Requests\RepositoryUpdateRequest; use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostRepository; @@ -126,6 +127,9 @@ public function test_field_fill_callback_has_high_priority() /** * @var Field $field */ $field = Field::new('title') + ->append(function () { + return 'from append callback'; + }) ->fillCallback(function ($request, $model) { $model->title = 'from fill callback'; }) @@ -248,5 +252,52 @@ public function test_field_can_have_custom_label() $field->resolveForIndex((object) ['name' => 'Binaryk'], 'name'); $this->assertEquals('custom_label', $field->label); + $this->assertEquals('custom_label', $field->jsonSerialize()['attribute']); + } + + public function test_field_can_be_filled_from_the_append_value() + { + $request = new RepositoryStoreRequest([], []); + + $request->merge([ + 'title' => 'Title from the request.', + ]); + + $model = new class extends Model { + protected $table = 'posts'; + protected $fillable = ['title']; + }; + + /** * @var Field $field */ + $field = Field::new('title')->append('Append title'); + + $field->fillAttribute($request, $model); + + $model->save(); + + $this->assertEquals($model->title, 'Append title'); + } + + public function test_field_can_be_filled_from_the_append_callback() + { + $request = new RepositoryStoreRequest([], []); + + $request->merge([ + 'title' => 'Title from the request.', + ]); + + $model = new class extends Model { + protected $table = 'posts'; + protected $fillable = ['title']; + }; + + /** * @var Field $field */ + $field = Field::new('title')->append(fn() => 'Append title'); + + $field->fillAttribute($request, $model); + + $model->save(); + + $this->assertEquals($model->title, 'Append title'); } } From 6cdf38b31218426ff0d54962ecdb49a0167d1715 Mon Sep 17 00:00:00 2001 From: Lupacescu Eduard Date: Wed, 20 May 2020 13:58:49 +0300 Subject: [PATCH 2/2] Apply fixes from StyleCI (#186) --- src/Fields/Field.php | 12 ++++++------ tests/Controllers/RepositoryShowControllerTest.php | 4 ++-- tests/Unit/FieldTest.php | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Fields/Field.php b/src/Fields/Field.php index c201872c3..dcc5ad0e9 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -198,12 +198,12 @@ public function fillAttribute(RestifyRequest $request, $model) $this->resolveValueBeforeUpdate($request, $model); if ($this->isHidden($request)) { - if (!isset($this->appendCallback)) { + if (! isset($this->appendCallback)) { return; } } - if (!$this->isHidden($request) && isset($this->fillCallback)) { + if (! $this->isHidden($request) && isset($this->fillCallback)) { return call_user_func( $this->fillCallback, $request, $model, $this->attribute ); @@ -253,7 +253,7 @@ protected function fillAttributeFromRequest(RestifyRequest $request, $model, $at */ protected function fillAttributeFromAppend(RestifyRequest $request, $model, $attribute) { - if (!isset($this->appendCallback)) { + if (! isset($this->appendCallback)) { return; } @@ -356,7 +356,7 @@ public function resolveForShow($repository, $attribute = null) return; } - if (!$this->showCallback) { + if (! $this->showCallback) { $this->resolve($repository, $attribute); } elseif (is_callable($this->showCallback)) { tap($this->value ?? $this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { @@ -379,7 +379,7 @@ public function resolveForIndex($repository, $attribute = null) return; } - if (!$this->indexCallback) { + if (! $this->indexCallback) { $this->resolve($repository, $attribute); } elseif (is_callable($this->indexCallback)) { tap($this->value ?? $this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { @@ -399,7 +399,7 @@ public function resolve($repository, $attribute = null) return; } - if (!$this->resolveCallback) { + if (! $this->resolveCallback) { $this->value = $this->resolveAttribute($repository, $attribute); } elseif (is_callable($this->resolveCallback)) { tap($this->resolveAttribute($repository, $attribute), function ($value) use ($repository, $attribute) { diff --git a/tests/Controllers/RepositoryShowControllerTest.php b/tests/Controllers/RepositoryShowControllerTest.php index 103287fb9..2d63b1a85 100644 --- a/tests/Controllers/RepositoryShowControllerTest.php +++ b/tests/Controllers/RepositoryShowControllerTest.php @@ -121,11 +121,11 @@ public function test_repository_hidden_fields_could_not_be_updated() public function test_repository_hidden_fields_could_be_updated_through_append() { - $post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard', 'category' => 'Hidden category before update.',]); + $post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard', 'category' => 'Hidden category before update.']); $this->putJson('/restify-api/post-with-hidden-fields/1', [ 'title' => 'Updated title', - 'category' => 'Trying to update hidden category.' + 'category' => 'Trying to update hidden category.', ]); $this->assertEquals('Append category for a hidden field.', $post->fresh()->category); diff --git a/tests/Unit/FieldTest.php b/tests/Unit/FieldTest.php index ec7a0ae9c..f38703018 100644 --- a/tests/Unit/FieldTest.php +++ b/tests/Unit/FieldTest.php @@ -3,7 +3,6 @@ namespace Binaryk\LaravelRestify\Tests\Unit; use Binaryk\LaravelRestify\Fields\Field; -use Binaryk\LaravelRestify\Http\Requests\RepositoryIndexRequest; use Binaryk\LaravelRestify\Http\Requests\RepositoryStoreRequest; use Binaryk\LaravelRestify\Http\Requests\RepositoryUpdateRequest; use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostRepository; @@ -292,7 +291,7 @@ public function test_field_can_be_filled_from_the_append_callback() }; /** * @var Field $field */ - $field = Field::new('title')->append(fn() => 'Append title'); + $field = Field::new('title')->append(fn () => 'Append title'); $field->fillAttribute($request, $model);