Skip to content

Commit f512500

Browse files
committed
Clean up and fix tests
1 parent 3238ee3 commit f512500

File tree

13 files changed

+219
-223
lines changed

13 files changed

+219
-223
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Tobyz\JsonApiServer\Endpoint\Concerns;
4+
5+
use Tobyz\JsonApiServer\JsonApi;
6+
7+
trait BuildsOpenApiPaths
8+
{
9+
private function buildOpenApiContent(array $resources, bool $multiple = false): array
10+
{
11+
$item = count($resources) === 1 ? $resources[0] : ['oneOf' => $resources];
12+
13+
return [
14+
JsonApi::MEDIA_TYPE => [
15+
'schema' => [
16+
'type' => 'object',
17+
'required' => ['data'],
18+
'properties' => [
19+
'data' => $multiple ? ['type' => 'array', 'items' => $item] : $item,
20+
],
21+
],
22+
],
23+
];
24+
}
25+
}

src/Endpoint/Concerns/SavesData.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ private function parseData(Context $context): array
8787
/**
8888
* Assert that the fields contained within a data object are valid.
8989
*/
90-
private function assertFieldsValid(Context $context, array $data): void
90+
private function assertFieldsValid(Context $context, array $data, bool $creating = false): void
9191
{
9292
$this->assertFieldsExist($context, $data);
93-
$this->assertFieldsWritable($context, $data);
93+
$this->assertFieldsWritable($context, $data, $creating);
9494
}
9595

9696
/**
@@ -118,14 +118,23 @@ private function assertFieldsExist(Context $context, array $data): void
118118
*
119119
* @throws ForbiddenException if a field is not writable.
120120
*/
121-
private function assertFieldsWritable(Context $context, array $data): void
122-
{
121+
private function assertFieldsWritable(
122+
Context $context,
123+
array $data,
124+
bool $creating = false,
125+
): void {
123126
foreach ($context->fields($context->resource) as $field) {
124127
if (!has_value($data, $field)) {
125128
continue;
126129
}
127130

128-
if (!$field->isWritable($context->withField($field))) {
131+
$context = $context->withField($field);
132+
133+
$writable = $creating
134+
? $field->isWritableOnCreate($context)
135+
: $field->isWritable($context);
136+
137+
if (!$writable) {
129138
throw (new ForbiddenException("Field [$field->name] is not writable"))->setSource([
130139
'pointer' => '/data/' . location($field) . '/' . $field->name,
131140
]);

src/Endpoint/Create.php

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
use Psr\Http\Message\ResponseInterface;
66
use RuntimeException;
77
use Tobyz\JsonApiServer\Context;
8+
use Tobyz\JsonApiServer\Endpoint\Concerns\BuildsOpenApiPaths;
89
use Tobyz\JsonApiServer\Endpoint\Concerns\SavesData;
910
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
1011
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1112
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
12-
use Tobyz\JsonApiServer\JsonApi;
1313
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
1414
use Tobyz\JsonApiServer\Resource\Collection;
1515
use Tobyz\JsonApiServer\Resource\Creatable;
@@ -26,6 +26,7 @@ class Create implements Endpoint, OpenApiPathsProvider
2626
use SavesData;
2727
use ShowsResources;
2828
use HasDescription;
29+
use BuildsOpenApiPaths;
2930

3031
private array $afterCallbacks = [];
3132

@@ -62,7 +63,7 @@ public function handle(Context $context): ?ResponseInterface
6263
->withResource($resource = $context->resource($data['type']))
6364
->withModel($model = $collection->newModel($context));
6465

65-
$this->assertFieldsValid($context, $data);
66+
$this->assertFieldsValid($context, $data, true);
6667
$this->fillDefaultValues($context, $data);
6768
$this->deserializeValues($context, $data);
6869
$this->assertDataValid($context, $data, true);
@@ -105,54 +106,30 @@ private function fillDefaultValues(Context $context, array &$data): void
105106

106107
public function getOpenApiPaths(Collection $collection): array
107108
{
108-
$resourcesCreate = array_map(
109-
fn($resource) => ['$ref' => "#/components/schemas/{$resource}Create"],
110-
$collection->resources(),
111-
);
112-
113-
$resources = array_map(
114-
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
115-
$collection->resources(),
116-
);
117-
118109
return [
119110
"/{$collection->name()}" => [
120111
'post' => [
121112
'description' => $this->getDescription(),
122113
'tags' => [$collection->name()],
123114
'requestBody' => [
124-
'content' => [
125-
JsonApi::MEDIA_TYPE => [
126-
'schema' => [
127-
'type' => 'object',
128-
'required' => ['data'],
129-
'properties' => [
130-
'data' =>
131-
count($resourcesCreate) === 1
132-
? $resourcesCreate[0]
133-
: ['oneOf' => $resourcesCreate],
134-
],
135-
],
136-
],
137-
],
138115
'required' => true,
116+
'content' => $this->buildOpenApiContent(
117+
array_map(
118+
fn($resource) => [
119+
'$ref' => "#/components/schemas/{$resource}Create",
120+
],
121+
$collection->resources(),
122+
),
123+
),
139124
],
140125
'responses' => [
141126
'200' => [
142-
'content' => [
143-
JsonApi::MEDIA_TYPE => [
144-
'schema' => [
145-
'type' => 'object',
146-
'required' => ['data'],
147-
'properties' => [
148-
'data' =>
149-
count($resources) === 1
150-
? $resources[0]
151-
: ['oneOf' => $resources],
152-
],
153-
],
154-
],
155-
],
127+
'content' => $this->buildOpenApiContent(
128+
array_map(
129+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
130+
$collection->resources(),
131+
),
132+
),
156133
],
157134
],
158135
],

src/Endpoint/Index.php

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
use Psr\Http\Message\ResponseInterface as Response;
77
use RuntimeException;
88
use Tobyz\JsonApiServer\Context;
9+
use Tobyz\JsonApiServer\Endpoint\Concerns\BuildsOpenApiPaths;
910
use Tobyz\JsonApiServer\Endpoint\Concerns\IncludesData;
1011
use Tobyz\JsonApiServer\Exception\BadRequestException;
1112
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1213
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
1314
use Tobyz\JsonApiServer\Exception\Sourceable;
14-
use Tobyz\JsonApiServer\JsonApi;
1515
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
1616
use Tobyz\JsonApiServer\Pagination\OffsetPagination;
1717
use Tobyz\JsonApiServer\Resource\Collection;
@@ -32,6 +32,7 @@ class Index implements Endpoint, OpenApiPathsProvider
3232
use HasVisibility;
3333
use IncludesData;
3434
use HasDescription;
35+
use BuildsOpenApiPaths;
3536

3637
public Closure $paginationResolver;
3738
public ?string $defaultSort = null;
@@ -174,37 +175,20 @@ private function applyFilters($query, Context $context): void
174175

175176
public function getOpenApiPaths(Collection $collection): array
176177
{
177-
$resources = array_map(
178-
fn($resource) => [
179-
'$ref' => "#/components/schemas/$resource",
180-
],
181-
$collection->resources(),
182-
);
183-
184178
return [
185179
"/{$collection->name()}" => [
186180
'get' => [
187181
'description' => $this->getDescription(),
188182
'tags' => [$collection->name()],
189183
'responses' => [
190184
'200' => [
191-
'content' => [
192-
JsonApi::MEDIA_TYPE => [
193-
'schema' => [
194-
'type' => 'object',
195-
'required' => ['data'],
196-
'properties' => [
197-
'data' => [
198-
'type' => 'array',
199-
'items' =>
200-
count($resources) === 1
201-
? $resources[0]
202-
: ['oneOf' => $resources],
203-
],
204-
],
205-
],
206-
],
207-
],
185+
'content' => $this->buildOpenApiContent(
186+
array_map(
187+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
188+
$collection->resources(),
189+
),
190+
multiple: true,
191+
),
208192
],
209193
],
210194
],

src/Endpoint/ResourceAction.php

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
use Closure;
66
use Psr\Http\Message\ResponseInterface;
77
use Tobyz\JsonApiServer\Context;
8+
use Tobyz\JsonApiServer\Endpoint\Concerns\BuildsOpenApiPaths;
89
use Tobyz\JsonApiServer\Endpoint\Concerns\FindsResources;
910
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
1011
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1112
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
12-
use Tobyz\JsonApiServer\JsonApi;
1313
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
1414
use Tobyz\JsonApiServer\Resource\Collection;
1515
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
@@ -23,6 +23,7 @@ class ResourceAction implements Endpoint, OpenApiPathsProvider
2323
use HasDescription;
2424
use FindsResources;
2525
use ShowsResources;
26+
use BuildsOpenApiPaths;
2627

2728
public string $method = 'POST';
2829

@@ -93,20 +94,12 @@ public function getOpenApiPaths(Collection $collection): array
9394
],
9495
'responses' => [
9596
'200' => [
96-
'content' => [
97-
JsonApi::MEDIA_TYPE => [
98-
'schema' => [
99-
'type' => 'object',
100-
'required' => ['data'],
101-
'properties' => [
102-
'data' =>
103-
count($resources) === 1
104-
? $resources[0]
105-
: ['oneOf' => $resources],
106-
],
107-
],
108-
],
109-
],
97+
'content' => $this->buildOpenApiContent(
98+
array_map(
99+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
100+
$collection->resources(),
101+
),
102+
),
110103
],
111104
],
112105
],

src/Endpoint/Show.php

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
use Psr\Http\Message\ResponseInterface;
66
use Tobyz\JsonApiServer\Context;
7+
use Tobyz\JsonApiServer\Endpoint\Concerns\BuildsOpenApiPaths;
78
use Tobyz\JsonApiServer\Endpoint\Concerns\FindsResources;
89
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
910
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1011
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
11-
use Tobyz\JsonApiServer\JsonApi;
1212
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
1313
use Tobyz\JsonApiServer\Resource\Collection;
1414
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
@@ -22,6 +22,7 @@ class Show implements Endpoint, OpenApiPathsProvider
2222
use FindsResources;
2323
use ShowsResources;
2424
use HasDescription;
25+
use BuildsOpenApiPaths;
2526

2627
public static function make(): static
2728
{
@@ -51,11 +52,6 @@ public function handle(Context $context): ?ResponseInterface
5152

5253
public function getOpenApiPaths(Collection $collection): array
5354
{
54-
$resources = array_map(
55-
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
56-
$collection->resources(),
57-
);
58-
5955
return [
6056
"/{$collection->name()}/{id}" => [
6157
'get' => [
@@ -71,20 +67,12 @@ public function getOpenApiPaths(Collection $collection): array
7167
],
7268
'responses' => [
7369
'200' => [
74-
'content' => [
75-
JsonApi::MEDIA_TYPE => [
76-
'schema' => [
77-
'type' => 'object',
78-
'required' => ['data'],
79-
'properties' => [
80-
'data' =>
81-
count($resources) === 1
82-
? $resources[0]
83-
: ['oneOf' => $resources],
84-
],
85-
],
86-
],
87-
],
70+
'content' => $this->buildOpenApiContent(
71+
array_map(
72+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
73+
$collection->resources(),
74+
),
75+
),
8876
],
8977
],
9078
],

0 commit comments

Comments
 (0)