-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NewResourceObject to allow omitting id in resources to-be-created (#108)
- Loading branch information
Showing
8 changed files
with
302 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
interface Attachable | ||
{ | ||
/** | ||
* Adds this object's data to $o | ||
* @param object $o | ||
* @internal | ||
*/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace JsonApiPhp\JsonApi\Internal; | ||
|
||
use function JsonApiPhp\JsonApi\isValidName; | ||
|
||
/** | ||
* Class BaseResource | ||
* @internal | ||
*/ | ||
class BaseResource implements Attachable | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
protected $type; | ||
protected $obj; | ||
protected $registry = []; | ||
|
||
public function __construct(string $type, ResourceMember ...$members) | ||
{ | ||
if (isValidName($type) === false) { | ||
throw new \DomainException("Invalid type value: $type"); | ||
} | ||
$this->obj = (object) ['type' => $type]; | ||
$this->type = $type; | ||
|
||
$this->addMembers(...$members); | ||
} | ||
|
||
/** | ||
* @param ResourceMember ...$members | ||
* @internal | ||
*/ | ||
protected function addMembers(ResourceMember ...$members): void | ||
{ | ||
$fields = []; | ||
foreach ($members as $member) { | ||
if ($member instanceof Identifier) { | ||
$member->registerIn($this->registry); | ||
} | ||
if ($member instanceof ResourceField) { | ||
$name = $member->name(); | ||
if (isset($fields[$name])) { | ||
throw new \LogicException("Field '$name' already exists'"); | ||
} | ||
$fields[$name] = true; | ||
} | ||
$member->attachTo($this->obj); | ||
} | ||
} | ||
|
||
/** | ||
* @param object $o | ||
* @internal | ||
*/ | ||
public function attachTo($o): void | ||
{ | ||
$o->data = $this->obj; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace JsonApiPhp\JsonApi; | ||
|
||
use JsonApiPhp\JsonApi\Internal\BaseResource; | ||
use JsonApiPhp\JsonApi\Internal\PrimaryData; | ||
use JsonApiPhp\JsonApi\Internal\ResourceMember; | ||
|
||
/** | ||
* A resource to-be-created on the server. Does not have the `id` yet. | ||
* | ||
* Class NewResourceObject | ||
*/ | ||
final class NewResourceObject extends BaseResource implements PrimaryData | ||
{ | ||
public function __construct(string $type, ResourceMember ...$members) | ||
{ | ||
parent::__construct($type, ...$members); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace JsonApiPhp\JsonApi\Test; | ||
|
||
use JsonApiPhp\JsonApi\Attribute; | ||
use JsonApiPhp\JsonApi\DataDocument; | ||
use JsonApiPhp\JsonApi\EmptyRelationship; | ||
use JsonApiPhp\JsonApi\Link\RelatedLink; | ||
use JsonApiPhp\JsonApi\Link\SelfLink; | ||
use JsonApiPhp\JsonApi\Meta; | ||
use JsonApiPhp\JsonApi\NewResourceObject; | ||
use JsonApiPhp\JsonApi\ResourceIdentifier; | ||
use JsonApiPhp\JsonApi\ResourceIdentifierCollection; | ||
use JsonApiPhp\JsonApi\ToMany; | ||
use JsonApiPhp\JsonApi\ToNull; | ||
use JsonApiPhp\JsonApi\ToOne; | ||
|
||
class NewResourceObjectTest extends BaseTestCase | ||
{ | ||
public function testFullFledgedResourceObject() | ||
{ | ||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "apples", | ||
"attributes": { | ||
"title": "Rails is Omakase" | ||
}, | ||
"meta": {"foo": "bar"}, | ||
"relationships": { | ||
"author": { | ||
"meta": {"foo": "bar"}, | ||
"data": null | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'apples', | ||
new Meta('foo', 'bar'), | ||
new Attribute('title', 'Rails is Omakase'), | ||
new ToNull( | ||
'author', | ||
new Meta('foo', 'bar') | ||
) | ||
) | ||
) | ||
); | ||
} | ||
|
||
public function testRelationshipWithSingleIdLinkage() | ||
{ | ||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "basket", | ||
"relationships": { | ||
"content": { | ||
"data": {"type": "apples", "id": "1"} | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'basket', | ||
new ToOne('content', new ResourceIdentifier('apples', '1')) | ||
) | ||
) | ||
); | ||
} | ||
|
||
public function testRelationshipWithMultiIdLinkage() | ||
{ | ||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "basket", | ||
"relationships": { | ||
"content": { | ||
"data": [{ | ||
"type": "apples", | ||
"id": "1" | ||
},{ | ||
"type": "pears", | ||
"id": "2" | ||
}] | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'basket', | ||
new ToMany( | ||
'content', | ||
new ResourceIdentifierCollection( | ||
new ResourceIdentifier('apples', '1'), | ||
new ResourceIdentifier('pears', '2') | ||
) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
|
||
public function testRelationshipWithEmptyMultiIdLinkage() | ||
{ | ||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "basket", | ||
"relationships": { | ||
"content": { | ||
"data": [] | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'basket', | ||
new ToMany('content', new ResourceIdentifierCollection()) | ||
) | ||
) | ||
); | ||
} | ||
|
||
public function testRelationshipWithNoData() | ||
{ | ||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "basket", | ||
"relationships": { | ||
"empty": { | ||
"links": { | ||
"related": "/foo" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'basket', | ||
new EmptyRelationship('empty', new RelatedLink('/foo')) | ||
) | ||
) | ||
); | ||
|
||
$this->assertEncodesTo( | ||
' | ||
{ | ||
"data": { | ||
"type": "basket", | ||
"relationships": { | ||
"empty": { | ||
"links": { | ||
"related": "/foo", | ||
"self": "/bar" | ||
}, | ||
"meta": { | ||
"foo": "bar" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
', | ||
new DataDocument( | ||
new NewResourceObject( | ||
'basket', | ||
new EmptyRelationship('empty', new RelatedLink('/foo'), new SelfLink('/bar'), new Meta('foo', 'bar')) | ||
) | ||
) | ||
); | ||
} | ||
|
||
public function testResourceFieldsMustBeUnique() | ||
{ | ||
$this->expectException(\LogicException::class); | ||
$this->expectExceptionMessage("Field 'foo' already exists"); | ||
new NewResourceObject( | ||
'apples', | ||
new Attribute('foo', 'bar'), | ||
new ToOne('foo', new ResourceIdentifier('apples', '1')) | ||
); | ||
} | ||
|
||
public function testNameValidation() | ||
{ | ||
$this->expectException(\DomainException::class); | ||
new NewResourceObject('invalid:id'); | ||
} | ||
} |