Skip to content

Commit

Permalink
Merge pull request #45 from swisnl/feature/improve-relations
Browse files Browse the repository at this point in the history
Refactor relations
  • Loading branch information
JaZo authored Jan 22, 2019
2 parents 5270798 + 7c6eb7c commit b8d1ae8
Show file tree
Hide file tree
Showing 16 changed files with 204 additions and 275 deletions.
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

* Nothing
This release includes changes to some interfaces. This is a breaking change if you use these interfaces in your own code.

### Added

* Added `OneRelationInterface` and `ManyRelationInterface` to differentiate between singular and plural relations.

### Changed

* Moved `setType` and `getType` from `RelationInterface` to a separate interface; `TypedRelationInterface`.
* Added type hints to `ItemInterface::setRelation`.
* Added return type hint to `Item::hasAttribute`.

### Removed

* Removed `RelationInterface` in favor of `OneRelationInterface` and `ManyRelationInterface`.
* Removed `setId` and `getId` from `HasOneRelation` and `MorphToRelation`. These operations should be performed on the included item.
* Removed `setType` and `getType` from morph relations. Use regular relations if you want to set the type.

## [0.13.0] - 2019-01-14

Expand Down
8 changes: 3 additions & 5 deletions src/Interfaces/ItemInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,16 @@ public function getAvailableRelations(): array;
/**
* Set the specific relationship in the model.
*
* @param string $relation
* @param mixed $value
* @param string $relation
* @param DataInterface $value
*
* @return static
*/
public function setRelation($relation, $value);
public function setRelation(string $relation, DataInterface $value);

/**
* @TODO: MEGA TODO. Set up a serializer for the Item so that we can remove this, getRelationships etc
*
* @throws \Exception
*
* @return \Swis\JsonApi\Client\Collection
*/
public function getIncluded();
Expand Down
42 changes: 42 additions & 0 deletions src/Interfaces/ManyRelationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Swis\JsonApi\Client\Interfaces;

use Swis\JsonApi\Client\Collection;

interface ManyRelationInterface
{
/**
* @param \Swis\JsonApi\Client\Collection $included
*
* @return static
*/
public function associate(Collection $included);

/**
* @return static
*/
public function dissociate();

/**
* @return bool
*/
public function hasIncluded(): bool;

/**
* @return \Swis\JsonApi\Client\Collection
*/
public function getIncluded(): Collection;

/**
* @param bool $omitIncluded
*
* @return static
*/
public function setOmitIncluded(bool $omitIncluded);

/**
* @return bool
*/
public function shouldOmitIncluded(): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,39 @@

namespace Swis\JsonApi\Client\Interfaces;

interface RelationInterface
interface OneRelationInterface
{
/**
* @return string
*/
public function getType(): string;

/**
* @param string $type
*
* @return static
*/
public function setType(string $type);

/**
* @param \Swis\JsonApi\Client\Interfaces\DataInterface $included
* @param \Swis\JsonApi\Client\Interfaces\ItemInterface $included
*
* @return static
*/
public function associate(DataInterface $included);
public function associate(ItemInterface $included);

/**
* @return static
*/
public function dissociate();

/**
* @return \Swis\JsonApi\Client\Collection|\Swis\JsonApi\Client\Interfaces\DataInterface|\Swis\JsonApi\Client\Interfaces\ItemInterface|null
*/
public function getIncluded();

/**
* @return bool
*/
public function hasIncluded(): bool;

/**
* @return bool
* @return \Swis\JsonApi\Client\Interfaces\ItemInterface|null
*/
public function shouldOmitIncluded(): bool;
public function getIncluded();

/**
* @param bool $omitIncluded
*
* @return static
*/
public function setOmitIncluded(bool $omitIncluded);

/**
* @return bool
*/
public function shouldOmitIncluded(): bool;
}
18 changes: 18 additions & 0 deletions src/Interfaces/TypedRelationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Swis\JsonApi\Client\Interfaces;

interface TypedRelationInterface
{
/**
* @return string
*/
public function getType(): string;

/**
* @param string $type
*
* @return static
*/
public function setType(string $type);
}
94 changes: 33 additions & 61 deletions src/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Swis\JsonApi\Client;

use Jenssegers\Model\Model;
use Swis\JsonApi\Client\Interfaces\DataInterface;
use Swis\JsonApi\Client\Interfaces\ItemInterface;
use Swis\JsonApi\Client\Interfaces\RelationInterface;
use Swis\JsonApi\Client\Interfaces\ManyRelationInterface;
use Swis\JsonApi\Client\Interfaces\OneRelationInterface;
use Swis\JsonApi\Client\Relations\HasManyRelation;
use Swis\JsonApi\Client\Relations\HasOneRelation;
use Swis\JsonApi\Client\Relations\MorphToManyRelation;
Expand All @@ -23,14 +25,14 @@ class Item extends Model implements ItemInterface
protected $id;

/**
* Contains the initial values (Which fields are pre-filled on CREATE-form).
* Contains the initial values.
*
* @var array
*/
protected $initial = [];

/**
* @var \Swis\JsonApi\Client\Interfaces\RelationInterface[]
* @var \Swis\JsonApi\Client\Interfaces\OneRelationInterface[]|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface[]
*/
protected $relationships = [];

Expand Down Expand Up @@ -135,30 +137,8 @@ public function getRelationships(): array
{
$relationships = [];

/** @var \Swis\JsonApi\Client\Interfaces\RelationInterface $relationship */
foreach ($this->relationships as $name => $relationship) {
if ($relationship instanceof HasOneRelation) {
$relationships[$name] = ['data' => null];

if ($relationship->getIncluded() !== null) {
$relationships[$name] = [
'data' => [
'type' => $relationship->getType(),
'id' => $relationship->getId(),
],
];
}
} elseif ($relationship instanceof HasManyRelation) {
$relationships[$name]['data'] = [];

foreach ($relationship->getIncluded() as $item) {
$relationships[$name]['data'][] =
[
'type' => $relationship->getType(),
'id' => $item->getId(),
];
}
} elseif ($relationship instanceof MorphToRelation) {
if ($relationship instanceof OneRelationInterface) {
$relationships[$name] = ['data' => null];

if ($relationship->getIncluded() !== null) {
Expand All @@ -169,7 +149,7 @@ public function getRelationships(): array
],
];
}
} elseif ($relationship instanceof MorphToManyRelation) {
} elseif ($relationship instanceof ManyRelationInterface) {
$relationships[$name]['data'] = [];

foreach ($relationship->getIncluded() as $item) {
Expand All @@ -188,8 +168,6 @@ public function getRelationships(): array
/**
* @TODO: MEGA TODO. Set up a serializer for the Item so that we can remove this, getRelationships etc
*
* @throws \Exception
*
* @return \Swis\JsonApi\Client\Collection
*/
public function getIncluded(): Collection
Expand All @@ -201,23 +179,22 @@ public function getIncluded(): Collection
continue;
}

$includedFromRelationship = $relationship->getIncluded();
if ($includedFromRelationship instanceof ItemInterface) {
if ($includedFromRelationship->canBeIncluded()) {
$included->push($includedFromRelationship->toJsonApiArray());
if ($relationship instanceof OneRelationInterface) {
/** @var \Swis\JsonApi\Client\Interfaces\ItemInterface $item */
$item = $relationship->getIncluded();
if ($item->canBeIncluded()) {
$included->push($item->toJsonApiArray());
}
$included = $included->merge($includedFromRelationship->getIncluded());
} elseif ($includedFromRelationship instanceof Collection) {
$includedFromRelationship->each(
$included = $included->merge($item->getIncluded());
} elseif ($relationship instanceof ManyRelationInterface) {
$relationship->getIncluded()->each(
function (ItemInterface $item) use (&$included) {
if ($item->canBeIncluded()) {
$included->push($item->toJsonApiArray());
}
$included = $included->merge($item->getIncluded());
}
);
} else {
throw new \Exception('Not yet implemented');
}
}

Expand Down Expand Up @@ -269,7 +246,7 @@ public function getAttribute($key)
*
* @return bool
*/
public function hasAttribute($key)
public function hasAttribute($key): bool
{
return array_key_exists($key, $this->attributes);
}
Expand All @@ -279,7 +256,7 @@ public function hasAttribute($key)
*
* @param string $key
*
* @return \Swis\JsonApi\Client\Interfaces\DataInterface
* @return \Swis\JsonApi\Client\Interfaces\DataInterface|null
*/
public function getRelationValue($key)
{
Expand All @@ -295,6 +272,8 @@ public function getRelationValue($key)
if ($this->hasRelationship($key)) {
return $this->getRelationship($key)->getIncluded();
}

return null;
}

/**
Expand All @@ -306,18 +285,15 @@ public function getRelationValue($key)
*/
public function __isset($key)
{
$result = (isset($this->attributes[$key]) || isset($this->relationships[snake_case($key)])) ||
($this->hasGetMutator($key) && !is_null($this->getAttributeValue($key)));

return $result;
return parent::__isset($key) || $this->hasRelationship($key) || $this->hasRelationship(snake_case($key));
}

/**
* @param $name
* @param string $name
*
* @return \Swis\JsonApi\Client\Interfaces\RelationInterface
* @return \Swis\JsonApi\Client\Interfaces\OneRelationInterface|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface
*/
public function getRelationship(string $name): RelationInterface
public function getRelationship(string $name)
{
return $this->relationships[$name];
}
Expand Down Expand Up @@ -355,10 +331,9 @@ public function removeRelationship(string $name)
public function hasOne(string $class, string $relationName = null)
{
$relationName = $relationName ?: snake_case(debug_backtrace()[1]['function']);
$itemType = (new $class())->getType();

if (!array_key_exists($relationName, $this->relationships)) {
$this->relationships[$relationName] = new HasOneRelation($itemType);
$this->relationships[$relationName] = new HasOneRelation((new $class())->getType());
}

return $this->relationships[$relationName];
Expand All @@ -375,10 +350,9 @@ public function hasOne(string $class, string $relationName = null)
public function hasMany(string $class, string $relationName = null)
{
$relationName = $relationName ?: snake_case(debug_backtrace()[1]['function']);
$itemType = (new $class())->getType();

if (!array_key_exists($relationName, $this->relationships)) {
$this->relationships[$relationName] = new HasManyRelation($itemType);
$this->relationships[$relationName] = new HasManyRelation((new $class())->getType());
}

return $this->relationships[$relationName];
Expand Down Expand Up @@ -481,24 +455,22 @@ public function getAvailableRelations(): array
}

/**
* Set the specific relationship in the model.
* Set the specific relationship on the model.
*
* @param string $relation
* @param mixed $value
* @param string $relation
* @param \Swis\JsonApi\Client\Interfaces\DataInterface $value
*
* @return static
*/
public function setRelation($relation, $value)
public function setRelation(string $relation, DataInterface $value)
{
if (method_exists($this, $relation)) {
/** @var \Swis\JsonApi\Client\Interfaces\RelationInterface $relationObject */
/** @var \Swis\JsonApi\Client\Interfaces\OneRelationInterface|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface $relationObject */
$relationObject = $this->$relation();
} elseif ($value instanceof Collection) {
$relationObject = $this->morphToMany(snake_case($relation));
} else {
if ($value instanceof Collection) {
$relationObject = $this->morphToMany(snake_case($relation));
} else {
$relationObject = $this->morphTo(snake_case($relation));
}
$relationObject = $this->morphTo(snake_case($relation));
}

$relationObject->associate($value);
Expand Down
Loading

0 comments on commit b8d1ae8

Please sign in to comment.