Skip to content

Commit 605cd4a

Browse files
Samoht7015g-lucas
andauthored
Multiple keys support (#168)
--------- Co-authored-by: 15glucas <gosgnach24lucas@gmail.com>
1 parent da3ffba commit 605cd4a

File tree

11 files changed

+2616
-421
lines changed

11 files changed

+2616
-421
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Concerns\Relations;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Lomkit\Rest\Contracts\QueryBuilder;
7+
use Lomkit\Rest\Relations\Relation;
8+
9+
trait PerformsRelationOperations
10+
{
11+
/**
12+
* @param Model $model
13+
* @param Relation $relation
14+
* @param array $mutation
15+
* @param array $attributes
16+
*
17+
* @return void
18+
*/
19+
public function create(Model $model, Relation $relation, array $mutation = [], array $attributes = [])
20+
{
21+
$toPerformActionModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
22+
->applyMutation($mutation, $attributes);
23+
24+
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
25+
26+
$model
27+
->{$relation->relation}()
28+
->syncWithoutDetaching(
29+
[
30+
$toPerformActionModel->getKey() => $mutation['pivot'] ?? [],
31+
]
32+
);
33+
}
34+
35+
/**
36+
* @param Model $model
37+
* @param Relation $relation
38+
* @param array $mutation
39+
* @param array $attributes
40+
*
41+
* @return void
42+
*/
43+
public function update(Model $model, Relation $relation, array $mutation = [], array $attributes = [])
44+
{
45+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
46+
->mutations($mutation, $attributes);
47+
48+
foreach ($toPerformActionModels as $toPerformActionModel) {
49+
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
50+
}
51+
52+
$model->{$relation->relation}()
53+
->syncWithoutDetaching(
54+
collect($toPerformActionModels)
55+
->mapWithKeys(
56+
fn (Model $toPerformActionModel) => [$toPerformActionModel->getKey() => $mutation['pivot'] ?? []]
57+
)->toArray()
58+
);
59+
}
60+
61+
/**
62+
* @param Model $model
63+
* @param Relation $relation
64+
* @param array $mutation
65+
* @param array $attributes
66+
*
67+
* @return void
68+
*/
69+
public function attach(Model $model, Relation $relation, array $mutation = [], array $attributes = [])
70+
{
71+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
72+
->mutations($mutation, $attributes);
73+
74+
foreach ($toPerformActionModels as $toPerformActionModel) {
75+
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
76+
}
77+
78+
$model->{$relation->relation}()
79+
->attach(
80+
collect($toPerformActionModels)
81+
->mapWithKeys(
82+
fn (Model $toPerformActionModel) => [$toPerformActionModel->getKey() => $mutation['pivot'] ?? []]
83+
)->toArray()
84+
);
85+
}
86+
87+
/**
88+
* @param Model $model
89+
* @param Relation $relation
90+
* @param array $mutation
91+
* @param array $attributes
92+
*
93+
* @return void
94+
*/
95+
public function detach(Model $model, Relation $relation, array $mutation = [], array $attributes = [])
96+
{
97+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
98+
->mutations($mutation, $attributes);
99+
100+
foreach ($toPerformActionModels as $toPerformActionModel) {
101+
$this->resource()->authorizeToDetach($model, $toPerformActionModel);
102+
}
103+
104+
$model->{$relation->relation}()->detach($toPerformActionModels);
105+
}
106+
107+
/**
108+
* @param Model $model
109+
* @param Relation $relation
110+
* @param array $mutation
111+
* @param array $attributes
112+
*
113+
* @return void
114+
*/
115+
public function toggle(Model $model, Relation $relation, array $mutation = [], array $attributes = [])
116+
{
117+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
118+
->mutations($mutation, $attributes);
119+
120+
$results = $model->{$relation->relation}()
121+
->toggle(
122+
collect($toPerformActionModels)
123+
->mapWithKeys(
124+
fn (Model $toPerformActionModel) => [$toPerformActionModel->getKey() => $mutation['pivot'] ?? []]
125+
)->toArray(),
126+
);
127+
128+
foreach ($results['attached'] as $attached) {
129+
$this->resource()->authorizeToAttach($model, $relation->resource()::$model::find($attached));
130+
}
131+
132+
foreach ($results['detached'] as $detached) {
133+
$this->resource()->authorizeToDetach($model, $relation->resource()::$model::find($detached));
134+
}
135+
}
136+
137+
/**
138+
* @param Model $model
139+
* @param Relation $relation
140+
* @param array $mutation
141+
* @param array $attributes
142+
* @param bool $withoutDetaching
143+
*
144+
* @return void
145+
*/
146+
public function sync(Model $model, Relation $relation, array $mutation = [], array $attributes = [], $withoutDetaching = false)
147+
{
148+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
149+
->mutations($mutation, $attributes);
150+
151+
$results = $model->{$relation->relation}()
152+
->sync(
153+
collect($toPerformActionModels)
154+
->mapWithKeys(
155+
fn (Model $toPerformActionModel) => [$toPerformActionModel->getKey() => $mutation['pivot'] ?? []]
156+
)->toArray(),
157+
$withoutDetaching
158+
);
159+
160+
foreach ($results['attached'] as $attached) {
161+
$this->resource()->authorizeToAttach($model, $relation->resource()::$model::find($attached));
162+
}
163+
164+
foreach ($results['detached'] as $detached) {
165+
$this->resource()->authorizeToDetach($model, $relation->resource()::$model::find($detached));
166+
}
167+
}
168+
}

src/Query/Traits/PerformMutation.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ public function mutate(array $parameters = [])
3333
];
3434

3535
foreach ($parameters['mutate'] as $parameter) {
36-
$operations[
37-
$this->mutateOperationsVerbose[$parameter['operation']]
38-
][] = $this->applyMutation($parameter)->getKey();
36+
$operations[$this->mutateOperationsVerbose[$parameter['operation']]][] = $this->applyMutation($parameter)->getKey();
3937
}
4038

4139
return $operations;
@@ -49,14 +47,14 @@ public function mutate(array $parameters = [])
4947
*
5048
* @return Model The mutated model.
5149
*/
52-
public function applyMutation(array $mutation = [], $attributes = [])
50+
public function applyMutation(array $mutation = [], $attributes = [], $key = null)
5351
{
5452
$allAttributes = array_merge($attributes, $mutation['attributes'] ?? []);
5553

5654
if ($mutation['operation'] === 'create') {
5755
$model = $this->resource::newModel();
5856
} else {
59-
$model = $this->resource::newModel()::findOrFail($mutation['key']);
57+
$model = $this->resource::newModel()::query()->findOrFail($key ?? $mutation['key']);
6058
}
6159

6260
if ($mutation['operation'] === 'create') {
@@ -74,6 +72,25 @@ public function applyMutation(array $mutation = [], $attributes = [])
7472
);
7573
}
7674

75+
/**
76+
* Apply a mutation to the model based on the provided mutation parameters.
77+
*
78+
* @param array $mutation An array of mutation parameters.
79+
* @param array $attributes Additional attributes to apply to the model.
80+
*
81+
* @return array<Model> The mutated model.
82+
*/
83+
public function mutations(array $mutation = [], $attributes = [])
84+
{
85+
$keys = $mutation['key'] ?? [];
86+
$keys = is_array($keys) ? $keys : [$keys];
87+
88+
return array_map(
89+
fn ($key) => $this->applyMutation($mutation, $attributes, $key),
90+
$keys
91+
);
92+
}
93+
7794
/**
7895
* Mutate the model by applying attributes and relations.
7996
*

src/Relations/BelongsToMany.php

Lines changed: 12 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
namespace Lomkit\Rest\Relations;
44

55
use Illuminate\Database\Eloquent\Model;
6+
use InvalidArgumentException;
67
use Lomkit\Rest\Concerns\Relations\HasPivotFields;
7-
use Lomkit\Rest\Contracts\QueryBuilder;
8+
use Lomkit\Rest\Concerns\Relations\PerformsRelationOperations;
89
use Lomkit\Rest\Contracts\RelationResource;
910
use Lomkit\Rest\Http\Resource;
1011
use Lomkit\Rest\Relations\Traits\HasMultipleResults;
@@ -14,6 +15,7 @@ class BelongsToMany extends Relation implements RelationResource
1415
{
1516
use HasPivotFields;
1617
use HasMultipleResults;
18+
use PerformsRelationOperations;
1719

1820
/**
1921
* Define validation rules for the BelongsToMany relation.
@@ -46,82 +48,15 @@ public function rules(Resource $resource, string $prefix)
4648
public function afterMutating(Model $model, Relation $relation, array $mutationRelations)
4749
{
4850
foreach ($mutationRelations[$relation->relation] as $mutationRelation) {
49-
if ($mutationRelation['operation'] === 'detach') {
50-
$toDetachModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
51-
->applyMutation($mutationRelation);
52-
53-
$this->resource()->authorizeToDetach($model, $toDetachModel);
54-
55-
$model
56-
->{$relation->relation}()
57-
->detach(
58-
$toDetachModel->getKey()
59-
);
60-
} elseif ($mutationRelation['operation'] === 'attach') {
61-
$toAttachModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
62-
->applyMutation($mutationRelation);
63-
64-
$this->resource()->authorizeToAttach($model, $toAttachModel);
65-
66-
$model
67-
->{$relation->relation}()
68-
->attach(
69-
[
70-
$toAttachModel->getKey() => $mutationRelation['pivot'] ?? [],
71-
]
72-
);
73-
} elseif ($mutationRelation['operation'] === 'toggle') {
74-
$results = $model
75-
->{$relation->relation}()
76-
->toggle(
77-
[
78-
app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
79-
->applyMutation($mutationRelation)
80-
->getKey() => $mutationRelation['pivot'] ?? [],
81-
]
82-
);
83-
84-
foreach ($results['attached'] as $attached) {
85-
$this->resource()->authorizeToAttach($model, $relation->resource()::$model::find($attached));
86-
}
87-
88-
foreach ($results['detached'] as $detached) {
89-
$this->resource()->authorizeToDetach($model, $relation->resource()::$model::find($detached));
90-
}
91-
} elseif ($mutationRelation['operation'] === 'sync') {
92-
$results = $model
93-
->{$relation->relation}()
94-
->sync(
95-
[
96-
app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
97-
->applyMutation($mutationRelation)
98-
->getKey() => $mutationRelation['pivot'] ?? [],
99-
],
100-
!isset($mutationRelation['without_detaching']) || !$mutationRelation['without_detaching']
101-
);
102-
103-
foreach ($results['attached'] as $attached) {
104-
$this->resource()->authorizeToAttach($model, $relation->resource()::$model::find($attached));
105-
}
106-
107-
foreach ($results['detached'] as $detached) {
108-
$this->resource()->authorizeToDetach($model, $relation->resource()::$model::find($detached));
109-
}
110-
} elseif (in_array($mutationRelation['operation'], ['create', 'update'])) {
111-
$toAttachModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
112-
->applyMutation($mutationRelation);
113-
114-
$this->resource()->authorizeToAttach($model, $toAttachModel);
115-
116-
$model
117-
->{$relation->relation}()
118-
->syncWithoutDetaching(
119-
[
120-
$toAttachModel
121-
->getKey() => $mutationRelation['pivot'] ?? [],
122-
]
123-
);
124-
}
51+
match ($mutationRelation['operation']) {
52+
'create' => $this->create($model, $relation, $mutationRelation),
53+
'update' => $this->update($model, $relation, $mutationRelation),
54+
'attach' => $this->attach($model, $relation, $mutationRelation),
55+
'detach' => $this->detach($model, $relation, $mutationRelation),
56+
'toggle' => $this->toggle($model, $relation, $mutationRelation),
57+
'sync' => $this->sync($model, $relation, $mutationRelation, withoutDetaching: !isset($mutationRelation['without_detaching']) || !$mutationRelation['without_detaching']),
58+
default => throw new InvalidArgumentException("Unknown operation: {$mutationRelation['operation']}"),
59+
};
12560
}
12661
}
12762
}

src/Relations/HasMany.php

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,23 @@ public function afterMutating(Model $model, Relation $relation, array $mutationR
2525
$model->{$relation->relation}()->getForeignKeyName() => $mutationRelation['operation'] === 'detach' ? null : $model->{$relation->relation}()->getParentKey(),
2626
];
2727

28-
$toPerformActionModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
29-
->applyMutation($mutationRelation, $attributes);
28+
if ($mutationRelation['operation'] === 'create') {
29+
$toPerformActionModel = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
30+
->applyMutation($mutationRelation, $attributes);
3031

31-
switch ($mutationRelation['operation']) {
32-
case 'create':
33-
case 'update':
34-
case 'attach':
35-
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
36-
break;
37-
case 'detach':
32+
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
33+
continue;
34+
}
35+
36+
$toPerformActionModels = app()->make(QueryBuilder::class, ['resource' => $relation->resource()])
37+
->mutations($mutationRelation, $attributes);
38+
39+
foreach ($toPerformActionModels as $toPerformActionModel) {
40+
if ($mutationRelation['operation'] === 'detach') {
3841
$this->resource()->authorizeToDetach($model, $toPerformActionModel);
39-
break;
42+
} else {
43+
$this->resource()->authorizeToAttach($model, $toPerformActionModel);
44+
}
4045
}
4146
}
4247
}

0 commit comments

Comments
 (0)