Skip to content

Commit 16e8c61

Browse files
committed
2 parents a6fb72b + 43b1929 commit 16e8c61

File tree

1 file changed

+155
-20
lines changed

1 file changed

+155
-20
lines changed

src/Http/Api/Contracts/HasBatchActions.php

Lines changed: 155 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
<?php
22

3-
/**
4-
Note this is still experimental
5-
**/
6-
7-
namespace Phpsa\LaravelApiController\Http\Api\Contracts;
3+
namespace App\Models\Contracts;
84

5+
use Illuminate\Support\Collection;
96
use Illuminate\Support\Facades\DB;
7+
use Phpsa\LaravelApiController\Events\Created;
8+
use Phpsa\LaravelApiController\Events\Updated;
109
use Phpsa\LaravelApiController\Exceptions\ApiException;
10+
use Illuminate\Database\Eloquent\ModelNotFoundException;
1111

1212
trait HasBatchActions
1313
{
1414

15-
public function handleBatchStoreAction($request, array $extraParams)
15+
public function getBatchData(): Collection
16+
{
17+
return collect($this->request->get('data', []));
18+
}
19+
20+
/**
21+
* @param \Illuminate\Http\Request|\Illuminate\Foundation\Http\FormRequest $request
22+
* @param array $extraParams
23+
*
24+
* @return mixed
25+
*/
26+
public function handleBatchStoreAction($request, array $extraParams = [])
1627
{
1728
$this->validateRequestType($request);
1829
$this->addCustomParams($extraParams);
30+
1931
$this->authoriseUserAction('create');
2032

2133
$this->validate($this->request, $this->rulesForBatchCreate());
@@ -25,45 +37,168 @@ public function handleBatchStoreAction($request, array $extraParams)
2537
$this->unguardIfNeeded();
2638

2739
try {
28-
$records = collect($this->request->get('data'), [])->map(function ($item) {
29-
$data = $this->qualifyStoreQuery($item);
30-
$insert = $this->addTableData($data);
31-
$diff = array_diff(array_keys($data), array_keys($insert));
32-
$item = self::$model->create($insert);
40+
$records = $this->processStoreQuery(collect($this->getBatchData()));
41+
42+
DB::commit();
43+
44+
return $this->handleBatchStoreResponse($records);
45+
} catch (\Exception $exception) {
46+
$message = config('app.debug') ? $exception->getMessage() : 'Failed to create Records';
3347

34-
$this->storeRelated($item, $diff, $data);
48+
DB::rollback();
49+
throw new ApiException($message, (int) $exception->getCode(), $exception);
50+
}
51+
}
3552

36-
return $item;
37-
});
53+
protected function processStoreQuery(Collection $items): Collection
54+
{
55+
return $items->map(function ($item) {
56+
$data = $this->qualifyStoreQuery($item);
57+
$insert = $this->addTableData($data);
58+
$diff = array_diff(array_keys($data), array_keys($insert));
59+
$item = self::$model->create($insert);
60+
61+
$this->storeRelated($item, $diff, $data);
62+
63+
event(new Created($item, $this->request));
64+
65+
return $item;
66+
});
67+
}
68+
69+
/**
70+
* @param \Illuminate\Http\Request|\Illuminate\Foundation\Http\FormRequest $request
71+
*
72+
* @return mixed
73+
*/
74+
public function handleBatchUpdateAction($request, array $extraParams = [])
75+
{
76+
$this->validateRequestType($request);
77+
$this->addCustomParams($extraParams);
78+
79+
$this->validate($this->request, $this->rulesForBatchUpdate());
80+
81+
DB::beginTransaction();
82+
83+
$this->unguardIfNeeded();
84+
85+
try {
86+
$records = $this->processUpdateQuery(collect($this->getBatchData()));
3887

3988
DB::commit();
4089

41-
return $this->handleStoreResponse($records);
90+
return $this->handleBatchUpdateResponse($records);
4291
} catch (\Exception $exception) {
4392
$message = config('app.debug') ? $exception->getMessage() : 'Failed to create Records';
4493

4594
DB::rollback();
46-
throw new ApiException($message, (int) $exception->getCode(), $exception);
95+
match (get_class($exception)) {
96+
ModelNotFoundException::class => throw $exception,
97+
default => throw new ApiException($message, (int) $exception->getCode(), $exception)
98+
};
4799
}
48100
}
49101

102+
protected function processUpdateQuery(Collection $items): Collection
103+
{
104+
return $items->map(function ($item) {
105+
106+
$key = self::$model->getKeyName();
107+
108+
$id = $item[$key];
109+
$existing = $this->builder->where($key, $id)->firstOrFail();
110+
$this->authoriseUserAction('update', $existing);
111+
112+
$data = $this->qualifyUpdateQuery($item);
50113

51-
protected function handleBatchStoreResponse($items)
114+
$updates = $this->addTableData($data);
115+
116+
$diff = array_diff(array_keys($data), array_keys($updates));
117+
118+
$existing->fill($updates);
119+
$existing->save();
120+
121+
$this->storeRelated($existing, $diff, $data);
122+
123+
event(new Updated($existing, $this->request));
124+
125+
return $existing;
126+
});
127+
}
128+
129+
130+
/**
131+
* @param \Illuminate\Http\Request|\Illuminate\Foundation\Http\FormRequest $request
132+
*
133+
* @return mixed
134+
*/
135+
public function handleBatchStoreOrUpdateAction($request, array $extraParams = [])
136+
{
137+
$this->validateRequestType($request);
138+
$this->addCustomParams($extraParams);
139+
140+
$key = self::$model->getKeyName();
141+
$records = $this->getBatchData();
142+
143+
DB::beginTransaction();
144+
145+
$this->unguardIfNeeded();
146+
147+
try {
148+
$existing = $this->processUpdateQuery($records->filter(function ($record) use ($key) {
149+
return ! isset($record[$key]) || empty($record[$key]);
150+
}));
151+
152+
$new = $this->processStoreQuery($records->filter(function ($record) use ($key) {
153+
return isset($record[$key]) && ! empty($record[$key]);
154+
}));
155+
156+
DB::commit();
157+
158+
return $this->handleBatchStoreOrUpdateResponse($existing->merge($new));
159+
} catch (\Exception $exception) {
160+
$message = config('app.debug') ? $exception->getMessage() : 'Failed to create Records';
161+
162+
DB::rollback();
163+
match (get_class($exception)) {
164+
ModelNotFoundException::class => throw $exception,
165+
default => throw new ApiException($message, (int) $exception->getCode(), $exception)
166+
};
167+
}
168+
}
169+
170+
171+
172+
/**
173+
* @return mixed Response|jsonResponse
174+
*/
175+
protected function handleBatchStoreResponse(Collection $items)
52176
{
53177
return $this->respondWithResource($this->/** @scrutinizer ignore-call */getResourceCollection(), $items, 201);
54178
}
55179

56-
protected function handleBatchUpdateResponse($items)
180+
/**
181+
* @return mixed Response|jsonResponse
182+
*/
183+
protected function handleBatchUpdateResponse(Collection $items)
57184
{
58185
return $this->respondWithResource($this->/** @scrutinizer ignore-call */getResourceCollection(), $items, 200);
59186
}
60187

61-
protected function rulesForBatchCreate() : array
188+
/**
189+
* @return mixed Response|jsonResponse
190+
*/
191+
protected function handleBatchStoreOrUpdateResponse(Collection $items)
192+
{
193+
return $this->respondWithResource($this->getResourceCollection(), $items, 200);
194+
}
195+
196+
protected function rulesForBatchCreate(): array
62197
{
63198
return [];
64199
}
65200

66-
protected function rulesForBatchUpdate() : array
201+
protected function rulesForBatchUpdate(): array
67202
{
68203
return [];
69204
}

0 commit comments

Comments
 (0)