Skip to content

[Feature] Serialize resources using schemas #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 2, 2021
Prev Previous commit
Next Next commit
Add changelog and some tidying up
  • Loading branch information
lindyhopchris committed Jan 30, 2021
commit e866b9e94db09e04451a47cf84ac545405422f40
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,48 @@
All notable changes to this project will be documented in this file. This project adheres to
[Semantic Versioning](http://semver.org/) and [this changelog format](http://keepachangelog.com/).

## Unreleased

### Added
- [#2](https://github.com/laravel-json-api/core/pull/2)
A new `Core\Resources\SchemaResource` uses a schema to convert a model to a JSON:API resource.
This allows the resource classes to be optional, as the resource resolution logic will now
fall-back to the `SchemaResource` when no resource class exists. Schemas must implement
the `Contracts\Resources\Serializer\Attribute` and `Contracts\Resources\Serializer\Relation`
interfaces on their fields for the serialization to work.
- **BREAKING** The `Contracts\Encoder\Encoder` contract now has a `withRequest` method to inject the
current HTTP request into the encoding process. The response classes have been updated to pass
the request through to the encoder in their `toResponse()` methods.
- **BREAKING** The `Contracts\Schema\Container` contract now has a `schemaForModel` method to
lookup a schema by providing either a model instance, or the fully-qualified class name of a model.
- New `Contracts\Resources\JsonApiRelation` contract for the relation object returned by the
`JsonApiResource::relationships()` method. This has the methods on it that encoders can rely on when
encoding the relationship to JSON.
- New `Core\Resources\ConditionalIterator` class for iterating over values that could contain
conditional attributes.

### Changed
- **BREAKING** The `attributes`, `relationships`, `meta` and `links` method of the `JsonApiResource`
class now require the request to be passed as a parameter. This is to bring the resource in line
with Laravel's Eloquent resource, though our implementation allows the request to be `null` to
cater for resource encoding outside of HTTP requests (e.g. queued broadcasting). Additionally,
the `relationship` method return type has been changed to the new `Contracts\Resources\JsonApiResource`
contract.
- **BREAKING** The `exists` and `create` methods on the `Contracts\Resources\Container` contract now
correctly type-hint the parameter as an `object`.
- **BREAKING** The `createResource` method on the `Contracts\Resources\Factory` contract now correctly
type-hints the parameter as an `object`.
- **BREAKING** The constructor of the `Core\Resources\Factory` class now expects an array of resource
bindings, instead of an iterable. The protected `build` method signature has been updated to
correctly type-hint the second argument as an `object`.
- **BREAKING** The constructor arguments for the `Core\Resources\Relation` class have been changed
so that it now receives the model and base URI - rather than the `JsonApiResource` object. This
change was made so that it can be used more broadly.

### Removed
- **BREAKING** The `attach` and `attachAll` methods of the `Core\Resources\Factory` class have been
removed, because they were not in use.

## [1.0.0-alpha.1] - 2021-01-25

Initial release.
20 changes: 10 additions & 10 deletions src/Contracts/Resources/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,32 @@ interface Container
* Resolve the value to a resource object or a cursor of resource objects.
*
* @param mixed $value
* a resource object, record or an iterable of records.
* a resource object, model or an iterable of models.
* @return JsonApiResource|Generator
*/
public function resolve($value);

/**
* Can the provided record be converted to a resource object?
* Can the provided model be converted to a resource object?
*
* @param object $record
* @param object $model
* @return bool
*/
public function exists(object $record): bool;
public function exists(object $model): bool;

/**
* Create a resource object for the supplied record.
* Create a resource object for the supplied models.
*
* @param object $record
* @param object $model
* @return JsonApiResource
*/
public function create(object $record): JsonApiResource;
public function create(object $model): JsonApiResource;

/**
* Create resource objects for the supplied records.
* Create resource objects for the supplied models.
*
* @param iterable $records
* @param iterable $models
* @return Generator
*/
public function cursor(iterable $records): Generator;
public function cursor(iterable $models): Generator;
}
14 changes: 7 additions & 7 deletions src/Core/Resources/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,27 @@ public function resolve($value)
/**
* @inheritDoc
*/
public function exists(object $record): bool
public function exists(object $model): bool
{
return isset($this->bindings[get_class($record)]);
return isset($this->bindings[get_class($model)]);
}

/**
* @inheritDoc
*/
public function create(object $record): JsonApiResource
public function create(object $model): JsonApiResource
{
return $this->factoryFor($record)->createResource(
$record
return $this->factoryFor($model)->createResource(
$model
);
}

/**
* @inheritDoc
*/
public function cursor(iterable $records): Generator
public function cursor(iterable $models): Generator
{
foreach ($records as $record) {
foreach ($models as $record) {
if ($record instanceof JsonApiResource) {
yield $record;
continue;
Expand Down
6 changes: 3 additions & 3 deletions src/Core/Resources/DefaultFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ public function createResource(object $model): JsonApiResource
* Build a new resource object instance.
*
* @param Schema $schema
* @param object $record
* @param object $model
* @return JsonApiResource
*/
protected function build(Schema $schema, object $record): JsonApiResource
protected function build(Schema $schema, object $model): JsonApiResource
{
$fqn = $this->class;

return new $fqn($schema, $record);
return new $fqn($schema, $model);
}

}
6 changes: 3 additions & 3 deletions src/Core/Resources/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ public function createResource(object $model): JsonApiResource
* Build a new resource object instance.
*
* @param string $fqn
* @param object $record
* @param object $model
* @return JsonApiResource
*/
protected function build(string $fqn, object $record): JsonApiResource
protected function build(string $fqn, object $model): JsonApiResource
{
return new $fqn($record);
return new $fqn($model);
}

}
4 changes: 2 additions & 2 deletions src/Core/Resources/JsonApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ protected function identifierMeta(): array
*
* @param string $fieldName
* @param string|null $keyName
* @return JsonApiRelation
* @return Relation
*/
protected function relation(string $fieldName, string $keyName = null): JsonApiRelation
protected function relation(string $fieldName, string $keyName = null): Relation
{
return new Relation(
$this->resource,
Expand Down
40 changes: 20 additions & 20 deletions src/Core/Resources/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ public function relatedUrl(): string
/**
* Use the field-name as-is for relationship URLs.
*
* @return JsonApiRelation
* @return $this
*/
public function retainFieldName(): JsonApiRelation
public function retainFieldName(): self
{
$this->uriName = $this->fieldName();

Expand All @@ -212,9 +212,9 @@ public function retainFieldName(): JsonApiRelation
* Use the provided string as the URI fragment for the field name.
*
* @param string $uri
* @return JsonApiRelation
* @return $this
*/
public function withUriFieldName(string $uri): JsonApiRelation
public function withUriFieldName(string $uri): self
{
if (empty($uri)) {
throw new InvalidArgumentException('Expecting a non-empty string URI fragment.');
Expand All @@ -226,29 +226,29 @@ public function withUriFieldName(string $uri): JsonApiRelation
}

/**
* @return JsonApiRelation
* @return $this
*/
public function withoutSelfLink(): JsonApiRelation
public function withoutSelfLink(): self
{
$this->showSelf = false;

return $this;
}

/**
* @return JsonApiRelation
* @return $this
*/
public function withoutRelatedLink(): JsonApiRelation
public function withoutRelatedLink(): self
{
$this->showRelated = false;

return $this;
}

/**
* @return JsonApiRelation
* @return $this
*/
public function withoutLinks(): JsonApiRelation
public function withoutLinks(): self
{
$this->withoutSelfLink();
$this->withoutRelatedLink();
Expand All @@ -258,9 +258,9 @@ public function withoutLinks(): JsonApiRelation

/**
* @param mixed $data
* @return JsonApiRelation
* @return $this
*/
public function withData($data): JsonApiRelation
public function withData($data): self
{
$this->data = $data;
$this->hasData = true;
Expand All @@ -271,9 +271,9 @@ public function withData($data): JsonApiRelation
/**
* Always show the data member of the relation.
*
* @return JsonApiRelation
* @return $this
*/
public function alwaysShowData(): JsonApiRelation
public function alwaysShowData(): self
{
$this->showData = true;

Expand All @@ -283,9 +283,9 @@ public function alwaysShowData(): JsonApiRelation
/**
* Always show the data member of the relation if it is loaded on the model.
*
* @return JsonApiRelation
* @return $this
*/
public function showDataIfLoaded(): JsonApiRelation
public function showDataIfLoaded(): self
{
if (method_exists($this->resource, 'relationLoaded')) {
$this->showData = $this->resource->relationLoaded($this->keyName);
Expand All @@ -297,9 +297,9 @@ public function showDataIfLoaded(): JsonApiRelation

/**
* @param $meta
* @return JsonApiRelation
* @return $this
*/
public function withMeta($meta): JsonApiRelation
public function withMeta($meta): self
{
if (!is_array($meta) && !$meta instanceof Closure) {
throw new InvalidArgumentException('Expecting meta to be an array or a closure.');
Expand All @@ -313,9 +313,9 @@ public function withMeta($meta): JsonApiRelation
/**
* Mark the relation as required for validation.
*
* @return JsonApiRelation
* @return $this
*/
public function mustValidate(): JsonApiRelation
public function mustValidate(): self
{
$this->validated = true;

Expand Down