Skip to content

Commit 10aed25

Browse files
committed
Extended the ApiModel interface to provide more helper methods for creating model instances from API responses and updated the trait accordingly.
1 parent 1e5318c commit 10aed25

File tree

5 files changed

+380
-23
lines changed

5 files changed

+380
-23
lines changed

src/Interfaces/ApiModel.php

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Kroderdev\LaravelMicroserviceCore\Interfaces;
4+
5+
use Illuminate\Pagination\LengthAwarePaginator;
6+
use Illuminate\Support\Collection;
7+
8+
interface ApiModelContract
9+
{
10+
/** Create a model instance from raw API payload */
11+
public static function fromApiResponse(array $data): static;
12+
13+
/** Build a collection of models from an array of payloads */
14+
public static function fromCollection(array $items): Collection;
15+
16+
/** Extract the model from a standard API response */
17+
public static function fromResponse(array $response): ?static;
18+
19+
/** Convert a paginated API response into a paginator of models */
20+
public static function fromPaginatedResponse(array $response): LengthAwarePaginator;
21+
}

src/Models/Model.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
namespace Kroderdev\LaravelMicroserviceCore\Models;
4+
5+
use Illuminate\Database\Eloquent\Model as BaseModel;
6+
use Illuminate\Pagination\LengthAwarePaginator;
7+
use Illuminate\Support\Collection;
8+
use Illuminate\Support\Str;
9+
use Kroderdev\LaravelMicroserviceCore\Contracts\ApiGatewayClientInterface;
10+
use Kroderdev\LaravelMicroserviceCore\Interfaces\ApiModelContract;
11+
use Kroderdev\LaravelMicroserviceCore\Traits\ApiModelTrait;
12+
13+
abstract class Model extends BaseModel implements ApiModelContract
14+
{
15+
use ApiModelTrait;
16+
17+
/**
18+
* Endpoint for this model. Defaults to plural kebab of the class name.
19+
*/
20+
protected static string $endpoint = '';
21+
22+
/**
23+
* Return the endpoint for the model.
24+
*/
25+
protected static function endpoint(): string
26+
{
27+
if (static::$endpoint !== '') {
28+
return static::$endpoint;
29+
}
30+
31+
return '/' . Str::kebab(Str::pluralStudly(class_basename(static::class)));
32+
}
33+
34+
/**
35+
* Get the ApiGateway client instance.
36+
*/
37+
protected static function client(): ApiGatewayClientInterface
38+
{
39+
return app(ApiGatewayClientInterface::class);
40+
}
41+
42+
/**
43+
* Get all models.
44+
*/
45+
public static function all($columns = ['*']): Collection
46+
{
47+
$response = static::client()->get(static::endpoint());
48+
$data = static::parseResponse($response);
49+
50+
return static::fromCollection($data['data'] ?? $data);
51+
}
52+
53+
/**
54+
* Find a model by its primary key.
55+
*/
56+
public static function find($id, $columns = ['*']): ?self
57+
{
58+
$response = static::client()->get(static::endpoint() . '/' . $id);
59+
$data = static::parseResponse($response);
60+
61+
return static::fromResponse($data);
62+
}
63+
64+
/**
65+
* Paginate models from the API.
66+
*/
67+
public static function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null): LengthAwarePaginator
68+
{
69+
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
70+
$query = [$pageName => $page, 'per_page' => $perPage];
71+
$response = static::client()->get(static::endpoint(), $query);
72+
$data = static::parseResponse($response);
73+
74+
return static::fromPaginatedResponse($data);
75+
}
76+
77+
/**
78+
* Create a model via the API.
79+
*/
80+
public static function create(array $attributes = []): self|null
81+
{
82+
$response = static::client()->post(static::endpoint(), $attributes);
83+
$data = static::parseResponse($response);
84+
85+
return static::fromResponse($data);
86+
}
87+
88+
/**
89+
* Save the model via the API.
90+
*/
91+
public function save(array $options = []): bool
92+
{
93+
if ($this->exists) {
94+
$response = static::client()->put(static::endpoint() . '/' . $this->getKey(), $this->attributesToArray());
95+
} else {
96+
$response = static::client()->post(static::endpoint(), $this->attributesToArray());
97+
}
98+
99+
$data = static::parseResponse($response);
100+
if ($fresh = static::fromResponse($data)) {
101+
$this->fill($fresh->attributesToArray());
102+
$this->exists = true;
103+
$this->syncOriginal();
104+
}
105+
106+
return true;
107+
}
108+
109+
/**
110+
* Delete the model via the API.
111+
*/
112+
public function delete(): bool
113+
{
114+
$response = static::client()->delete(static::endpoint() . '/' . $this->getKey());
115+
116+
if (is_object($response) && method_exists($response, 'successful')) {
117+
return $response->successful();
118+
}
119+
120+
return true;
121+
}
122+
123+
/**
124+
* Refresh the model from the API.
125+
*/
126+
public function refresh(): static
127+
{
128+
$response = static::client()->get(static::endpoint() . '/' . $this->getKey());
129+
$data = static::parseResponse($response);
130+
if ($fresh = static::fromResponse($data)) {
131+
$this->fill($fresh->attributesToArray());
132+
$this->syncOriginal();
133+
}
134+
135+
return $this;
136+
}
137+
138+
/**
139+
* Normalize different response types to array.
140+
*/
141+
protected static function parseResponse($response): array
142+
{
143+
if ($response === null) {
144+
return [];
145+
}
146+
147+
if (is_array($response)) {
148+
return $response;
149+
}
150+
151+
if ($response instanceof Collection) {
152+
return $response->toArray();
153+
}
154+
155+
if (method_exists($response, 'json')) {
156+
return $response->json();
157+
}
158+
159+
return (array) $response;
160+
}
161+
}

src/Traits/ApiModelTrait.php

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,36 @@
77

88
trait ApiModelTrait
99
{
10-
public static function fromApiResponse(array $data)
10+
/**
11+
* Instantiate a model from raw API data.
12+
*/
13+
public static function fromApiResponse(array $data): static
1114
{
1215
$instance = new static();
1316
$instance->fill($data);
17+
1418
return $instance;
1519
}
1620

21+
/**
22+
* Create a collection of models from an array of payloads.
23+
*/
24+
public static function fromCollection(array $items): Collection
25+
{
26+
return collect($items)->map(fn ($item) => static::fromApiResponse($item));
27+
}
28+
29+
/**
30+
* Build a model from a typical API response wrapper.
31+
*/
32+
public static function fromResponse(array $response): ?static
33+
{
34+
return isset($response['data']) ? static::fromApiResponse($response['data']) : null;
35+
}
36+
37+
/**
38+
* Convert a paginated API payload into a paginator of models.
39+
*/
1740
public static function fromPaginatedResponse(array $response): LengthAwarePaginator
1841
{
1942
$items = collect($response['data'] ?? [])
@@ -30,15 +53,4 @@ public static function fromPaginatedResponse(array $response): LengthAwarePagina
3053
);
3154
}
3255

33-
public static function fromCollection(array $items): Collection
34-
{
35-
return collect($items)->map(fn($item) => static::fromApiResponse($item));
36-
}
37-
38-
public static function fromResponse(array $response): ?self
39-
{
40-
return isset($response['data']) ? static::fromApiResponse($response['data']) : null;
41-
}
42-
43-
4456
}

0 commit comments

Comments
 (0)