Skip to content

Commit a05802a

Browse files
[Feature] Serialize resources using schemas (#2)
Makes `JsonApiResource` non-abstract, by injecting the schema. This means writing a resource class for a specific resource type is now optional.
1 parent feaee1a commit a05802a

31 files changed

+857
-199
lines changed

CHANGELOG.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,54 @@
33
All notable changes to this project will be documented in this file. This project adheres to
44
[Semantic Versioning](http://semver.org/) and [this changelog format](http://keepachangelog.com/).
55

6+
## Unreleased
7+
8+
### Added
9+
- [#2](https://github.com/laravel-json-api/core/pull/2)
10+
**BREAKING** The `Core\Resources\JsonApiResource` is no longer abstract, and now expects the
11+
schema *and* the model to be injected via its constructor. It will use the schema to convert a
12+
model to a JSON:API resource. This allows the resource classes to be optional, as the resource
13+
resolution logic can now fall-back to the `JsonApiResource` when no specific resource class
14+
exists. Schema fields must implement the `Contracts\Resources\Serializer\Attribute`
15+
and `Contracts\Resources\Serializer\Relation` interfaces on their fields for the serialization
16+
to work.
17+
- **BREAKING** The `Contracts\Encoder\Encoder` contract now has a `withRequest` method to inject the
18+
current HTTP request into the encoding process. The response classes have been updated to pass
19+
the request through to the encoder in their `toResponse()` methods.
20+
- **BREAKING** The `Contracts\Schema\Container` contract now has a `schemaForModel` method to
21+
lookup a schema by providing either a model instance, or the fully-qualified class name of a model.
22+
- **BREAKING** The `Contracts\Schema\ID` contract now has a `key()` method, that can return
23+
the model key for the ID.
24+
- **BREAKING** The `Contracts\Schema\Schema` contract now has a `idKeyName()` method
25+
- New `Contracts\Resources\JsonApiRelation` contract for the relation object returned by the
26+
`JsonApiResource::relationships()` method. This has the methods on it that encoders can rely on when
27+
encoding the relationship to JSON.
28+
- New `Core\Resources\ConditionalIterator` class for iterating over values that could contain
29+
conditional attributes.
30+
31+
### Changed
32+
- **BREAKING** The `attributes`, `relationships`, `meta` and `links` method of the `JsonApiResource`
33+
class now require the request to be passed as a parameter. This is to bring the resource in line
34+
with Laravel's Eloquent resource, though our implementation allows the request to be `null` to
35+
cater for resource encoding outside of HTTP requests (e.g. queued broadcasting). Additionally,
36+
the `relationship` method return type has been changed to the new `Contracts\Resources\JsonApiResource`
37+
contract.
38+
- **BREAKING** The `exists` and `create` methods on the `Contracts\Resources\Container` contract now
39+
correctly type-hint the parameter as an `object`.
40+
- **BREAKING** The `createResource` method on the `Contracts\Resources\Factory` contract now correctly
41+
type-hints the parameter as an `object`.
42+
- **BREAKING** The constructor of the `Core\Resources\Factory` class now expects a schema container
43+
and an optional array of resource bindings (instead of an iterable). If a `null` value is provided
44+
for the bindings, the bindings will be retrieved from the schema container. Additionally, the protected
45+
`build` method signature has been updated to correctly type-hint the second argument as an `object`.
46+
- **BREAKING** The constructor arguments for the `Core\Resources\Relation` class have been changed
47+
so that it now receives the model and base URI - rather than the `JsonApiResource` object. This
48+
change was made so that it can be used more broadly.
49+
50+
### Removed
51+
- **BREAKING** The `attach` and `attachAll` methods of the `Core\Resources\Factory` class have been
52+
removed, because they were not in use.
53+
654
## [1.0.0-alpha.1] - 2021-01-25
755

856
Initial release.

src/Contracts/Encoder/Encoder.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,18 @@
1717

1818
namespace LaravelJsonApi\Contracts\Encoder;
1919

20+
use Illuminate\Http\Request;
2021
use LaravelJsonApi\Core\Resources\JsonApiResource;
2122

2223
interface Encoder
2324
{
25+
26+
/**
27+
* @param Request|null $request
28+
* @return $this
29+
*/
30+
public function withRequest($request): self;
31+
2432
/**
2533
* @param $includePaths
2634
* @return $this

src/Contracts/Resources/Container.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,32 @@ interface Container
2929
* Resolve the value to a resource object or a cursor of resource objects.
3030
*
3131
* @param mixed $value
32-
* a resource object, record or an iterable of records.
32+
* a resource object, model or an iterable of models.
3333
* @return JsonApiResource|Generator
3434
*/
3535
public function resolve($value);
3636

3737
/**
38-
* Can the provided record be converted to a resource object?
38+
* Can the provided model be converted to a resource object?
3939
*
40-
* @param mixed $record
40+
* @param object $model
4141
* @return bool
4242
*/
43-
public function exists($record): bool;
43+
public function exists(object $model): bool;
4444

4545
/**
46-
* Create a resource object for the supplied record.
46+
* Create a resource object for the supplied models.
4747
*
48-
* @param mixed $record
48+
* @param object $model
4949
* @return JsonApiResource
5050
*/
51-
public function create($record): JsonApiResource;
51+
public function create(object $model): JsonApiResource;
5252

5353
/**
54-
* Create resource objects for the supplied records.
54+
* Create resource objects for the supplied models.
5555
*
56-
* @param iterable $records
56+
* @param iterable $models
5757
* @return Generator
5858
*/
59-
public function cursor(iterable $records): Generator;
59+
public function cursor(iterable $models): Generator;
6060
}

src/Contracts/Resources/Factory.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ interface Factory
3232
public function handles(): iterable;
3333

3434
/**
35-
* Create a resource object for the supplied record.
35+
* Create a resource object for the supplied model.
3636
*
37-
* @param mixed $record
37+
* @param object $model
3838
* @return JsonApiResource
3939
*/
40-
public function createResource($record): JsonApiResource;
40+
public function createResource(object $model): JsonApiResource;
4141
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace LaravelJsonApi\Contracts\Resources;
21+
22+
use LaravelJsonApi\Core\Document\Links;
23+
24+
interface JsonApiRelation
25+
{
26+
27+
/**
28+
* Get the relation's JSON:API field name.
29+
*
30+
* @return string
31+
*/
32+
public function fieldName(): string;
33+
34+
/**
35+
* Get the value of the links member.
36+
*
37+
* @return Links
38+
*/
39+
public function links(): Links;
40+
41+
/**
42+
* Get the value of the meta member.
43+
*
44+
* @return array|null
45+
*/
46+
public function meta(): ?array;
47+
48+
/**
49+
* Get the value of the data member.
50+
*
51+
* @return mixed
52+
*/
53+
public function data();
54+
55+
/**
56+
* Should data always be shown?
57+
*
58+
* If this method returns `false`, the relationship's data will only be shown
59+
* if the client has requested it (via include paths). Returning `true` means
60+
* the relationship data will always be shown, regardless of what the client
61+
* has requested.
62+
*
63+
* @return bool
64+
*/
65+
public function showData(): bool;
66+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace LaravelJsonApi\Contracts\Resources\Serializer;
21+
22+
interface Attribute extends Hideable
23+
{
24+
25+
/**
26+
* Get the JSON:API field name for the serialized attribute.
27+
*
28+
* @return string
29+
*/
30+
public function serializedFieldName(): string;
31+
32+
/**
33+
* Get the JSON value from the provided model.
34+
*
35+
* @param object $model
36+
* @return mixed
37+
*/
38+
public function serialize(object $model);
39+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace LaravelJsonApi\Contracts\Resources\Serializer;
21+
22+
use Illuminate\Http\Request;
23+
24+
interface Hideable
25+
{
26+
27+
/**
28+
* Is the field hidden?
29+
*
30+
* @param Request|null $request
31+
* @return bool
32+
*/
33+
public function isHidden($request): bool;
34+
35+
/**
36+
* Is the field not hidden?
37+
*
38+
* @param Request|null $request
39+
* @return bool
40+
*/
41+
public function isNotHidden($request): bool;
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace LaravelJsonApi\Contracts\Resources\Serializer;
21+
22+
use LaravelJsonApi\Contracts\Resources\JsonApiRelation;
23+
24+
interface Relation extends Hideable
25+
{
26+
27+
/**
28+
* Get the JSON:API field name for the serialized relation.
29+
*
30+
* @return string
31+
*/
32+
public function serializedFieldName(): string;
33+
34+
/**
35+
* Get the JSON representation of the relationship.
36+
*
37+
* @param object $model
38+
* @param string $baseUri
39+
* @return JsonApiRelation
40+
*/
41+
public function serialize(object $model, string $baseUri): JsonApiRelation;
42+
}

src/Contracts/Schema/Container.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@ interface Container
2323
{
2424

2525
/**
26-
* Get a schema by JSON API resource type.
26+
* Get a schema by JSON:API resource type.
2727
*
2828
* @param string $resourceType
2929
* @return Schema
3030
*/
3131
public function schemaFor(string $resourceType): Schema;
3232

33+
/**
34+
* Get a schema for the provided model class.
35+
*
36+
* @param string|object $model
37+
* @return Schema
38+
*/
39+
public function schemaForModel($model): Schema;
40+
3341
/**
3442
* Does a schema exist for the supplied resource type?
3543
*

src/Contracts/Schema/Field.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface Field
2323
{
2424

2525
/**
26-
* The JSON API field name.
26+
* The JSON:API field name.
2727
*
2828
* @return string
2929
*/

0 commit comments

Comments
 (0)