Skip to content

Commit 0491ae4

Browse files
authored
Hidden and appendable fields (#187)
* Hiddeen appendable fields * Apply fixes from StyleCI (#186)
1 parent 084ca88 commit 0491ae4

File tree

6 files changed

+204
-1
lines changed

6 files changed

+204
-1
lines changed

src/Fields/Field.php

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ class Field extends OrganicField implements JsonSerializable
9797
*/
9898
protected $defaultCallback;
9999

100+
/**
101+
* Closure be used for the field's default value when store/update.
102+
*
103+
* @var callable
104+
*/
105+
protected $appendCallback;
106+
100107
/**
101108
* Closure be used to be called after the field value stored.
102109
*/
@@ -190,12 +197,22 @@ public function fillAttribute(RestifyRequest $request, $model)
190197
{
191198
$this->resolveValueBeforeUpdate($request, $model);
192199

193-
if (isset($this->fillCallback)) {
200+
if ($this->isHidden($request)) {
201+
if (! isset($this->appendCallback)) {
202+
return;
203+
}
204+
}
205+
206+
if (! $this->isHidden($request) && isset($this->fillCallback)) {
194207
return call_user_func(
195208
$this->fillCallback, $request, $model, $this->attribute
196209
);
197210
}
198211

212+
if (isset($this->appendCallback)) {
213+
return $this->fillAttributeFromAppend($request, $model, $this->attribute);
214+
}
215+
199216
if ($request->isStoreRequest() && is_callable($this->storeCallback)) {
200217
return call_user_func(
201218
$this->storeCallback, $request, $model, $this->attribute
@@ -227,6 +244,28 @@ protected function fillAttributeFromRequest(RestifyRequest $request, $model, $at
227244
}
228245
}
229246

247+
/**
248+
* Fill the model with the default value.
249+
*
250+
* @param RestifyRequest $request
251+
* @param $model
252+
* @param $attribute
253+
*/
254+
protected function fillAttributeFromAppend(RestifyRequest $request, $model, $attribute)
255+
{
256+
if (! isset($this->appendCallback)) {
257+
return;
258+
}
259+
260+
if (is_callable($this->appendCallback)) {
261+
return $model->{$attribute} = call_user_func(
262+
$this->appendCallback, $request, $model, $attribute
263+
);
264+
}
265+
266+
$model->{$attribute} = $this->appendCallback;
267+
}
268+
230269
/**
231270
* @return callable|string|null
232271
*/
@@ -477,4 +516,33 @@ public function invokeAfter(RestifyRequest $request, $repository)
477516
call_user_func($this->afterUpdateCallback, $this->resolveAttribute($repository, $this->attribute), $this->valueBeforeUpdate, $repository, $request);
478517
}
479518
}
519+
520+
/**
521+
* Indicate whatever the input is hidden or not.
522+
*
523+
* @param bool $callback
524+
* @return $this
525+
*/
526+
public function hidden($callback = true)
527+
{
528+
$this->hideFromIndex($callback)
529+
->hideFromShow($callback);
530+
531+
$this->hiddenCallback = $callback;
532+
533+
return $this;
534+
}
535+
536+
/**
537+
* Append values when store/update.
538+
*
539+
* @param callable|string $value
540+
* @return $this
541+
*/
542+
public function append($value)
543+
{
544+
$this->appendCallback = $value;
545+
546+
return $this;
547+
}
480548
}

src/Fields/OrganicField.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ abstract class OrganicField extends BaseField
1616

1717
public $readonlyCallback;
1818

19+
public $hiddenCallback;
20+
1921
public array $rules = [];
2022

2123
public array $storingRules = [];
@@ -64,6 +66,10 @@ public function hideFromIndex($callback = true)
6466

6567
public function isShownOnShow(RestifyRequest $request, $repository): bool
6668
{
69+
if ($this->isHidden($request)) {
70+
return false;
71+
}
72+
6773
if (is_callable($this->showOnShow)) {
6874
$this->showOnShow = call_user_func($this->showOnShow, $request, $repository);
6975
}
@@ -78,6 +84,10 @@ public function isHiddenOnShow(RestifyRequest $request, $repository): bool
7884

7985
public function isShownOnIndex(RestifyRequest $request, $repository): bool
8086
{
87+
if ($this->isHidden($request)) {
88+
return false;
89+
}
90+
8191
return false === $this->isHiddenOnIndex($request, $repository);
8292
}
8393

@@ -158,4 +168,15 @@ public function isShownOnStore(RestifyRequest $request, $repository): bool
158168
{
159169
return ! $this->isReadonly($request);
160170
}
171+
172+
public function isHidden(RestifyRequest $request)
173+
{
174+
return with($this->hiddenCallback, function ($callback) use ($request) {
175+
if ($callback === true || (is_callable($callback) && call_user_func($callback, $request))) {
176+
return true;
177+
}
178+
179+
return false;
180+
});
181+
}
161182
}

tests/Controllers/RepositoryShowControllerTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,39 @@ public function test_show_mergeable_repository_containes_model_attributes_and_lo
9595
],
9696
]);
9797
}
98+
99+
public function test_repository_hidden_fields_are_not_visible()
100+
{
101+
factory(Post::class)->create(['title' => 'Eduard']);
102+
103+
$response = $this->getJson('/restify-api/post-with-hidden-fields/1');
104+
105+
$this->assertArrayNotHasKey('user_id', $response->json('data.attributes'));
106+
}
107+
108+
public function test_repository_hidden_fields_could_not_be_updated()
109+
{
110+
$post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard']);
111+
112+
$oldUserId = $post->user_id;
113+
114+
$this->putJson('/restify-api/post-with-hidden-fields/1', [
115+
'title' => 'Updated title',
116+
'user_id' => 1,
117+
]);
118+
119+
$this->assertEquals($oldUserId, Post::find($post->id)->user_id);
120+
}
121+
122+
public function test_repository_hidden_fields_could_be_updated_through_append()
123+
{
124+
$post = factory(Post::class)->create(['user_id' => 2, 'title' => 'Eduard', 'category' => 'Hidden category before update.']);
125+
126+
$this->putJson('/restify-api/post-with-hidden-fields/1', [
127+
'title' => 'Updated title',
128+
'category' => 'Trying to update hidden category.',
129+
]);
130+
131+
$this->assertEquals('Append category for a hidden field.', $post->fresh()->category);
132+
}
98133
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Tests\Fixtures\Post;
4+
5+
use Binaryk\LaravelRestify\Fields\Field;
6+
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
7+
use Binaryk\LaravelRestify\Repositories\Repository;
8+
9+
class PostWithHiddenFieldRepository extends Repository
10+
{
11+
public static $model = Post::class;
12+
13+
public static $uriKey = 'post-with-hidden-fields';
14+
15+
public static $globallySearchable = false;
16+
17+
public function fields(RestifyRequest $request)
18+
{
19+
return [
20+
Field::new('user_id')->hidden(),
21+
22+
Field::new('category')->hidden()->append('Append category for a hidden field.'),
23+
24+
Field::new('title'),
25+
];
26+
}
27+
}

tests/IntegrationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostMergeableRepository;
1212
use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostRepository;
1313
use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostUnauthorizedFieldRepository;
14+
use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostWithHiddenFieldRepository;
1415
use Binaryk\LaravelRestify\Tests\Fixtures\Post\PostWithUnauthorizedFieldsRepository;
1516
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
1617
use Binaryk\LaravelRestify\Tests\Fixtures\User\UserRepository;
@@ -184,6 +185,7 @@ public function loadRepositories()
184185
PostAuthorizeRepository::class,
185186
PostWithUnauthorizedFieldsRepository::class,
186187
PostUnauthorizedFieldRepository::class,
188+
PostWithHiddenFieldRepository::class,
187189
]);
188190
}
189191

tests/Unit/FieldTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ public function test_field_fill_callback_has_high_priority()
126126

127127
/** * @var Field $field */
128128
$field = Field::new('title')
129+
->append(function () {
130+
return 'from append callback';
131+
})
129132
->fillCallback(function ($request, $model) {
130133
$model->title = 'from fill callback';
131134
})
@@ -248,5 +251,52 @@ public function test_field_can_have_custom_label()
248251
$field->resolveForIndex((object) ['name' => 'Binaryk'], 'name');
249252

250253
$this->assertEquals('custom_label', $field->label);
254+
$this->assertEquals('custom_label', $field->jsonSerialize()['attribute']);
255+
}
256+
257+
public function test_field_can_be_filled_from_the_append_value()
258+
{
259+
$request = new RepositoryStoreRequest([], []);
260+
261+
$request->merge([
262+
'title' => 'Title from the request.',
263+
]);
264+
265+
$model = new class extends Model {
266+
protected $table = 'posts';
267+
protected $fillable = ['title'];
268+
};
269+
270+
/** * @var Field $field */
271+
$field = Field::new('title')->append('Append title');
272+
273+
$field->fillAttribute($request, $model);
274+
275+
$model->save();
276+
277+
$this->assertEquals($model->title, 'Append title');
278+
}
279+
280+
public function test_field_can_be_filled_from_the_append_callback()
281+
{
282+
$request = new RepositoryStoreRequest([], []);
283+
284+
$request->merge([
285+
'title' => 'Title from the request.',
286+
]);
287+
288+
$model = new class extends Model {
289+
protected $table = 'posts';
290+
protected $fillable = ['title'];
291+
};
292+
293+
/** * @var Field $field */
294+
$field = Field::new('title')->append(fn () => 'Append title');
295+
296+
$field->fillAttribute($request, $model);
297+
298+
$model->save();
299+
300+
$this->assertEquals($model->title, 'Append title');
251301
}
252302
}

0 commit comments

Comments
 (0)