Skip to content

Commit 2bfb2a0

Browse files
committed
feat: v1.0.0 - Resource schema
1 parent c9e2fa6 commit 2bfb2a0

21 files changed

+573
-166
lines changed

CHANGELOG-1.0.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Release note
2+
============
3+
4+
# v1.0.0
5+
### Added
6+
- `Schema` trait implement method `schema` on `JsonApiResource` and `JsonApiCollection`
7+
- `Relationize::relationship` static method which allow to create relation for resource (like : `PostResource::relationship(fn() => $this->posts)`)
8+
9+
10+
### Breaking change
11+
- `Relationship::construct` signature has change for :
12+
```php
13+
public function __construct(
14+
protected string $resource, // represent class-string of resource
15+
protected Closure $value, // MUST be a closure which return real value
16+
protected ?Closure $links = null,
17+
protected ?Closure $meta = null
18+
)
19+
```
20+
21+
- `JsonApiResource`
22+
- `construct` can't be overwrited
23+
- `toAttributes` **SHOULD** return an `array<string, Closure>`
24+
- `toRelationships` **MUST** return an `array<string, Relationship>`
25+
26+
27+
- `JsonApiCollection`
28+
- `construct` can't be overwrited
29+
30+
31+
- `Resourceable`
32+
- `toArray` second parameter has been changed from `false` to `true`, and comportment has been inverted.
33+
34+
35+
- `Relationize`
36+
- `asRelationship` has been deleted

src/Concerns/Attributes.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ trait Attributes
1212
*
1313
* @param \Illuminate\Http\Request $request
1414
*
15-
* @return array<string, mixed>
15+
* @return array<string, Closure>
1616
*
1717
* ```
1818
* return [
19-
* 'name' => $this->name,
19+
* 'name' => fn() => $this->name,
2020
* // with laravel conditional attributes
21-
* 'secret' => $this->when($request->user()->isAdmin(), 'secret-value'),
21+
* 'secret' => fn() => $this->when($request->user()->isAdmin(), 'secret-value'),
2222
* ];
2323
* ```
2424
*/
@@ -34,7 +34,11 @@ protected function toAttributes(Request $request): iterable
3434
*/
3535
private function requestedAttributes(Request $request): array
3636
{
37-
$attributes = $this->filter(collect($this->toAttributes($request))->toArray());
37+
$attributes = collect($this->toAttributes($request))
38+
->map(fn($value) => value($value))
39+
->toArray();
40+
41+
$attributes = $this->filter($attributes);
3842

3943
$fields = Fields::get($request, $this->toType($request));
4044

src/Concerns/Identifier.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Ark4ne\JsonApi\Resource\Concerns;
44

5+
use Illuminate\Database\Eloquent\Model;
56
use Illuminate\Http\Request;
67
use Illuminate\Support\Str;
78

@@ -36,6 +37,10 @@ protected function toType(Request $request): string
3637
*/
3738
protected function toIdentifier(Request $request): int|string
3839
{
40+
if ($this->resource instanceof Model) {
41+
return $this->resource->getKey();
42+
}
43+
3944
return $this->id;
4045
}
4146

src/Concerns/Relationize.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
trait Relationize
99
{
1010
/**
11-
* Transform JSON:API resource as relationship
11+
* @param \Closure $value
12+
* @param \Closure|null $links
13+
* @param \Closure|null $meta
1214
*
13-
* @param iterable|\Closure $links
14-
* @param iterable|\Closure $meta
15-
*
16-
* @return \Ark4ne\JsonApi\Resource\Relationship
15+
* @return \Ark4ne\JsonApi\Resource\Relationship<static>
1716
*/
18-
public function asRelationship(
19-
iterable|Closure $links = [],
20-
iterable|Closure $meta = []
17+
public static function relationship(
18+
Closure $value,
19+
?Closure $links = null,
20+
?Closure $meta = null
2121
): Relationship {
22-
return new Relationship($this, $links, $meta);
22+
return new Relationship(static::class, $value, $links, $meta);
2323
}
2424
}

src/Concerns/Relationships.php

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ trait Relationships
1313
*
1414
* @param \Illuminate\Http\Request $request
1515
*
16-
* @return array<string, <Closure():<Relationship> | Relationship>>
16+
* @return array<string, Relationship>
1717
*
1818
* ```
1919
* return [
20-
* 'avatar' => AvatarResource::make($this->avatar),
21-
* // with lazy evaluation
22-
* 'posts' => fn () => PostResource::collection($this->posts),
20+
* 'avatar' => AvatarResource::relationship(fn() => $this->avatar),
21+
* // as collection
22+
* 'posts' => PostResource::relationship(fn() => $this->posts)->asCollection(),
2323
* // with laravel conditional relationships
24-
* 'comments' => $this->when($this->canComments(), fn() => fn() => CommentResource::collection($this->comments),
24+
* 'comments' => CommentResource::relationship(fn() => $this->when($this->canComments(), fn() => $this->comments))->asCollection(),
2525
* ];
2626
* ```
2727
*/
@@ -33,19 +33,14 @@ protected function toRelationships(Request $request): iterable
3333
private function requestedRelationships(Request $request): array
3434
{
3535
$relations = [];
36-
$relationships = $this->toRelationships($request);
3736

38-
foreach ($this->filter($relationships) as $name => $relationship) {
39-
$relationship = value($relationship);
37+
foreach ($this->toRelationships($request) as $name => $relationship) {
38+
$relationship->forRelation($name);
4039

41-
if (!($relationship instanceof Relationship)) {
42-
$relationship = new Relationship($relationship);
43-
}
44-
45-
$minimal = !Includes::include($request, $name);
40+
$included = Includes::include($request, $name);
4641

4742
$relations[$name] = Includes::through($name, fn() => $this->mapRelationship(
48-
$minimal,
43+
$included,
4944
$request,
5045
$relationship
5146
));
@@ -55,11 +50,11 @@ private function requestedRelationships(Request $request): array
5550
}
5651

5752
private function mapRelationship(
58-
bool $minimal,
53+
bool $included,
5954
Request $request,
6055
Relationship $relationship
6156
): array {
62-
$resource = $relationship->toArray($request, $minimal);
57+
$resource = $relationship->toArray($request, $included);
6358

6459
if (isset($resource['included'])) {
6560
$this->with['included'] = array_merge(

src/Concerns/Schema.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Ark4ne\JsonApi\Resource\Concerns;
4+
5+
use Ark4ne\JsonApi\Resource\JsonApiCollection;
6+
use Ark4ne\JsonApi\Resource\Support\FakeModel;
7+
use Illuminate\Http\Request;
8+
9+
trait Schema
10+
{
11+
private static array $schemas = [];
12+
13+
public static function schema(Request $request = null): object
14+
{
15+
$request ??= new Request;
16+
17+
$resource = new static(new FakeModel);
18+
19+
if ($resource instanceof JsonApiCollection) {
20+
return $resource->collects::schema($request);
21+
}
22+
23+
if (isset(self::$schemas[static::class])) {
24+
return self::$schemas[static::class];
25+
}
26+
27+
$schema = (object)[
28+
'type' => null,
29+
'fields' => [],
30+
'relationships' => [],
31+
];
32+
33+
self::$schemas[static::class] = $schema;
34+
35+
$schema->type = $resource->toType($request);
36+
$schema->fields = array_keys($resource->toAttributes($request));
37+
38+
foreach ($resource->toRelationships($request) as $name => $relation) {
39+
$schema->relationships[$name] = $relation->getResource()::schema();
40+
}
41+
42+
return self::$schemas[static::class];
43+
}
44+
}

src/JsonApiCollection.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
class JsonApiCollection extends ResourceCollection implements Resourceable
1111
{
1212
use Concerns\Relationize,
13-
Concerns\ConditionallyLoadsAttributes,
13+
Concerns\Schema,
1414
Concerns\ToResponse;
1515

1616
public $collects;
@@ -23,25 +23,25 @@ class JsonApiCollection extends ResourceCollection implements Resourceable
2323
*
2424
* @return void
2525
*/
26-
public function __construct($resource, ?string $collects = null)
26+
final public function __construct($resource, ?string $collects = null)
2727
{
2828
$this->collects = $collects ?: $this->collects;
2929

3030
parent::__construct($resource);
3131
}
3232

33-
public function toArray($request, bool $minimal = false): array
33+
public function toArray($request, bool $included = true): array
3434
{
3535
$data = [];
3636

3737
$base = collect($this->with)->toArray();
3838
foreach ($this->collection as $resource) {
39-
$data[] = $resource->toArray($request, $minimal);
39+
$data[] = $resource->toArray($request, $included);
4040

4141
if ($resource instanceof JsonResource) {
4242
$with = collect($resource->with($request))->toArray();
4343

44-
if ($minimal) {
44+
if (!$included) {
4545
unset($with['included']);
4646
}
4747

src/JsonApiResource.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@
88
abstract class JsonApiResource extends JsonResource implements Resourceable
99
{
1010
use Concerns\Relationize,
11-
Concerns\ConditionallyLoadsAttributes,
1211
Concerns\Identifier,
1312
Concerns\Attributes,
1413
Concerns\Relationships,
1514
Concerns\Links,
1615
Concerns\Meta,
16+
Concerns\Schema,
1717
Concerns\ToResponse;
1818

19-
public function toArray($request, bool $minimal = false): array
19+
final public function __construct($resource)
20+
{
21+
parent::__construct($resource);
22+
}
23+
24+
public function toArray($request, bool $included = true): array
2025
{
2126
$data = [
2227
'id' => $this->toIdentifier($request),
2328
'type' => $this->toType($request),
2429
];
2530

26-
if (!$minimal) {
31+
if ($included) {
2732
$data += [
2833
'attributes' => $this->requestedAttributes($request),
2934
'relationships' => $this->requestedRelationships($request),

0 commit comments

Comments
 (0)