Skip to content

Commit 5be672c

Browse files
committed
Added: Model update and find methods
1 parent 2da4bb9 commit 5be672c

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Error propagation improvements with tests for all status codes.
1313
- Introduced `ParsesApiResponse` trait to centralize API response parsing logic.
1414
- Configurable HTTP methods for model updates and deletions.
15+
- `updateById`, instance `update`, `updateOrFail`, and `findOrFail` for remote models.
1516

1617
### Changed
1718
- Refactored `QueryBuilder` and `ApiModel` to use the new `ParsesApiResponse` trait, removing duplicate `parseResponse` implementations.

src/Models/Model.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Kroderdev\LaravelMicroserviceCore\Models;
44

55
use Illuminate\Database\Eloquent\Model as BaseModel;
6+
use Illuminate\Database\Eloquent\ModelNotFoundException;
67
use Illuminate\Pagination\LengthAwarePaginator;
78
use Illuminate\Support\Collection;
89
use Illuminate\Support\Str;
@@ -79,6 +80,18 @@ public static function find($id, $columns = ['*']): ?self
7980
return static::fromResponse($data);
8081
}
8182

83+
/**
84+
* Find a model by its primary key or throw an exception.
85+
*/
86+
public static function findOrFail($id, $columns = ['*']): self
87+
{
88+
if ($model = static::find($id, $columns)) {
89+
return $model;
90+
}
91+
92+
throw (new ModelNotFoundException())->setModel(static::class, [$id]);
93+
}
94+
8295
/**
8396
* Paginate models from the API.
8497
*/
@@ -103,6 +116,75 @@ public static function create(array $attributes = []): ?self
103116
return static::fromResponse($data);
104117
}
105118

119+
/**
120+
* Update a model via the API.
121+
*
122+
* @param int|string $id The ID of the model to update.
123+
* @param array $attributes The attributes to update.
124+
* @return bool
125+
*/
126+
public static function updateById($id, array $attributes): bool
127+
{
128+
$method = strtolower(config('microservice.models.update_method', 'put'));
129+
$response = static::client()->{$method}(static::endpoint().'/'.$id, $attributes);
130+
131+
if (is_object($response) && method_exists($response, 'successful')) {
132+
return $response->successful();
133+
}
134+
135+
return true;
136+
}
137+
138+
/**
139+
* Update the model via the API.
140+
*/
141+
public function update(array $attributes = [], array $options = []): bool
142+
{
143+
if (! $this->exists) {
144+
return false;
145+
}
146+
147+
$this->fill($attributes);
148+
149+
$method = strtolower(config('microservice.models.update_method', 'put'));
150+
$response = static::client()->{$method}(static::endpoint().'/'.$this->getKey(), $this->attributesToArray());
151+
152+
$data = static::parseResponse($response);
153+
if ($fresh = static::fromResponse($data)) {
154+
$this->fill($fresh->attributesToArray());
155+
$this->syncOriginal();
156+
}
157+
158+
return true;
159+
}
160+
161+
/**
162+
* Update the model via the API, throwing an exception on failure.
163+
*/
164+
public function updateOrFail(array $attributes = [], array $options = []): bool
165+
{
166+
if (! $this->exists) {
167+
return false;
168+
}
169+
170+
$this->fill($attributes);
171+
172+
$method = strtolower(config('microservice.models.update_method', 'put'));
173+
$response = static::client()->{$method}(static::endpoint().'/'.$this->getKey(), $this->attributesToArray());
174+
175+
if (is_object($response) && method_exists($response, 'successful') && ! $response->successful()) {
176+
throw new \RuntimeException('Update failed.');
177+
}
178+
179+
$data = static::parseResponse($response);
180+
if ($fresh = static::fromResponse($data)) {
181+
$this->fill($fresh->attributesToArray());
182+
$this->syncOriginal();
183+
}
184+
185+
return true;
186+
}
187+
106188
/**
107189
* Save the model via the API.
108190
*/

tests/Models/ApiModelTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,83 @@ public function delete_users_respects_configured_method()
238238
], $this->gateway->getCalls());
239239
}
240240

241+
/** @test */
242+
public function static_update_users_gateway()
243+
{
244+
$this->gateway = new class () extends FakeGatewayClient {
245+
public function put(string $uri, array $data = [])
246+
{
247+
parent::put($uri, $data);
248+
249+
return collect();
250+
}
251+
};
252+
$this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway);
253+
254+
RemoteUser::updateById(10, ['name' => 'Updated']);
255+
256+
$this->assertSame([
257+
['method' => 'PUT', 'uri' => '/users/10', 'data' => ['name' => 'Updated']],
258+
], $this->gateway->getCalls());
259+
}
260+
261+
/** @test */
262+
public function instance_update_users_gateway()
263+
{
264+
$user = new RemoteUser(['id' => 11, 'name' => 'Old']);
265+
$user->exists = true;
266+
267+
$user->update(['name' => 'New']);
268+
269+
$this->assertSame([
270+
['method' => 'PUT', 'uri' => '/users/11', 'data' => ['id' => 11, 'name' => 'New']],
271+
], $this->gateway->getCalls());
272+
}
273+
274+
/** @test */
275+
public function find_or_fail_throws_when_not_found()
276+
{
277+
$this->gateway = new class () extends FakeGatewayClient {
278+
public function get(string $uri, array $query = [])
279+
{
280+
parent::get($uri, $query);
281+
282+
return null;
283+
}
284+
};
285+
$this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway);
286+
287+
$this->expectException(\Illuminate\Database\Eloquent\ModelNotFoundException::class);
288+
289+
RemoteUser::findOrFail(999);
290+
}
291+
292+
/** @test */
293+
public function update_or_fail_throws_on_failure()
294+
{
295+
$this->gateway = new class () extends FakeGatewayClient {
296+
public function put(string $uri, array $data = [])
297+
{
298+
parent::put($uri, $data);
299+
300+
return new class () {
301+
public function successful()
302+
{
303+
return false;
304+
}
305+
};
306+
}
307+
};
308+
$this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway);
309+
310+
$user = new RemoteUser(['id' => 13, 'name' => 'Old']);
311+
$user->exists = true;
312+
313+
$this->expectException(\RuntimeException::class);
314+
315+
$user->updateOrFail(['name' => 'Fail']);
316+
}
317+
241318
/** @test */
242319
public function where_get_filters_results()
243320
{

0 commit comments

Comments
 (0)