Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions docs/basics/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ for Eloquent models. The relationship types available are `belongsTo`, `hasOne`,
| Eloquent | JSON API |
| :-- | :-- |
| `hasOne` | `hasOne` |
| `hasOneThrough` | `hasOneThrough` |
| `belongsTo` | `belongsTo` |
| `hasMany` | `hasMany` |
| `belongsToMany` | `hasMany` |
Expand Down Expand Up @@ -338,15 +339,16 @@ class Adapter extends AbstractAdapter
}
```

#### Has-Many-Through
#### Has-One-Through and Has-Many-Through

The JSON API `hasManyThrough` relation can be used for an Eloquent `hasManyThrough` relation. The important thing
to note about this relationship is it is **read-only**. This is because the relationship can be modified in your API
by modifying the intermediary model. For example, a `countries` resource might have many `posts` resources through
an intermediate `users` resource. The relationship is effectively modified by creating and deleting posts and/or a
user changing which country they are associated to.
The JSON API `hasOneThrough` and `hasManyThrough` relations can be used for an Eloquent `hasOneThrough`
and `hasManyThrough` relation. The important thing to note about these relationships is that both are **read-only**.
This is because the relationship can be modified in your API by modifying the intermediary model.
For example, a `countries` resource might have many `posts` resources through an intermediate `users` resource.
The relationship is effectively modified by creating and deleting posts and/or a user changing which country they
are associated to.

Define a has-many-through relationship on an adapter as follows:
Use the `hasOneThrough()` or `hasManyThrough()` methods on your adapter as follows:

```php
class Adapter extends AbstractAdapter
Expand Down
9 changes: 9 additions & 0 deletions src/Eloquent/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,15 @@ protected function hasOne($modelKey = null)
return new HasOne($modelKey ?: $this->guessRelation());
}

/**
* @param string|null $modelKey
* @return HasOneThrough
*/
protected function hasOneThrough($modelKey = null)
{
return new HasOneThrough($modelKey ?: $this->guessRelation());
}

/**
* @param string|null $modelKey
* @return HasMany
Expand Down
50 changes: 50 additions & 0 deletions src/Eloquent/HasOneThrough.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Copyright 2019 Cloud Creativity Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace CloudCreativity\LaravelJsonApi\Eloquent;

use CloudCreativity\LaravelJsonApi\Exceptions\RuntimeException;
use Illuminate\Database\Eloquent\Relations;
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;

class HasOneThrough extends BelongsTo
{

/**
* @inheritDoc
*/
public function update($record, array $relationship, EncodingParametersInterface $parameters)
{
throw new RuntimeException('Modifying a has-one-through Eloquent relation is not supported.');
}

/**
* @inheritDoc
*/
public function replace($record, array $relationship, EncodingParametersInterface $parameters)
{
throw new RuntimeException('Modifying a has-one-through Eloquent relation is not supported.');
}

/**
* @inheritdoc
*/
protected function acceptRelation($relation)
{
return $relation instanceof Relations\HasOneThrough;
}
}
23 changes: 23 additions & 0 deletions tests/dummy/app/History.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace DummyApp;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class History extends Model
{

/**
* @var array
*/
protected $fillable = ['detail'];

/**
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
43 changes: 43 additions & 0 deletions tests/dummy/app/JsonApi/Histories/Adapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Copyright 2019 Cloud Creativity Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace DummyApp\JsonApi\Histories;

use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use DummyApp\History;
use Illuminate\Support\Collection;

class Adapter extends AbstractAdapter
{

/**
* Adapter constructor.
*/
public function __construct()
{
parent::__construct(new History());
}

/**
* @inheritDoc
*/
protected function filter($query, Collection $filters)
{
// TODO: Implement filter() method.
}

}
55 changes: 55 additions & 0 deletions tests/dummy/app/JsonApi/Histories/Schema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace DummyApp\JsonApi\Histories;

use DummyApp\History;
use Neomerx\JsonApi\Schema\SchemaProvider;

class Schema extends SchemaProvider
{

/**
* @var string
*/
protected $resourceType = 'histories';

/**
* @param History $resource
* @return string
*/
public function getId($resource)
{
return (string) $resource->getRouteKey();
}

/**
* @param History $resource
* @return array
*/
public function getAttributes($resource)
{
return ['detail' => $resource->detail];
}

/**
* @param History $resource
* @param bool $isPrimary
* @param array $includeRelationships
* @return array
*/
public function getRelationships($resource, $isPrimary, array $includeRelationships)
{
return [
'user' => [
self::SHOW_SELF => false,
self::SHOW_RELATED => false,
self::SHOW_DATA => isset($includeRelationships['user']),
self::DATA => static function () use ($resource) {
return $resource->user;
},
],
];
}


}
56 changes: 56 additions & 0 deletions tests/dummy/app/JsonApi/Histories/Validators.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* Copyright 2019 Cloud Creativity Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace DummyApp\JsonApi\Histories;

use CloudCreativity\LaravelJsonApi\Validation\AbstractValidators;

class Validators extends AbstractValidators
{

/**
* @var array
*/
protected $allowedIncludePaths = ['user'];

/**
* @var array
*/
protected $allowedSortParameters = [
'created-at',
'updated-at',
];

/**
* @inheritDoc
*/
protected function rules($record = null): array
{
return [
'detail' => ['required', 'string'],
];
}

/**
* @inheritDoc
*/
protected function queryRules(): array
{
return [];
}

}
52 changes: 52 additions & 0 deletions tests/dummy/app/JsonApi/Suppliers/Adapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* Copyright 2019 Cloud Creativity Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace DummyApp\JsonApi\Suppliers;

use CloudCreativity\LaravelJsonApi\Eloquent\AbstractAdapter;
use CloudCreativity\LaravelJsonApi\Eloquent\HasOneThrough;
use DummyApp\Supplier;
use Illuminate\Support\Collection;

class Adapter extends AbstractAdapter
{

/**
* Adapter constructor.
*/
public function __construct()
{
parent::__construct(new Supplier());
}

/**
* @return HasOneThrough
*/
protected function userHistory(): HasOneThrough
{
return $this->hasOneThrough();
}

/**
* @inheritDoc
*/
protected function filter($query, Collection $filters)
{
// TODO: Implement filter() method.
}

}
Loading