Skip to content

Commit ec25bd8

Browse files
committed
✨ test custom rules
1 parent 76dda4b commit ec25bd8

File tree

9 files changed

+196
-20
lines changed

9 files changed

+196
-20
lines changed

src/Concerns/Relations/HasPivotFields.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
trait HasPivotFields
66
{
77
protected array $pivotFields = [];
8+
protected array $pivotRules = [];
89

910
public function getPivotFields() {
1011
return $this->pivotFields;
@@ -15,4 +16,18 @@ public function withPivotFields(array $pivotFields) {
1516
$this->pivotFields = $pivotFields;
1617
});
1718
}
19+
20+
public function withPivotRules(array $pivotRules) {
21+
return tap($this, function () use ($pivotRules) {
22+
$this->pivotRules = $pivotRules;
23+
});
24+
}
25+
26+
/**
27+
* @return array
28+
*/
29+
public function getPivotRules(): array
30+
{
31+
return $this->pivotRules;
32+
}
1833
}

src/Concerns/Resource/Rulable.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
trait Rulable
1111
{
12+
public function rules(RestRequest $request) {
13+
return [];
14+
}
15+
1216
public function createRules(RestRequest $request) {
1317
return [];
1418
}

src/Relations/Relation.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Closure;
66
use Illuminate\Database\Eloquent\Builder;
77
use Illuminate\Support\Str;
8+
use Lomkit\Rest\Concerns\Relations\HasPivotFields;
89
use Lomkit\Rest\Contracts\RelationResource;
910
use Lomkit\Rest\Http\Requests\RestRequest;
1011
use Lomkit\Rest\Concerns\Makeable;
@@ -74,6 +75,19 @@ public function rules(Resource $resource, string $prefix) {
7475
$rules[$prefix] = RequiredRelation::make()->resource($resource);
7576
}
7677

78+
if (in_array(HasPivotFields::class, class_uses_recursive($this), true)) {
79+
80+
$pivotPrefix = $prefix;
81+
if ($this->hasMultipleEntries()) {
82+
$pivotPrefix .= '.*';
83+
}
84+
$pivotPrefix.= '.pivot.';
85+
// @TODO pivot fields here :) + doc
86+
foreach ($this->getPivotRules() as $pivotKey => $pivotRule) {
87+
$rules[$pivotPrefix.$pivotKey] = $pivotRule;
88+
}
89+
}
90+
7791
return $rules;
7892
}
7993
}

src/Rules/CustomRulable.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,23 @@ public function passes($attribute, $value)
8080
*/
8181
protected function buildValidationRules($attribute, $value)
8282
{
83-
$rules = [];
84-
8583
if ($value['operation'] === 'create') {
8684
$rules = $this->resource->createRules(
8785
app()->make(RestRequest::class)
8886
);
89-
} elseif ($value['operation'] === 'update') {
87+
} else {
9088
$rules = $this->resource->updateRules(
9189
app()->make(RestRequest::class)
9290
);
9391
}
9492

93+
$rules = array_merge_recursive(
94+
$rules,
95+
$this->resource->rules(
96+
app()->make(RestRequest::class)
97+
)
98+
);
99+
95100
return collect($rules)
96101
->mapWithKeys(function ($item, $key) use ($attribute) {
97102
return [$attribute.'.attributes.'.$key => $item];

tests/Feature/Controllers/MutateCreateOperationsTest.php

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,65 @@ public function test_creating_a_resource_using_not_authorized_field(): void
4343
$response->assertJsonStructure(['message', 'errors' => ['mutate.0.attributes']]);
4444
}
4545

46+
public function test_creating_a_resource_using_field_not_following_custom_rules(): void
47+
{
48+
Gate::policy(Model::class, GreenPolicy::class);
49+
50+
$response = $this->post(
51+
'/api/models/mutate',
52+
[
53+
'mutate' => [
54+
[
55+
'operation' => 'create',
56+
'attributes' => ['string' => true]
57+
],
58+
],
59+
],
60+
['Accept' => 'application/json']
61+
);
62+
63+
$response->assertStatus(422);
64+
$response->assertJsonStructure(['message', 'errors' => ['mutate.0']]);
65+
}
66+
67+
public function test_creating_a_resource_using_pivot_field_not_following_custom_pivot_rules(): void
68+
{
69+
$modelToCreate = ModelFactory::new()->makeOne();
70+
71+
Gate::policy(Model::class, GreenPolicy::class);
72+
Gate::policy(BelongsToManyRelation::class, GreenPolicy::class);
73+
74+
$response = $this->post(
75+
'/api/models/mutate',
76+
[
77+
'mutate' => [
78+
[
79+
'operation' => 'create',
80+
'attributes' => [
81+
'name' => $modelToCreate->name,
82+
'number' => $modelToCreate->number
83+
],
84+
'relations' => [
85+
'belongsToManyRelation' => [
86+
[
87+
'operation' => 'create',
88+
'attributes' => [],
89+
'pivot' => [
90+
'number' => true
91+
]
92+
]
93+
]
94+
]
95+
],
96+
],
97+
],
98+
['Accept' => 'application/json']
99+
);
100+
101+
$response->assertStatus(422);
102+
$response->assertJsonStructure(['message', 'errors' => ['mutate.0.relations.belongsToManyRelation.0.pivot.number']]);
103+
}
104+
46105
public function test_creating_a_resource(): void
47106
{
48107
$modelToCreate = ModelFactory::new()->makeOne();
@@ -1079,7 +1138,6 @@ public function test_creating_a_resource_with_updating_belongs_to_many_relation_
10791138
[$modelToCreate],
10801139
);
10811140

1082-
10831141
// Here we test that the number has been modified on the relation
10841142
$this->assertEquals(
10851143
$belongsToManyRelationToUpdate1->fresh()->number,

tests/Feature/Controllers/MutateUpdateMorphOperationsTest.php

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,30 @@
3030

3131
class MutateUpdateMorphOperationsTest extends TestCase
3232
{
33+
public function test_updating_a_resource_using_field_not_following_custom_rules(): void
34+
{
35+
$modelToUpdate = ModelFactory::new()->createOne();
36+
37+
Gate::policy(Model::class, GreenPolicy::class);
38+
39+
$response = $this->post(
40+
'/api/models/mutate',
41+
[
42+
'mutate' => [
43+
[
44+
'operation' => 'update',
45+
'key' => $modelToUpdate->getKey(),
46+
'attributes' => ['string' => true]
47+
],
48+
],
49+
],
50+
['Accept' => 'application/json']
51+
);
52+
53+
$response->assertStatus(422);
54+
$response->assertJsonStructure(['message', 'errors' => ['mutate.0']]);
55+
}
56+
3357
public function test_updating_a_resource_with_creating_morph_to_relation(): void
3458
{
3559
$modelToUpdate = ModelFactory::new()->createOne();
@@ -1045,9 +1069,9 @@ public function test_updating_a_resource_with_creating_morphed_by_many_relation(
10451069
);
10461070
}
10471071

1048-
public function test_creating_a_resource_with_creating_morphed_by_many_relation_with_unauthorized_pivot_fields(): void
1072+
public function test_updating_a_resource_with_creating_morphed_by_many_relation_with_unauthorized_pivot_fields(): void
10491073
{
1050-
$modelToCreate = ModelFactory::new()->makeOne();
1074+
$modelToUpdate = ModelFactory::new()->createOne();
10511075

10521076
Gate::policy(Model::class, GreenPolicy::class);
10531077
Gate::policy(MorphedByManyRelation::class, GreenPolicy::class);
@@ -1057,10 +1081,11 @@ public function test_creating_a_resource_with_creating_morphed_by_many_relation_
10571081
[
10581082
'mutate' => [
10591083
[
1060-
'operation' => 'create',
1084+
'operation' => 'update',
1085+
'key' => $modelToUpdate->getKey(),
10611086
'attributes' => [
1062-
'name' => $modelToCreate->name,
1063-
'number' => $modelToCreate->number
1087+
'name' => 'new name',
1088+
'number' => 5001
10641089
],
10651090
'relations' => [
10661091
'morphedByManyRelation' => [
@@ -1083,9 +1108,9 @@ public function test_creating_a_resource_with_creating_morphed_by_many_relation_
10831108
$response->assertJsonStructure(['message', 'errors' => ['mutate.0.relations.morphedByManyRelation.0.pivot']]);
10841109
}
10851110

1086-
public function test_creating_a_resource_with_creating_morphed_by_many_relation_with_pivot_fields(): void
1111+
public function test_updating_a_resource_with_creating_morphed_by_many_relation_with_pivot_fields(): void
10871112
{
1088-
$modelToCreate = ModelFactory::new()->makeOne();
1113+
$modelToUpdate = ModelFactory::new()->createOne();
10891114

10901115
Gate::policy(Model::class, GreenPolicy::class);
10911116
Gate::policy(MorphedByManyRelation::class, GreenPolicy::class);
@@ -1095,10 +1120,11 @@ public function test_creating_a_resource_with_creating_morphed_by_many_relation_
10951120
[
10961121
'mutate' => [
10971122
[
1098-
'operation' => 'create',
1123+
'operation' => 'update',
1124+
'key' => $modelToUpdate->getKey(),
10991125
'attributes' => [
1100-
'name' => $modelToCreate->name,
1101-
'number' => $modelToCreate->number
1126+
'name' => 'new name',
1127+
'number' => 5001
11021128
],
11031129
'relations' => [
11041130
'morphedByManyRelation' => [
@@ -1126,18 +1152,19 @@ public function test_creating_a_resource_with_creating_morphed_by_many_relation_
11261152

11271153
$this->assertMutatedResponse(
11281154
$response,
1129-
[$modelToCreate],
1155+
[],
1156+
[$modelToUpdate]
11301157
);
11311158

11321159
// Here we test that the relation is correctly linked
11331160
$this->assertEquals(
1134-
Model::find($response->json('created.0'))->morphedByManyRelation()->count(), 2
1161+
Model::find($response->json('updated.0'))->morphedByManyRelation()->count(), 2
11351162
);
11361163
$this->assertEquals(
1137-
Model::find($response->json('created.0'))->morphedByManyRelation[0]->morphed_by_many_pivot->number, 20
1164+
Model::find($response->json('updated.0'))->morphedByManyRelation[0]->morphed_by_many_pivot->number, 20
11381165
);
11391166
$this->assertEquals(
1140-
Model::find($response->json('created.0'))->morphedByManyRelation[1]->morphed_by_many_pivot->number, 30
1167+
Model::find($response->json('updated.0'))->morphedByManyRelation[1]->morphed_by_many_pivot->number, 30
11411168
);
11421169
}
11431170

tests/Feature/Controllers/MutateUpdateOperationsTest.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,41 @@ public function test_updating_a_resource_using_not_authorized_field(): void
4242
$response->assertJsonStructure(['message', 'errors' => ['mutate.0.attributes']]);
4343
}
4444

45+
public function test_updating_a_resource_using_pivot_field_not_following_custom_pivot_rules(): void
46+
{
47+
$modelToUpdate = ModelFactory::new()->createOne();
48+
49+
Gate::policy(Model::class, GreenPolicy::class);
50+
Gate::policy(BelongsToManyRelation::class, GreenPolicy::class);
51+
52+
$response = $this->post(
53+
'/api/models/mutate',
54+
[
55+
'mutate' => [
56+
[
57+
'operation' => 'update',
58+
'key' => $modelToUpdate->getKey(),
59+
'relations' => [
60+
'belongsToManyRelation' => [
61+
[
62+
'operation' => 'create',
63+
'attributes' => [],
64+
'pivot' => [
65+
'number' => true
66+
]
67+
]
68+
]
69+
]
70+
],
71+
],
72+
],
73+
['Accept' => 'application/json']
74+
);
75+
76+
$response->assertStatus(422);
77+
$response->assertJsonStructure(['message', 'errors' => ['mutate.0.relations.belongsToManyRelation.0.pivot.number']]);
78+
}
79+
4580
public function test_updating_a_resource(): void
4681
{
4782
$modelToUpdate = ModelFactory::new()->createOne();
@@ -1176,7 +1211,6 @@ public function test_updating_a_resource_with_updating_belongs_to_many_relation(
11761211
['Accept' => 'application/json']
11771212
);
11781213

1179-
11801214
$this->assertMutatedResponse(
11811215
$response,
11821216
[],

tests/Support/Database/migrations/2023_04_00_000000_create_models_table.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public function up()
1717
$table->id();
1818
$table->string('name');
1919
$table->bigInteger('number');
20+
$table->string('string')->nullable();
2021
$table->foreignIdFor(\Lomkit\Rest\Tests\Support\Models\BelongsToRelation::class)->nullable()->constrained();
2122
$table->nullableMorphs('morph_to_relation', 'morph_to_relation_index');
2223
$table->timestamps();

tests/Support/Rest/Resources/ModelResource.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ class ModelResource extends Resource
2525
{
2626
public static $model = Model::class;
2727

28+
public function createRules(RestRequest $request)
29+
{
30+
return [
31+
'string' => 'string'
32+
];
33+
}
34+
35+
public function updateRules(RestRequest $request)
36+
{
37+
return [
38+
'string' => 'string'
39+
];
40+
}
41+
2842
public function relations(RestRequest $request)
2943
{
3044
return [
@@ -33,6 +47,9 @@ public function relations(RestRequest $request)
3347
BelongsTo::make('belongsToRelation', BelongsToResource::class),
3448
HasMany::make('hasManyRelation', HasManyResource::class),
3549
BelongsToMany::make('belongsToManyRelation', BelongsToManyResource::class)
50+
->withPivotRules([
51+
'number' => 'numeric'
52+
])
3653
->withPivotFields(['created_at', 'number']),
3754

3855
// Through relationships
@@ -56,7 +73,8 @@ public function exposedFields(RestRequest $request)
5673
return [
5774
'id',
5875
'name',
59-
'number'
76+
'number',
77+
'string'
6078
];
6179
}
6280

0 commit comments

Comments
 (0)