From 1f42e314038b27e34f6c2b8dcdb76146cce89511 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 13:11:45 -0800 Subject: [PATCH 01/26] Added a benchmark --- test/benchmarks/compound10k.php | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 test/benchmarks/compound10k.php diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php new file mode 100644 index 0000000..048d041 --- /dev/null +++ b/test/benchmarks/compound10k.php @@ -0,0 +1,79 @@ +identifier())) + ); + + $document = new CompoundDocument( + new ResourceObjectSet( + new ResourceObject( + 'articles', + '1', + new Attribute('title', 'JSON API paints my bikeshed!'), + new SelfLink(new Url('http://example.com/articles/1')), + new Relationship( + 'author', + new SingleLinkage($dan->identifier()), + new SelfLink(new Url('http://example.com/articles/1/relationships/author')), + new RelatedLink(new Url('http://example.com/articles/1/author')) + ), + new Relationship( + 'comments', + new MultiLinkage( + $comment05->identifier(), + $comment12->identifier() + ), + new SelfLink(new Url('http://example.com/articles/1/relationships/comments')), + new RelatedLink(new Url('http://example.com/articles/1/comments')) + ) + ) + ), + new Included($dan, $comment05, $comment12), + new SelfLink(new Url('http://example.com/articles')), + new NextLink(new Url('http://example.com/articles?page[offset]=2')), + new LastLink(new Url('http://example.com/articles?page[offset]=10')) + ); + + $json = json_encode($document); +} From 5d65a8e5f830352d660b36674dc64afdca956df8 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 13:58:47 -0800 Subject: [PATCH 02/26] Performance improvements --- src/AttachableValue.php | 11 ++++++-- src/CompoundDocument.php | 11 ++++++-- src/DataDocument.php | 11 ++++++-- src/Error.php | 11 ++++++-- src/ErrorDocument.php | 11 ++++++-- src/JsonSerializableValue.php | 21 -------------- src/Link/LinkObject.php | 15 ++++++---- src/Link/Url.php | 13 ++++++--- src/MetaDocument.php | 11 ++++++-- src/PrimaryData/ResourceField.php | 2 +- src/ResourceObject.php | 34 ++++++++++------------- test/benchmarks/compound10k.php | 46 ++++++++++++++++++++++++++++--- 12 files changed, 130 insertions(+), 67 deletions(-) delete mode 100644 src/JsonSerializableValue.php diff --git a/src/AttachableValue.php b/src/AttachableValue.php index 0899519..774ccb2 100644 --- a/src/AttachableValue.php +++ b/src/AttachableValue.php @@ -5,18 +5,25 @@ /** * @internal */ -class AttachableValue extends JsonSerializableValue implements Attachable +class AttachableValue implements Attachable, \JsonSerializable { private $key; + private $value; public function __construct(string $key, $value) { - parent::__construct($value); + //parent::__construct($value); $this->key = $key; + $this->value = $value; } public function attachTo(object $o) { $o->{$this->key} = $this; } + + public function jsonSerialize() + { + return $this->value; + } } diff --git a/src/CompoundDocument.php b/src/CompoundDocument.php index fe6b31e..66e50bf 100644 --- a/src/CompoundDocument.php +++ b/src/CompoundDocument.php @@ -4,8 +4,10 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class CompoundDocument extends JsonSerializableValue +final class CompoundDocument implements \JsonSerializable { + private $doc; + public function __construct(PrimaryData $data, Included $included, DataDocumentMember ...$members) { foreach ($included as $resource) { @@ -19,6 +21,11 @@ public function __construct(PrimaryData $data, Included $included, DataDocumentM } throw new \DomainException('Full linkage required for '.json_encode($resource->identifier())); } - parent::__construct(combine($data, $included, ...$members)); + $this->doc = combine($data, $included, ...$members); + } + + public function jsonSerialize() + { + return $this->doc; } } diff --git a/src/DataDocument.php b/src/DataDocument.php index 64b4e31..130ff86 100644 --- a/src/DataDocument.php +++ b/src/DataDocument.php @@ -4,10 +4,17 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class DataDocument extends JsonSerializableValue +final class DataDocument implements \JsonSerializable { + private $value; + public function __construct(PrimaryData $data, DataDocumentMember ...$members) { - parent::__construct(combine($data, ...$members)); + $this->value = combine($data, ...$members); + } + + public function jsonSerialize() + { + return $this->value; } } diff --git a/src/Error.php b/src/Error.php index 501262a..dde99ff 100644 --- a/src/Error.php +++ b/src/Error.php @@ -4,15 +4,22 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; -final class Error extends JsonSerializableValue implements ErrorDocumentMember +final class Error implements \JsonSerializable, ErrorDocumentMember { + private $error; + public function __construct(ErrorMember ...$members) { - parent::__construct(combine(...$members)); + $this->error = combine(...$members); } public function attachTo(object $o) { $o->errors[] = $this; } + + public function jsonSerialize() + { + return $this->error; + } } diff --git a/src/ErrorDocument.php b/src/ErrorDocument.php index 6b31c40..84a5624 100644 --- a/src/ErrorDocument.php +++ b/src/ErrorDocument.php @@ -2,10 +2,17 @@ namespace JsonApiPhp\JsonApi; -final class ErrorDocument extends JsonSerializableValue +final class ErrorDocument implements \JsonSerializable { + private $doc; + public function __construct(Error $error, ErrorDocumentMember ...$members) { - parent::__construct(combine($error, ...$members)); + $this->doc = combine($error, ...$members); + } + + public function jsonSerialize() + { + return $this->doc; } } diff --git a/src/JsonSerializableValue.php b/src/JsonSerializableValue.php deleted file mode 100644 index 5784c9f..0000000 --- a/src/JsonSerializableValue.php +++ /dev/null @@ -1,21 +0,0 @@ -value = $value; - } - - public function jsonSerialize() - { - return $this->value; - } -} diff --git a/src/Link/LinkObject.php b/src/Link/LinkObject.php index 426aadf..7303088 100644 --- a/src/Link/LinkObject.php +++ b/src/Link/LinkObject.php @@ -2,19 +2,24 @@ namespace JsonApiPhp\JsonApi\Link; -use JsonApiPhp\JsonApi\JsonSerializableValue; use JsonApiPhp\JsonApi\Meta; -final class LinkObject extends JsonSerializableValue implements Link +final class LinkObject implements \JsonSerializable, Link { + private $link; + public function __construct(string $href, Meta $meta = null) { - $link = (object) [ + $this->link = (object) [ 'href' => $href, ]; if ($meta) { - $meta->attachTo($link); + $meta->attachTo($this->link); } - parent::__construct($link); + } + + public function jsonSerialize() + { + return $this->link; } } diff --git a/src/Link/Url.php b/src/Link/Url.php index 44c400c..fc7ef2c 100644 --- a/src/Link/Url.php +++ b/src/Link/Url.php @@ -2,12 +2,17 @@ namespace JsonApiPhp\JsonApi\Link; -use JsonApiPhp\JsonApi\JsonSerializableValue; - -final class Url extends JsonSerializableValue implements Link +final class Url implements \JsonSerializable, Link { + private $url; + public function __construct(string $url) { - parent::__construct($url); + $this->url = $url; + } + + public function jsonSerialize() + { + return $this->url; } } diff --git a/src/MetaDocument.php b/src/MetaDocument.php index 10210fa..d764bd4 100644 --- a/src/MetaDocument.php +++ b/src/MetaDocument.php @@ -2,10 +2,17 @@ namespace JsonApiPhp\JsonApi; -final class MetaDocument extends JsonSerializableValue +final class MetaDocument implements \JsonSerializable { + private $doc; + public function __construct(Meta $meta, TopLevelDocumentMember ...$members) { - parent::__construct(combine($meta, ...$members)); + $this->doc = combine($meta, ...$members); + } + + public function jsonSerialize() + { + return $this->doc; } } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index e0253d3..315aaa4 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -17,7 +17,7 @@ public function __construct(string $key, $value) if (isValidName($key) === false) { throw new \DomainException("Invalid character in a member name '$key'"); } - if (in_array($key, ['id', 'type'])) { + if ($key === 'id' || $key === 'type') { throw new \DomainException("Can not use '$key' as a resource field"); } parent::__construct($key, $value); diff --git a/src/ResourceObject.php b/src/ResourceObject.php index b7e2cb8..c60394c 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -19,18 +19,26 @@ final class ResourceObject extends AttachableValue implements PrimaryData public function __construct(string $type, string $id = null, ResourceMember ...$members) { - $this->checkUniqueness(...$members); + $keys = []; + foreach ($members as $member) { + if ($member instanceof Identifier) { + $this->identifiers[] = $member; + } + if ($member instanceof ResourceField) { + $key = $member->key(); + if (isset($keys[$key])) { + throw new \LogicException("Field '$key' already exists'"); + } + $keys[$key] = true; + } + } + $obj = combine(...$members); $obj->type = $type; $obj->id = $id; parent::__construct('data', $obj); $this->type = $type; $this->id = $id; - foreach ($members as $member) { - if ($member instanceof Identifier) { - $this->identifiers[] = $member; - } - } } public function identifier(): ResourceIdentifier @@ -47,18 +55,4 @@ public function identifies(ResourceObject $resource): bool } return false; } - - private function checkUniqueness(ResourceMember ...$members): void - { - $keys = []; - foreach ($members as $member) { - if ($member instanceof ResourceField) { - $key = $member->key(); - if (isset($keys[$key])) { - throw new \LogicException("Field '$key' already exists'"); - } - $keys[$key] = true; - } - } - } } diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index 048d041..40aff17 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -1,12 +1,25 @@ identifier())) ); - $document = new CompoundDocument( + $data_document = new CompoundDocument( new ResourceObjectSet( new ResourceObject( 'articles', @@ -75,5 +87,31 @@ new LastLink(new Url('http://example.com/articles?page[offset]=10')) ); - $json = json_encode($document); + $data_doc_json = json_encode($data_document); +} + +for ($count = 0; $count < 1000; $count++) { + $error_doc = new ErrorDocument( + new Error( + new Id('1'), + new AboutLink( + new Url('/errors/not_found') + ), + new Status('404'), + new Code('not_found'), + new Title('Resource not found'), + new Detail('We tried hard but could not find anything'), + new Pointer('/data'), + new Parameter('query_string'), + new Meta('purpose', 'test') + ), + new Meta('purpose', 'test'), + new JsonApi() + ); + + $error_doc_json = json_encode($error_doc); } + +echo $data_doc_json; +echo "\n\n"; +echo $error_doc_json; From a18b91ad54d07f19202b764b85e227735c51a479 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 14:02:13 -0800 Subject: [PATCH 03/26] Performance improvements --- src/AttachableValue.php | 1 - src/ResourceObject.php | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/AttachableValue.php b/src/AttachableValue.php index 774ccb2..37f0b92 100644 --- a/src/AttachableValue.php +++ b/src/AttachableValue.php @@ -12,7 +12,6 @@ class AttachableValue implements Attachable, \JsonSerializable public function __construct(string $key, $value) { - //parent::__construct($value); $this->key = $key; $this->value = $value; } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index c60394c..59b2332 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -7,7 +7,7 @@ use JsonApiPhp\JsonApi\PrimaryData\ResourceField; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class ResourceObject extends AttachableValue implements PrimaryData +final class ResourceObject implements Attachable, \JsonSerializable, PrimaryData { private $type; private $id; @@ -17,6 +17,8 @@ final class ResourceObject extends AttachableValue implements PrimaryData */ private $identifiers = []; + private $res; + public function __construct(string $type, string $id = null, ResourceMember ...$members) { $keys = []; @@ -33,10 +35,9 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ } } - $obj = combine(...$members); - $obj->type = $type; - $obj->id = $id; - parent::__construct('data', $obj); + $this->res = combine(...$members); + $this->res->type = $type; + $this->res->id = $id; $this->type = $type; $this->id = $id; } @@ -55,4 +56,14 @@ public function identifies(ResourceObject $resource): bool } return false; } + + public function attachTo(object $o) + { + $o->data = $this; + } + + public function jsonSerialize() + { + return $this->res; + } } From 0ec111ae32a9b0626c08794c33e780e2af7f1313 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 14:19:36 -0800 Subject: [PATCH 04/26] Performance improvements --- src/Error/Parameter.php | 17 +++++++++++++---- src/Error/Pointer.php | 15 +++++++++++---- src/PrimaryData/ResourceField.php | 17 ++++++++++++++--- src/Relationship.php | 15 ++++----------- src/ResourceObject.php | 22 ++++++---------------- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/Error/Parameter.php b/src/Error/Parameter.php index 5c403c6..17e191f 100644 --- a/src/Error/Parameter.php +++ b/src/Error/Parameter.php @@ -2,21 +2,30 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; use function JsonApiPhp\JsonApi\child; -final class Parameter extends AttachableValue implements ErrorMember +final class Parameter implements ErrorMember { + /** + * @var string + */ + private $parameter; + /** * @param string $parameter a string indicating which URI query parameter caused the error. */ public function __construct(string $parameter) { - parent::__construct('parameter', $parameter); + $this->parameter = $parameter; } public function attachTo(object $o) { - parent::attachTo(child($o, 'source')); + child($o, 'source')->parameter = $this; + } + + public function jsonSerialize() + { + return $this->parameter; } } diff --git a/src/Error/Pointer.php b/src/Error/Pointer.php index de768be..d0ceb09 100644 --- a/src/Error/Pointer.php +++ b/src/Error/Pointer.php @@ -2,21 +2,28 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; +use JsonApiPhp\JsonApi\Attachable; use function JsonApiPhp\JsonApi\child; -final class Pointer extends AttachableValue implements ErrorMember +final class Pointer implements Attachable, ErrorMember { + private $pointer; + /** * @param string $pointer JSON Pointer [RFC6901] to the associated entity in the request document */ public function __construct(string $pointer) { - parent::__construct('pointer', $pointer); + $this->pointer = $pointer; } public function attachTo(object $o) { - parent::attachTo(child($o, 'source')); + child($o, 'source')->pointer = $this; + } + + public function jsonSerialize() + { + return $this->pointer; } } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index 315aaa4..7cea747 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -2,15 +2,16 @@ namespace JsonApiPhp\JsonApi\PrimaryData; -use JsonApiPhp\JsonApi\AttachableValue; +use JsonApiPhp\JsonApi\Attachable; use function JsonApiPhp\JsonApi\isValidName; /** * @internal */ -abstract class ResourceField extends AttachableValue implements ResourceMember +abstract class ResourceField implements Attachable, ResourceMember { private $key; + private $value; public function __construct(string $key, $value) { @@ -20,12 +21,22 @@ public function __construct(string $key, $value) if ($key === 'id' || $key === 'type') { throw new \DomainException("Can not use '$key' as a resource field"); } - parent::__construct($key, $value); $this->key = $key; + $this->value = $value; } public function key(): string { return $this->key; } + + public function attachTo(object $o) + { + $o->{$this->key} = $this; + } + + public function jsonSerialize() + { + return $this->value; + } } diff --git a/src/Relationship.php b/src/Relationship.php index b19808a..7d70693 100644 --- a/src/Relationship.php +++ b/src/Relationship.php @@ -7,19 +7,12 @@ final class Relationship extends ResourceField implements Identifier { - /** - * @var \JsonApiPhp\JsonApi\PrimaryData\Identifier[] - */ - private $identifiers = []; + private $members = []; public function __construct(string $key, RelationshipMember $member, RelationshipMember ...$members) { parent::__construct($key, combine($member, ...$members)); - foreach ([$member] + $members as $m) { - if ($m instanceof Identifier) { - $this->identifiers[] = $m; - } - } + $this->members = [$member] + $members; } public function attachTo(object $o) @@ -29,8 +22,8 @@ public function attachTo(object $o) public function identifies(ResourceObject $resource): bool { - foreach ($this->identifiers as $identifier) { - if ($identifier->identifies($resource)) { + foreach ($this->members as $member) { + if ($member instanceof Identifier && $member->identifies($resource)) { return true; } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 59b2332..34f8cd5 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -9,23 +9,14 @@ final class ResourceObject implements Attachable, \JsonSerializable, PrimaryData { - private $type; - private $id; - - /** - * @var Identifier[] - */ - private $identifiers = []; - private $res; + private $members = []; + public function __construct(string $type, string $id = null, ResourceMember ...$members) { $keys = []; foreach ($members as $member) { - if ($member instanceof Identifier) { - $this->identifiers[] = $member; - } if ($member instanceof ResourceField) { $key = $member->key(); if (isset($keys[$key])) { @@ -35,22 +26,21 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ } } + $this->members = $members; $this->res = combine(...$members); $this->res->type = $type; $this->res->id = $id; - $this->type = $type; - $this->id = $id; } public function identifier(): ResourceIdentifier { - return new ResourceIdentifier($this->type, $this->id); + return new ResourceIdentifier($this->res->type, $this->res->id); } public function identifies(ResourceObject $resource): bool { - foreach ($this->identifiers as $identifier) { - if ($identifier->identifies($resource)) { + foreach ($this->members as $member) { + if ($member instanceof Identifier && $member->identifies($resource)) { return true; } } From 7c49423818c346855bfa57ea1adc6fd33088a95e Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 14:35:28 -0800 Subject: [PATCH 05/26] Performance improvements --- src/Error/Code.php | 16 ++++++++++++---- src/Error/Detail.php | 16 ++++++++++++---- src/Error/ErrorMember.php | 4 ++-- src/Error/Id.php | 20 ++++++++++++++------ src/Error/Parameter.php | 7 +------ src/Error/Pointer.php | 10 ++-------- src/Error/Status.php | 16 ++++++++++++---- src/Error/Title.php | 16 ++++++++++++---- src/Link/AttachableLink.php | 23 +++++++++++++++++++---- src/Meta.php | 19 +++++++++++++++---- 10 files changed, 101 insertions(+), 46 deletions(-) diff --git a/src/Error/Code.php b/src/Error/Code.php index fc3dc92..e8f5e65 100644 --- a/src/Error/Code.php +++ b/src/Error/Code.php @@ -2,15 +2,23 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; - -final class Code extends AttachableValue implements ErrorMember +final class Code implements ErrorMember { + /** + * @var string + */ + private $code; + /** * @param string $code an application-specific error code, expressed as a string value */ public function __construct(string $code) { - parent::__construct('code', $code); + $this->code = $code; + } + + public function attachTo(object $o) + { + $o->code = $this->code; } } diff --git a/src/Error/Detail.php b/src/Error/Detail.php index 3acf546..699c4c0 100644 --- a/src/Error/Detail.php +++ b/src/Error/Detail.php @@ -2,15 +2,23 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; - -final class Detail extends AttachableValue implements ErrorMember +final class Detail implements ErrorMember { + /** + * @var string + */ + private $detail; + /** * @param string $detail a human-readable explanation specific to this occurrence of the problem. */ public function __construct(string $detail) { - parent::__construct('detail', $detail); + $this->detail = $detail; + } + + public function attachTo(object $o) + { + $o->detail = $this->detail; } } diff --git a/src/Error/ErrorMember.php b/src/Error/ErrorMember.php index 7dd48de..7fc06b4 100644 --- a/src/Error/ErrorMember.php +++ b/src/Error/ErrorMember.php @@ -2,11 +2,11 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\DocumentMember; +use JsonApiPhp\JsonApi\Attachable; /** * @internal */ -interface ErrorMember extends DocumentMember +interface ErrorMember extends Attachable { } diff --git a/src/Error/Id.php b/src/Error/Id.php index 7e7d1c7..ab817a6 100644 --- a/src/Error/Id.php +++ b/src/Error/Id.php @@ -2,15 +2,23 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; - -final class Id extends AttachableValue implements ErrorMember +final class Id implements ErrorMember { /** - * @param string $identifier a unique identifier for this particular occurrence of the problem + * @var string + */ + private $id; + + /** + * @param string $id a unique identifier for this particular occurrence of the problem */ - public function __construct(string $identifier) + public function __construct(string $id) + { + $this->id = $id; + } + + public function attachTo(object $o) { - parent::__construct('id', $identifier); + $o->id = $this->id; } } diff --git a/src/Error/Parameter.php b/src/Error/Parameter.php index 17e191f..874b34c 100644 --- a/src/Error/Parameter.php +++ b/src/Error/Parameter.php @@ -21,11 +21,6 @@ public function __construct(string $parameter) public function attachTo(object $o) { - child($o, 'source')->parameter = $this; - } - - public function jsonSerialize() - { - return $this->parameter; + child($o, 'source')->parameter = $this->parameter; } } diff --git a/src/Error/Pointer.php b/src/Error/Pointer.php index d0ceb09..957743f 100644 --- a/src/Error/Pointer.php +++ b/src/Error/Pointer.php @@ -2,10 +2,9 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\Attachable; use function JsonApiPhp\JsonApi\child; -final class Pointer implements Attachable, ErrorMember +final class Pointer implements ErrorMember { private $pointer; @@ -19,11 +18,6 @@ public function __construct(string $pointer) public function attachTo(object $o) { - child($o, 'source')->pointer = $this; - } - - public function jsonSerialize() - { - return $this->pointer; + child($o, 'source')->pointer = $this->pointer; } } diff --git a/src/Error/Status.php b/src/Error/Status.php index d5c7105..db38ef4 100644 --- a/src/Error/Status.php +++ b/src/Error/Status.php @@ -2,15 +2,23 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; - -final class Status extends AttachableValue implements ErrorMember +final class Status implements ErrorMember { + /** + * @var string + */ + private $status; + /** * @param string $status the HTTP status code applicable to this problem, expressed as a string value */ public function __construct(string $status) { - parent::__construct('status', $status); + $this->status = $status; + } + + public function attachTo(object $o) + { + $o->status = $this->status; } } diff --git a/src/Error/Title.php b/src/Error/Title.php index 10eddd0..2d71d2a 100644 --- a/src/Error/Title.php +++ b/src/Error/Title.php @@ -2,16 +2,24 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\AttachableValue; - -class Title extends AttachableValue implements ErrorMember +class Title implements ErrorMember { + /** + * @var string + */ + private $title; + /** * @param string $title a short, human-readable summary of the problem that SHOULD NOT change from occurrence * to occurrence of the problem, except for purposes of localization */ public function __construct(string $title) { - parent::__construct('title', $title); + $this->title = $title; + } + + public function attachTo(object $o) + { + $o->title = $this->title; } } diff --git a/src/Link/AttachableLink.php b/src/Link/AttachableLink.php index 50491e7..83d85a1 100644 --- a/src/Link/AttachableLink.php +++ b/src/Link/AttachableLink.php @@ -2,21 +2,36 @@ namespace JsonApiPhp\JsonApi\Link; -use JsonApiPhp\JsonApi\AttachableValue; +use JsonApiPhp\JsonApi\Attachable; use function JsonApiPhp\JsonApi\child; /** * @internal */ -class AttachableLink extends AttachableValue +class AttachableLink implements Attachable, \JsonSerializable { + /** + * @var string + */ + private $key; + /** + * @var Link + */ + private $link; + public function __construct(string $key, Link $link) { - parent::__construct($key, $link); + $this->key = $key; + $this->link = $link; } public function attachTo(object $o) { - parent::attachTo(child($o, 'links')); + child($o, 'links')->{$this->key} = $this; + } + + public function jsonSerialize() + { + return $this->link; } } diff --git a/src/Meta.php b/src/Meta.php index 78099ef..36d8a58 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -5,19 +5,30 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class Meta extends AttachableValue implements ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember +final class Meta implements Attachable, ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember { + /** + * @var string + */ + private $key; + private $value; + public function __construct(string $key, $value) { if (isValidName($key) === false) { throw new \DomainException("Invalid character in a member name '$key'"); } - - parent::__construct($key, $value); + $this->key = $key; + $this->value = $value; } public function attachTo(object $o) { - parent::attachTo(child($o, 'meta')); + child($o, 'meta')->{$this->key} = $this; + } + + public function jsonSerialize() + { + return $this->value; } } From cd27b4d46a0bf6df784a8d0d09d2add749b7aa5a Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 14:53:22 -0800 Subject: [PATCH 06/26] Performance improvements --- src/Included.php | 13 +++++++++++-- src/Link/AttachableLink.php | 4 ++-- src/Meta.php | 2 +- src/MultiLinkage.php | 20 ++++++++++++++++++-- src/PrimaryData/ResourceField.php | 2 +- src/ResourceObject.php | 2 +- src/SingleLinkage.php | 13 +++++++++++-- 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/Included.php b/src/Included.php index 14d73ce..aad831f 100644 --- a/src/Included.php +++ b/src/Included.php @@ -2,7 +2,7 @@ namespace JsonApiPhp\JsonApi; -final class Included extends AttachableValue implements DataDocumentMember, \IteratorAggregate +final class Included implements DataDocumentMember, \IteratorAggregate { private $resources = []; @@ -15,11 +15,20 @@ public function __construct(ResourceObject ...$resources) } $this->resources[$string_id] = $resource; } - parent::__construct('included', $resources); } public function getIterator() { return new \ArrayIterator($this->resources); } + + public function attachTo(object $o) + { + $o->included = array_values($this->resources); + } + + public function jsonSerialize() + { + return array_values($this->resources); + } } diff --git a/src/Link/AttachableLink.php b/src/Link/AttachableLink.php index 83d85a1..a533ee4 100644 --- a/src/Link/AttachableLink.php +++ b/src/Link/AttachableLink.php @@ -8,7 +8,7 @@ /** * @internal */ -class AttachableLink implements Attachable, \JsonSerializable +class AttachableLink implements Attachable { /** * @var string @@ -27,7 +27,7 @@ public function __construct(string $key, Link $link) public function attachTo(object $o) { - child($o, 'links')->{$this->key} = $this; + child($o, 'links')->{$this->key} = $this->link; } public function jsonSerialize() diff --git a/src/Meta.php b/src/Meta.php index 36d8a58..a3575e6 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -24,7 +24,7 @@ public function __construct(string $key, $value) public function attachTo(object $o) { - child($o, 'meta')->{$this->key} = $this; + child($o, 'meta')->{$this->key} = $this->value; } public function jsonSerialize() diff --git a/src/MultiLinkage.php b/src/MultiLinkage.php index b1f3ccb..8a80f00 100644 --- a/src/MultiLinkage.php +++ b/src/MultiLinkage.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\Identifier; -class MultiLinkage extends AttachableValue implements RelationshipMember, Identifier +class MultiLinkage implements RelationshipMember, Identifier { /** * @var \JsonApiPhp\JsonApi\ResourceIdentifier[] @@ -13,7 +13,6 @@ class MultiLinkage extends AttachableValue implements RelationshipMember, Identi public function __construct(ResourceIdentifier ...$identifiers) { - parent::__construct('data', $identifiers); $this->identifiers = $identifiers; } @@ -26,4 +25,21 @@ public function identifies(ResourceObject $resource): bool } return false; } + + public function attachTo(object $o) + { + $o->data = $this->identifiers; + } + + /** + * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + * @since 5.4.0 + */ + public function jsonSerialize() + { + // TODO: Implement jsonSerialize() method. + } } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index 7cea747..8ce4270 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -32,7 +32,7 @@ public function key(): string public function attachTo(object $o) { - $o->{$this->key} = $this; + $o->{$this->key} = $this->value; } public function jsonSerialize() diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 34f8cd5..927fc31 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -49,7 +49,7 @@ public function identifies(ResourceObject $resource): bool public function attachTo(object $o) { - $o->data = $this; + $o->data = $this->res; } public function jsonSerialize() diff --git a/src/SingleLinkage.php b/src/SingleLinkage.php index e53b74a..b0eb84d 100644 --- a/src/SingleLinkage.php +++ b/src/SingleLinkage.php @@ -4,13 +4,12 @@ use JsonApiPhp\JsonApi\PrimaryData\Identifier; -final class SingleLinkage extends AttachableValue implements RelationshipMember, Identifier +final class SingleLinkage implements RelationshipMember, Identifier { private $identifier; public function __construct(ResourceIdentifier $identifier = null) { - parent::__construct('data', $identifier); $this->identifier = $identifier; } @@ -18,4 +17,14 @@ public function identifies(ResourceObject $resource): bool { return $this->identifier && $this->identifier->identifies($resource); } + + public function attachTo(object $o) + { + $o->data = $this->identifier; + } + + public function jsonSerialize() + { + // TODO: Implement jsonSerialize() method. + } } From c95a67a3a7222006fdaeda4142889864f2e2d29d Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 15:38:11 -0800 Subject: [PATCH 07/26] Performance improvements --- src/AttachableValue.php | 2 +- src/DataDocumentMember.php | 2 +- src/DocumentMember.php | 10 -- src/Error/Title.php | 2 +- src/ErrorDocumentMember.php | 2 +- src/JsonApi.php | 14 ++- src/Link/AboutLink.php | 5 +- src/Link/AttachableLink.php | 11 +-- src/Link/FirstLink.php | 5 +- src/Link/LastLink.php | 5 +- src/Link/NextLink.php | 5 +- src/Link/PrevLink.php | 5 +- src/Link/RelatedLink.php | 5 +- src/Link/SelfLink.php | 5 +- src/Meta.php | 2 +- src/NullData.php | 10 +- src/PrimaryData/PrimaryData.php | 4 +- src/PrimaryData/ResourceField.php | 3 +- src/PrimaryData/ResourceMember.php | 4 +- src/RelationshipMember.php | 2 +- src/ResourceObject.php | 2 +- src/functions.php | 6 +- test/JsonApiTest.php | 16 +++- test/ResourceObjectTest.php | 144 +++++++++++++++++++---------- 24 files changed, 147 insertions(+), 124 deletions(-) delete mode 100644 src/DocumentMember.php diff --git a/src/AttachableValue.php b/src/AttachableValue.php index 37f0b92..4a2a9cb 100644 --- a/src/AttachableValue.php +++ b/src/AttachableValue.php @@ -18,7 +18,7 @@ public function __construct(string $key, $value) public function attachTo(object $o) { - $o->{$this->key} = $this; + $o->{$this->key} = $this->value; } public function jsonSerialize() diff --git a/src/DataDocumentMember.php b/src/DataDocumentMember.php index 9227b07..078815a 100644 --- a/src/DataDocumentMember.php +++ b/src/DataDocumentMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface DataDocumentMember extends DocumentMember +interface DataDocumentMember extends Attachable { } diff --git a/src/DocumentMember.php b/src/DocumentMember.php deleted file mode 100644 index d69a5ea..0000000 --- a/src/DocumentMember.php +++ /dev/null @@ -1,10 +0,0 @@ -jsonapi = (object) [ 'version' => $version, ]; if ($meta) { - $meta->attachTo($jsonapi); + $meta->attachTo($this->jsonapi); } - parent::__construct('jsonapi', $jsonapi); + } + + public function attachTo(object $o) + { + $o->jsonapi = $this->jsonapi; } } diff --git a/src/Link/AboutLink.php b/src/Link/AboutLink.php index 036a185..400e289 100644 --- a/src/Link/AboutLink.php +++ b/src/Link/AboutLink.php @@ -6,8 +6,5 @@ final class AboutLink extends AttachableLink implements ErrorMember { - public function __construct(Link $link) - { - parent::__construct('about', $link); - } + protected $key = 'about'; } diff --git a/src/Link/AttachableLink.php b/src/Link/AttachableLink.php index a533ee4..7805c35 100644 --- a/src/Link/AttachableLink.php +++ b/src/Link/AttachableLink.php @@ -13,15 +13,15 @@ class AttachableLink implements Attachable /** * @var string */ - private $key; + protected $key; + /** * @var Link */ private $link; - public function __construct(string $key, Link $link) + public function __construct(Link $link) { - $this->key = $key; $this->link = $link; } @@ -29,9 +29,4 @@ public function attachTo(object $o) { child($o, 'links')->{$this->key} = $this->link; } - - public function jsonSerialize() - { - return $this->link; - } } diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index 9a1ca5a..1ea6d81 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -8,8 +8,5 @@ final class FirstLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('first', $link); - } + protected $key = 'first'; } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 0bc75ff..985b54b 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -8,8 +8,5 @@ final class LastLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('last', $link); - } + protected $key = 'last'; } diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index b40bad2..5099611 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -8,8 +8,5 @@ final class NextLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('next', $link); - } + protected $key = 'next'; } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index e87eef5..e90b752 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -8,8 +8,5 @@ final class PrevLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('prev', $link); - } + protected $key = 'prev'; } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index 9990acb..ffd14c8 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -6,8 +6,5 @@ final class RelatedLink extends AttachableLink implements RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('related', $link); - } + protected $key = 'related'; } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 55d8002..aac8140 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -8,8 +8,5 @@ final class SelfLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember { - public function __construct(Link $link) - { - parent::__construct('self', $link); - } + protected $key = 'self'; } diff --git a/src/Meta.php b/src/Meta.php index a3575e6..fece71c 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -5,7 +5,7 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class Meta implements Attachable, ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember +final class Meta implements ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember { /** * @var string diff --git a/src/NullData.php b/src/NullData.php index 7d39ca6..5128a0a 100644 --- a/src/NullData.php +++ b/src/NullData.php @@ -4,15 +4,15 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class NullData extends AttachableValue implements PrimaryData +final class NullData implements PrimaryData { - public function __construct() + public function identifies(ResourceObject $resource): bool { - parent::__construct('data', null); + return false; } - public function identifies(ResourceObject $resource): bool + public function attachTo(object $o) { - return false; + $o->data = null; } } diff --git a/src/PrimaryData/PrimaryData.php b/src/PrimaryData/PrimaryData.php index 57d5b1c..dc467f1 100644 --- a/src/PrimaryData/PrimaryData.php +++ b/src/PrimaryData/PrimaryData.php @@ -2,9 +2,11 @@ namespace JsonApiPhp\JsonApi\PrimaryData; +use JsonApiPhp\JsonApi\Attachable; + /** * @internal */ -interface PrimaryData extends Identifier +interface PrimaryData extends Attachable, Identifier { } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index 8ce4270..c0da3a8 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -2,13 +2,12 @@ namespace JsonApiPhp\JsonApi\PrimaryData; -use JsonApiPhp\JsonApi\Attachable; use function JsonApiPhp\JsonApi\isValidName; /** * @internal */ -abstract class ResourceField implements Attachable, ResourceMember +abstract class ResourceField implements ResourceMember { private $key; private $value; diff --git a/src/PrimaryData/ResourceMember.php b/src/PrimaryData/ResourceMember.php index 0a88dff..02b51f9 100644 --- a/src/PrimaryData/ResourceMember.php +++ b/src/PrimaryData/ResourceMember.php @@ -2,11 +2,11 @@ namespace JsonApiPhp\JsonApi\PrimaryData; -use JsonApiPhp\JsonApi\DocumentMember; +use JsonApiPhp\JsonApi\Attachable; /** * @internal */ -interface ResourceMember extends DocumentMember +interface ResourceMember extends Attachable { } diff --git a/src/RelationshipMember.php b/src/RelationshipMember.php index 8360f92..81ac79d 100644 --- a/src/RelationshipMember.php +++ b/src/RelationshipMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface RelationshipMember extends DocumentMember +interface RelationshipMember extends Attachable { } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 927fc31..307ca3e 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -7,7 +7,7 @@ use JsonApiPhp\JsonApi\PrimaryData\ResourceField; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class ResourceObject implements Attachable, \JsonSerializable, PrimaryData +final class ResourceObject implements \JsonSerializable, PrimaryData { private $res; diff --git a/src/functions.php b/src/functions.php index cace2e9..69bb00d 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,11 +2,11 @@ namespace JsonApiPhp\JsonApi; -function combine(Attachable ...$things): object +function combine(Attachable ...$members): object { $obj = (object) []; - foreach ($things as $thing) { - $thing->attachTo($obj); + foreach ($members as $member) { + $member->attachTo($obj); } return $obj; } diff --git a/test/JsonApiTest.php b/test/JsonApiTest.php index 99731b0..49c5982 100644 --- a/test/JsonApiTest.php +++ b/test/JsonApiTest.php @@ -2,9 +2,9 @@ namespace JsonApiPhp\JsonApi\Test; -use JsonApiPhp\JsonApi\Document\JsonApi\Version; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Meta; +use JsonApiPhp\JsonApi\MetaDocument; class JsonApiTest extends BaseTestCase { @@ -13,13 +13,21 @@ public function testJsonApiMayContainVersionAndMeta() $this->assertEncodesTo( ' { - "version": "1.0", "meta": { - "foo": "bar" + "test": "test" + }, + "jsonapi": { + "version": "1.0", + "meta": { + "foo": "bar" + } } } ', - new JsonApi('1.0', new Meta('foo', 'bar')) + new MetaDocument( + new Meta('test', 'test'), + new JsonApi('1.0', new Meta('foo', 'bar')) + ) ); } } diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index 3548dcd..db31389 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -3,6 +3,7 @@ namespace JsonApiPhp\JsonApi\Test; use JsonApiPhp\JsonApi\Attribute; +use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Link\Url; @@ -20,39 +21,43 @@ public function testFullFledgedResourceObject() $this->assertEncodesTo( ' { - "type": "apples", - "id": "1", - "attributes": { - "title": "Rails is Omakase" - }, - "meta": {"foo": "bar"}, - "links": { - "self": "http://self" - }, - "relationships": { - "author": { - "meta": {"foo": "bar"}, - "links": { - "self": "http://rel/author", - "related": "http://author" - }, - "data": null + "data": { + "type": "apples", + "id": "1", + "attributes": { + "title": "Rails is Omakase" + }, + "meta": {"foo": "bar"}, + "links": { + "self": "http://self" + }, + "relationships": { + "author": { + "meta": {"foo": "bar"}, + "links": { + "self": "http://rel/author", + "related": "http://author" + }, + "data": null + } } } } ', - new ResourceObject( - 'apples', - '1', - new Meta('foo', 'bar'), - new Attribute('title', 'Rails is Omakase'), - new SelfLink(new Url('http://self')), - new Relationship( - 'author', + new DataDocument( + new ResourceObject( + 'apples', + '1', new Meta('foo', 'bar'), - new SelfLink(new Url('http://rel/author')), - new RelatedLink(new Url('http://author')), - new SingleLinkage() + new Attribute('title', 'Rails is Omakase'), + new SelfLink(new Url('http://self')), + new Relationship( + 'author', + new Meta('foo', 'bar'), + new SelfLink(new Url('http://rel/author')), + new RelatedLink(new Url('http://author')), + new SingleLinkage() + ) ) ) ); @@ -64,15 +69,26 @@ public function testRelationshipWithSingleIdLinkage() ' { "data": { - "type": "apples", - "id": "1" + "type": "basket", + "id": "1", + "relationships": { + "content": { + "data": {"type": "apples", "id": "1"} + } + } } } ', - new Relationship( - 'fruits', - new SingleLinkage( - new ResourceIdentifier('apples', '1') + new DataDocument( + new ResourceObject( + 'basket', + '1', + new Relationship( + 'content', + new SingleLinkage( + new ResourceIdentifier('apples', '1') + ) + ) ) ) ); @@ -83,20 +99,34 @@ public function testRelationshipWithMultiIdLinkage() $this->assertEncodesTo( ' { - "data": [{ - "type": "apples", - "id": "1" - },{ - "type": "pears", - "id": "2" - }] + "data": { + "type": "basket", + "id": "1", + "relationships": { + "content": { + "data": [{ + "type": "apples", + "id": "1" + },{ + "type": "pears", + "id": "2" + }] + } + } + } } ', - new Relationship( - 'fruits', - new MultiLinkage( - new ResourceIdentifier('apples', '1'), - new ResourceIdentifier('pears', '2') + new DataDocument( + new ResourceObject( + 'basket', + '1', + new Relationship( + 'content', + new MultiLinkage( + new ResourceIdentifier('apples', '1'), + new ResourceIdentifier('pears', '2') + ) + ) ) ) ); @@ -107,12 +137,26 @@ public function testRelationshipWithEmptyMultiIdLinkage() $this->assertEncodesTo( ' { - "data": [] + "data": { + "type": "basket", + "id": "1", + "relationships": { + "content": { + "data": [] + } + } + } } ', - new Relationship( - 'fruits', - new MultiLinkage() + new DataDocument( + new ResourceObject( + 'basket', + '1', + new Relationship( + 'content', + new MultiLinkage() + ) + ) ) ); } From f35b389cb0e72ba3f6c9b79f9cd75ad8d0112e55 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 16:52:48 -0800 Subject: [PATCH 08/26] Performance improvements --- src/Error.php | 9 ++------- src/Included.php | 7 +------ src/Link/AboutLink.php | 18 +++++++++++++++-- src/Link/AttachableLink.php | 32 ------------------------------- src/Link/FirstLink.php | 18 +++++++++++++++-- src/Link/LastLink.php | 18 +++++++++++++++-- src/Link/NextLink.php | 18 +++++++++++++++-- src/Link/PrevLink.php | 18 +++++++++++++++-- src/Link/RelatedLink.php | 18 +++++++++++++++-- src/Link/SelfLink.php | 18 +++++++++++++++-- src/MultiLinkage.php | 12 ------------ src/PrimaryData/ResourceField.php | 5 ----- src/ResourceIdentifier.php | 18 +++++++++++++---- src/ResourceIdentifierSet.php | 8 ++++++-- src/ResourceObject.php | 9 +++++++++ src/SingleLinkage.php | 5 ----- test/CompoundDocumentTest.php | 2 +- 17 files changed, 145 insertions(+), 88 deletions(-) delete mode 100644 src/Link/AttachableLink.php diff --git a/src/Error.php b/src/Error.php index dde99ff..69b0c3b 100644 --- a/src/Error.php +++ b/src/Error.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; -final class Error implements \JsonSerializable, ErrorDocumentMember +final class Error implements ErrorDocumentMember { private $error; @@ -15,11 +15,6 @@ public function __construct(ErrorMember ...$members) public function attachTo(object $o) { - $o->errors[] = $this; - } - - public function jsonSerialize() - { - return $this->error; + $o->errors[] = $this->error; } } diff --git a/src/Included.php b/src/Included.php index aad831f..566f4e8 100644 --- a/src/Included.php +++ b/src/Included.php @@ -9,7 +9,7 @@ final class Included implements DataDocumentMember, \IteratorAggregate public function __construct(ResourceObject ...$resources) { foreach ($resources as $resource) { - $string_id = json_encode($resource->identifier()); + $string_id = $resource->uniqueId(); if (isset($this->resources[$string_id])) { throw new \LogicException("Resource $string_id is already included"); } @@ -26,9 +26,4 @@ public function attachTo(object $o) { $o->included = array_values($this->resources); } - - public function jsonSerialize() - { - return array_values($this->resources); - } } diff --git a/src/Link/AboutLink.php b/src/Link/AboutLink.php index 400e289..d144eb9 100644 --- a/src/Link/AboutLink.php +++ b/src/Link/AboutLink.php @@ -3,8 +3,22 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\Error\ErrorMember; +use function JsonApiPhp\JsonApi\child; -final class AboutLink extends AttachableLink implements ErrorMember +final class AboutLink implements ErrorMember { - protected $key = 'about'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->about = $this->link; + } } diff --git a/src/Link/AttachableLink.php b/src/Link/AttachableLink.php deleted file mode 100644 index 7805c35..0000000 --- a/src/Link/AttachableLink.php +++ /dev/null @@ -1,32 +0,0 @@ -link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->{$this->key} = $this->link; - } -} diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index 1ea6d81..6b9c383 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -5,8 +5,22 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class FirstLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class FirstLink implements DataDocumentMember, ResourceMember, RelationshipMember { - protected $key = 'first'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->first = $this->link; + } } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 985b54b..936ec57 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -5,8 +5,22 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class LastLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class LastLink implements DataDocumentMember, ResourceMember, RelationshipMember { - protected $key = 'last'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->last = $this->link; + } } diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index 5099611..c698ddd 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -5,8 +5,22 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class NextLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class NextLink implements DataDocumentMember, ResourceMember, RelationshipMember { - protected $key = 'next'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->next = $this->link; + } } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index e90b752..9310a18 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -5,8 +5,22 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class PrevLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class PrevLink implements DataDocumentMember, ResourceMember, RelationshipMember { - protected $key = 'prev'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->prev = $this->link; + } } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index ffd14c8..b340111 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -3,8 +3,22 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class RelatedLink extends AttachableLink implements RelationshipMember +final class RelatedLink implements RelationshipMember { - protected $key = 'related'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->related = $this->link; + } } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index aac8140..f06a402 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -5,8 +5,22 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; +use function JsonApiPhp\JsonApi\child; -final class SelfLink extends AttachableLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class SelfLink implements DataDocumentMember, ResourceMember, RelationshipMember { - protected $key = 'self'; + /** + * @var Link + */ + private $link; + + public function __construct(Link $link) + { + $this->link = $link; + } + + public function attachTo(object $o) + { + child($o, 'links')->self = $this->link; + } } diff --git a/src/MultiLinkage.php b/src/MultiLinkage.php index 8a80f00..96b8269 100644 --- a/src/MultiLinkage.php +++ b/src/MultiLinkage.php @@ -30,16 +30,4 @@ public function attachTo(object $o) { $o->data = $this->identifiers; } - - /** - * Specify data which should be serialized to JSON - * @link http://php.net/manual/en/jsonserializable.jsonserialize.php - * @return mixed data which can be serialized by json_encode, - * which is a value of any type other than a resource. - * @since 5.4.0 - */ - public function jsonSerialize() - { - // TODO: Implement jsonSerialize() method. - } } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index c0da3a8..98e8e21 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -33,9 +33,4 @@ public function attachTo(object $o) { $o->{$this->key} = $this->value; } - - public function jsonSerialize() - { - return $this->value; - } } diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index fc2bddd..c8d2e75 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -4,21 +4,21 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceIdentifier extends AttachableValue implements PrimaryData +final class ResourceIdentifier implements PrimaryData, \JsonSerializable { private $type; private $id; + private $identifier; public function __construct(string $type, string $id, Meta $meta = null) { - $identifier = (object) [ + $this->identifier = (object) [ 'type' => $type, 'id' => $id, ]; if ($meta) { - $meta->attachTo($identifier); + $meta->attachTo($this->identifier); } - parent::__construct('data', $identifier); $this->type = $type; $this->id = $id; } @@ -32,4 +32,14 @@ public function equals(ResourceIdentifier $that): bool { return $this->type === $that->type && $this->id === $that->id; } + + public function attachTo(object $o) + { + $o->data = $this->identifier; + } + + public function jsonSerialize() + { + return $this->identifier; + } } diff --git a/src/ResourceIdentifierSet.php b/src/ResourceIdentifierSet.php index e63efc0..82a4f19 100644 --- a/src/ResourceIdentifierSet.php +++ b/src/ResourceIdentifierSet.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceIdentifierSet extends AttachableValue implements PrimaryData +final class ResourceIdentifierSet implements PrimaryData { /** * @var ResourceIdentifier[] @@ -13,7 +13,6 @@ final class ResourceIdentifierSet extends AttachableValue implements PrimaryData public function __construct(ResourceIdentifier ...$identifiers) { - parent::__construct('data', $identifiers); $this->identifiers = $identifiers; } @@ -26,4 +25,9 @@ public function identifies(ResourceObject $resource): bool } return false; } + + public function attachTo(object $o) + { + $o->data = $this->identifiers; + } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 307ca3e..1328ac9 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -10,6 +10,8 @@ final class ResourceObject implements \JsonSerializable, PrimaryData { private $res; + private $type; + private $id; private $members = []; @@ -27,6 +29,8 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ } $this->members = $members; + $this->type = $type; + $this->id = $id; $this->res = combine(...$members); $this->res->type = $type; $this->res->id = $id; @@ -56,4 +60,9 @@ public function jsonSerialize() { return $this->res; } + + public function uniqueId(): string + { + return "{$this->type}:{$this->id}"; + } } diff --git a/src/SingleLinkage.php b/src/SingleLinkage.php index b0eb84d..94c5d06 100644 --- a/src/SingleLinkage.php +++ b/src/SingleLinkage.php @@ -22,9 +22,4 @@ public function attachTo(object $o) { $o->data = $this->identifier; } - - public function jsonSerialize() - { - // TODO: Implement jsonSerialize() method. - } } diff --git a/test/CompoundDocumentTest.php b/test/CompoundDocumentTest.php index 258fa6e..69cfcf7 100644 --- a/test/CompoundDocumentTest.php +++ b/test/CompoundDocumentTest.php @@ -247,7 +247,7 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() /** * A compound document MUST NOT include more than one resource object for each type and id pair. * @expectedException \LogicException - * @expectedExceptionMessage Resource {"type":"apples","id":"1"} is already included + * @expectedExceptionMessage Resource apples:1 is already included */ public function testCanNotBeManyIncludedResourcesWithEqualIdentifiers() { From 3082e00af02d842513f910563c1db5defa519b67 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 18:02:12 -0800 Subject: [PATCH 09/26] Performance improvements --- README.md | 5 ++-- examples/compound_doc.php | 23 ++++++++-------- examples/simple_doc.php | 5 ++-- src/Link/AboutLink.php | 18 ++----------- src/Link/FirstLink.php | 18 ++----------- src/Link/LastLink.php | 18 ++----------- src/Link/Link.php | 24 ++++++++++++++++- src/Link/LinkObject.php | 25 ----------------- src/Link/NextLink.php | 18 ++----------- src/Link/PrevLink.php | 18 ++----------- src/Link/RelatedLink.php | 18 ++----------- src/Link/SelfLink.php | 18 ++----------- src/Link/Url.php | 18 ------------- src/Meta.php | 5 ---- src/ResourceObjectSet.php | 8 ++++-- test/CompoundDocumentTest.php | 23 ++++++++-------- .../ManyResourceIdentifiersTest.php | 3 +-- test/DataDocument/ManyResourceObjectsTest.php | 3 +-- test/DataDocument/NullDataTest.php | 3 +-- .../SingleResourceIdentifierTest.php | 3 +-- .../DataDocument/SingleResourceObjectTest.php | 3 +-- test/ErrorDocumentTest.php | 5 +--- test/LinkObjectTest.php | 6 ++--- test/PaginationLinksTest.php | 9 +++---- test/ResourceObjectTest.php | 7 +++-- test/benchmarks/compound10k.php | 27 +++++++++---------- 26 files changed, 97 insertions(+), 234 deletions(-) delete mode 100644 src/Link/LinkObject.php delete mode 100644 src/Link/Url.php diff --git a/README.md b/README.md index 9431d4e..9dc0e30 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; @@ -50,8 +49,8 @@ echo json_encode( new Relationship( 'author', new SingleLinkage(new ResourceIdentifier('author', '9')), - new SelfLink(new Url('/articles/1/relationships/author')), - new RelatedLink(new Url('/articles/1/author')) + new SelfLink('/articles/1/relationships/author'), + new RelatedLink('/articles/1/author') ) ) ), diff --git a/examples/compound_doc.php b/examples/compound_doc.php index 02fdac0..7d65b20 100644 --- a/examples/compound_doc.php +++ b/examples/compound_doc.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\MultiLinkage; use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; @@ -22,14 +21,14 @@ new Attribute('first-name', 'Dan'), new Attribute('last-name', 'Gebhardt'), new Attribute('twitter', 'dgeb'), - new SelfLink(new Url('http://example.com/people/9')) + new SelfLink('http://example.com/people/9') ); $comment05 = new ResourceObject( 'comments', '5', new Attribute('body', 'First!'), - new SelfLink(new Url('http://example.com/comments/5')), + new SelfLink('http://example.com/comments/5'), new Relationship('author', new SingleLinkage(new ResourceIdentifier('people', '2'))) ); @@ -37,7 +36,7 @@ 'comments', '12', new Attribute('body', 'I like XML better'), - new SelfLink(new Url('http://example.com/comments/12')), + new SelfLink('http://example.com/comments/12'), new Relationship('author', new SingleLinkage($dan->identifier())) ); @@ -47,12 +46,12 @@ 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), - new SelfLink(new Url('http://example.com/articles/1')), + new SelfLink('http://example.com/articles/1'), new Relationship( 'author', new SingleLinkage($dan->identifier()), - new SelfLink(new Url('http://example.com/articles/1/relationships/author')), - new RelatedLink(new Url('http://example.com/articles/1/author')) + new SelfLink('http://example.com/articles/1/relationships/author'), + new RelatedLink('http://example.com/articles/1/author') ), new Relationship( 'comments', @@ -60,15 +59,15 @@ $comment05->identifier(), $comment12->identifier() ), - new SelfLink(new Url('http://example.com/articles/1/relationships/comments')), - new RelatedLink(new Url('http://example.com/articles/1/comments')) + new SelfLink('http://example.com/articles/1/relationships/comments'), + new RelatedLink('http://example.com/articles/1/comments') ) ) ), new Included($dan, $comment05, $comment12), - new SelfLink(new Url('http://example.com/articles')), - new NextLink(new Url('http://example.com/articles?page[offset]=2')), - new LastLink(new Url('http://example.com/articles?page[offset]=10')) + new SelfLink('http://example.com/articles'), + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') ); echo json_encode($document, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); diff --git a/examples/simple_doc.php b/examples/simple_doc.php index 48b60b7..4ebcc3f 100644 --- a/examples/simple_doc.php +++ b/examples/simple_doc.php @@ -5,7 +5,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; @@ -20,8 +19,8 @@ new Relationship( 'author', new SingleLinkage(new ResourceIdentifier('author', '9')), - new SelfLink(new Url('/articles/1/relationships/author')), - new RelatedLink(new Url('/articles/1/author')) + new SelfLink('/articles/1/relationships/author'), + new RelatedLink('/articles/1/author') ) ) ), diff --git a/src/Link/AboutLink.php b/src/Link/AboutLink.php index d144eb9..3005597 100644 --- a/src/Link/AboutLink.php +++ b/src/Link/AboutLink.php @@ -3,22 +3,8 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\Error\ErrorMember; -use function JsonApiPhp\JsonApi\child; -final class AboutLink implements ErrorMember +final class AboutLink extends Link implements ErrorMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->about = $this->link; - } + protected $name = 'about'; } diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index 6b9c383..87c98d5 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -5,22 +5,8 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class FirstLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class FirstLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->first = $this->link; - } + protected $name = 'first'; } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 936ec57..7aa9880 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -5,22 +5,8 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class LastLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class LastLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->last = $this->link; - } + protected $name = 'last'; } diff --git a/src/Link/Link.php b/src/Link/Link.php index 96335f3..e64d941 100644 --- a/src/Link/Link.php +++ b/src/Link/Link.php @@ -2,9 +2,31 @@ namespace JsonApiPhp\JsonApi\Link; +use JsonApiPhp\JsonApi\Attachable; +use JsonApiPhp\JsonApi\Meta; +use function JsonApiPhp\JsonApi\child; +use function JsonApiPhp\JsonApi\combine; + /** * @internal */ -interface Link +abstract class Link implements Attachable { + protected $name; + private $link; + + public function __construct(string $url, Meta ...$metas) + { + if ($metas) { + $this->link = combine(...$metas); + $this->link->href = $url; + } else { + $this->link = $url; + } + } + + public function attachTo(object $o) + { + child($o, 'links')->{$this->name} = $this->link; + } } diff --git a/src/Link/LinkObject.php b/src/Link/LinkObject.php deleted file mode 100644 index 7303088..0000000 --- a/src/Link/LinkObject.php +++ /dev/null @@ -1,25 +0,0 @@ -link = (object) [ - 'href' => $href, - ]; - if ($meta) { - $meta->attachTo($this->link); - } - } - - public function jsonSerialize() - { - return $this->link; - } -} diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index c698ddd..bdbf442 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -5,22 +5,8 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class NextLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class NextLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->next = $this->link; - } + protected $name = 'next'; } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index 9310a18..eb7fc7f 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -5,22 +5,8 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class PrevLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class PrevLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->prev = $this->link; - } + protected $name = 'prev'; } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index b340111..de691e6 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -3,22 +3,8 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class RelatedLink implements RelationshipMember +final class RelatedLink extends Link implements RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->related = $this->link; - } + protected $name = 'related'; } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index f06a402..05b2f7d 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -5,22 +5,8 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\RelationshipMember; -use function JsonApiPhp\JsonApi\child; -final class SelfLink implements DataDocumentMember, ResourceMember, RelationshipMember +final class SelfLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember { - /** - * @var Link - */ - private $link; - - public function __construct(Link $link) - { - $this->link = $link; - } - - public function attachTo(object $o) - { - child($o, 'links')->self = $this->link; - } + protected $name = 'self'; } diff --git a/src/Link/Url.php b/src/Link/Url.php deleted file mode 100644 index fc7ef2c..0000000 --- a/src/Link/Url.php +++ /dev/null @@ -1,18 +0,0 @@ -url = $url; - } - - public function jsonSerialize() - { - return $this->url; - } -} diff --git a/src/Meta.php b/src/Meta.php index fece71c..56316a6 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -26,9 +26,4 @@ public function attachTo(object $o) { child($o, 'meta')->{$this->key} = $this->value; } - - public function jsonSerialize() - { - return $this->value; - } } diff --git a/src/ResourceObjectSet.php b/src/ResourceObjectSet.php index 2eb37c5..678a75b 100644 --- a/src/ResourceObjectSet.php +++ b/src/ResourceObjectSet.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceObjectSet extends AttachableValue implements PrimaryData +final class ResourceObjectSet implements PrimaryData { /** * @var ResourceObject[] @@ -14,7 +14,6 @@ final class ResourceObjectSet extends AttachableValue implements PrimaryData public function __construct(ResourceObject ...$resources) { $this->resources = $resources; - parent::__construct('data', $this->resources); } public function identifies(ResourceObject $resource): bool @@ -26,4 +25,9 @@ public function identifies(ResourceObject $resource): bool } return false; } + + public function attachTo(object $o) + { + $o->data = $this->resources; + } } diff --git a/test/CompoundDocumentTest.php b/test/CompoundDocumentTest.php index 69cfcf7..57a34f1 100644 --- a/test/CompoundDocumentTest.php +++ b/test/CompoundDocumentTest.php @@ -9,7 +9,6 @@ use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\MultiLinkage; use JsonApiPhp\JsonApi\NullData; use JsonApiPhp\JsonApi\Relationship; @@ -29,14 +28,14 @@ public function testOfficialDocsExample() new Attribute('first-name', 'Dan'), new Attribute('last-name', 'Gebhardt'), new Attribute('twitter', 'dgeb'), - new SelfLink(new Url('http://example.com/people/9')) + new SelfLink('http://example.com/people/9') ); $comment05 = new ResourceObject( 'comments', '5', new Attribute('body', 'First!'), - new SelfLink(new Url('http://example.com/comments/5')), + new SelfLink('http://example.com/comments/5'), new Relationship('author', new SingleLinkage(new ResourceIdentifier('people', '2'))) ); @@ -44,7 +43,7 @@ public function testOfficialDocsExample() 'comments', '12', new Attribute('body', 'I like XML better'), - new SelfLink(new Url('http://example.com/comments/12')), + new SelfLink('http://example.com/comments/12'), new Relationship('author', new SingleLinkage($dan->identifier())) ); @@ -54,12 +53,12 @@ public function testOfficialDocsExample() 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), - new SelfLink(new Url('http://example.com/articles/1')), + new SelfLink('http://example.com/articles/1'), new Relationship( 'author', new SingleLinkage($dan->identifier()), - new SelfLink(new Url('http://example.com/articles/1/relationships/author')), - new RelatedLink(new Url('http://example.com/articles/1/author')) + new SelfLink('http://example.com/articles/1/relationships/author'), + new RelatedLink('http://example.com/articles/1/author') ), new Relationship( 'comments', @@ -67,15 +66,15 @@ public function testOfficialDocsExample() $comment05->identifier(), $comment12->identifier() ), - new SelfLink(new Url('http://example.com/articles/1/relationships/comments')), - new RelatedLink(new Url('http://example.com/articles/1/comments')) + new SelfLink('http://example.com/articles/1/relationships/comments'), + new RelatedLink('http://example.com/articles/1/comments') ) ) ), new Included($dan, $comment05, $comment12), - new SelfLink(new Url('http://example.com/articles')), - new NextLink(new Url('http://example.com/articles?page[offset]=2')), - new LastLink(new Url('http://example.com/articles?page[offset]=10')) + new SelfLink('http://example.com/articles'), + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') ); $this->assertEncodesTo( ' diff --git a/test/DataDocument/ManyResourceIdentifiersTest.php b/test/DataDocument/ManyResourceIdentifiersTest.php index 6aaa5bf..d4fb181 100644 --- a/test/DataDocument/ManyResourceIdentifiersTest.php +++ b/test/DataDocument/ManyResourceIdentifiersTest.php @@ -5,7 +5,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceIdentifierSet; @@ -63,7 +62,7 @@ public function testExtendedDocument() new Meta('apple_meta', 'foo') ) ), - new SelfLink(new Url('/apples')), + new SelfLink('/apples'), new JsonApi(), new Meta('document_meta', 'bar') ) diff --git a/test/DataDocument/ManyResourceObjectsTest.php b/test/DataDocument/ManyResourceObjectsTest.php index ef3da2c..7ba9939 100644 --- a/test/DataDocument/ManyResourceObjectsTest.php +++ b/test/DataDocument/ManyResourceObjectsTest.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ResourceObjectSet; @@ -76,7 +75,7 @@ public function testExtendedDocument() new Meta('apple_meta', 'foo') ) ), - new SelfLink(new Url('/apples')), + new SelfLink('/apples'), new JsonApi(), new Meta('document_meta', 'bar') ) diff --git a/test/DataDocument/NullDataTest.php b/test/DataDocument/NullDataTest.php index 9d436e7..05746cd 100644 --- a/test/DataDocument/NullDataTest.php +++ b/test/DataDocument/NullDataTest.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\NullData; use JsonApiPhp\JsonApi\Test\BaseTestCase; @@ -44,7 +43,7 @@ public function testExtendedDocument() ', new DataDocument( new NullData(), - new SelfLink(new Url('/apples/1')), + new SelfLink('/apples/1'), new JsonApi(), new Meta('document_meta', 'bar') ) diff --git a/test/DataDocument/SingleResourceIdentifierTest.php b/test/DataDocument/SingleResourceIdentifierTest.php index becb005..92a91d5 100644 --- a/test/DataDocument/SingleResourceIdentifierTest.php +++ b/test/DataDocument/SingleResourceIdentifierTest.php @@ -5,7 +5,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\Test\BaseTestCase; @@ -54,7 +53,7 @@ public function testExtendedDocument() '1', new Meta('apple_meta', 'foo') ), - new SelfLink(new Url('/apples/1')), + new SelfLink('/apples/1'), new JsonApi(), new Meta('document_meta', 'bar') ) diff --git a/test/DataDocument/SingleResourceObjectTest.php b/test/DataDocument/SingleResourceObjectTest.php index 5d9af4b..dfa25a1 100644 --- a/test/DataDocument/SingleResourceObjectTest.php +++ b/test/DataDocument/SingleResourceObjectTest.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\Test\BaseTestCase; @@ -61,7 +60,7 @@ public function testExtendedDocument() new Attribute('sort', 'Fuji'), new Meta('apple_meta', 'foo') ), - new SelfLink(new Url('/apples/1')), + new SelfLink('/apples/1'), new JsonApi(), new Meta('document_meta', 'bar') ) diff --git a/test/ErrorDocumentTest.php b/test/ErrorDocumentTest.php index 5ed715a..bf6fc29 100644 --- a/test/ErrorDocumentTest.php +++ b/test/ErrorDocumentTest.php @@ -14,7 +14,6 @@ use JsonApiPhp\JsonApi\ErrorDocument; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\AboutLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; class ErrorDocumentTest extends BaseTestCase @@ -68,9 +67,7 @@ public function testExtensiveExample() new ErrorDocument( new Error( new Id('1'), - new AboutLink( - new Url('/errors/not_found') - ), + new AboutLink('/errors/not_found'), new Status('404'), new Code('not_found'), new Title('Resource not found'), diff --git a/test/LinkObjectTest.php b/test/LinkObjectTest.php index 6df8fff..a69443c 100644 --- a/test/LinkObjectTest.php +++ b/test/LinkObjectTest.php @@ -3,7 +3,6 @@ namespace JsonApiPhp\JsonApi\Test; use JsonApiPhp\JsonApi\DataDocument; -use JsonApiPhp\JsonApi\Link\LinkObject; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; @@ -19,7 +18,8 @@ public function testLinkObject() "self": { "href": "http://example.com", "meta": { - "foo": "bar" + "foo": "bar", + "test": true } } } @@ -27,7 +27,7 @@ public function testLinkObject() ', new DataDocument( new ResourceIdentifier('apples', '1'), - new SelfLink(new LinkObject('http://example.com', new Meta('foo', 'bar'))) + new SelfLink('http://example.com', new Meta('foo', 'bar'), new Meta('test', true)) ) ); } diff --git a/test/PaginationLinksTest.php b/test/PaginationLinksTest.php index f1774d6..c33b105 100644 --- a/test/PaginationLinksTest.php +++ b/test/PaginationLinksTest.php @@ -7,7 +7,6 @@ use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\PrevLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ResourceObjectSet; @@ -35,10 +34,10 @@ public function testPagination() new ResourceObject('apples', '1'), new ResourceObject('apples', '2') ), - new FirstLink(new Url('http://example.com/fruits?page=first')), - new LastLink(new Url('http://example.com/fruits?page=last')), - new PrevLink(new Url('http://example.com/fruits?page=3')), - new NextLink(new Url('http://example.com/fruits?page=5')) + new FirstLink('http://example.com/fruits?page=first'), + new LastLink('http://example.com/fruits?page=last'), + new PrevLink('http://example.com/fruits?page=3'), + new NextLink('http://example.com/fruits?page=5') ) ); } diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index db31389..356f6d8 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\MultiLinkage; use JsonApiPhp\JsonApi\Relationship; @@ -50,12 +49,12 @@ public function testFullFledgedResourceObject() '1', new Meta('foo', 'bar'), new Attribute('title', 'Rails is Omakase'), - new SelfLink(new Url('http://self')), + new SelfLink('http://self'), new Relationship( 'author', new Meta('foo', 'bar'), - new SelfLink(new Url('http://rel/author')), - new RelatedLink(new Url('http://author')), + new SelfLink('http://rel/author'), + new RelatedLink('http://author'), new SingleLinkage() ) ) diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index 40aff17..c7224a5 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -18,7 +18,6 @@ use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Link\Url; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\MultiLinkage; use JsonApiPhp\JsonApi\Relationship; @@ -38,14 +37,14 @@ new Attribute('first-name', 'Dan'), new Attribute('last-name', 'Gebhardt'), new Attribute('twitter', 'dgeb'), - new SelfLink(new Url('http://example.com/people/9')) + new SelfLink('http://example.com/people/9') ); $comment05 = new ResourceObject( 'comments', '5', new Attribute('body', 'First!'), - new SelfLink(new Url('http://example.com/comments/5')), + new SelfLink('http://example.com/comments/5'), new Relationship('author', new SingleLinkage(new ResourceIdentifier('people', '2'))) ); @@ -53,7 +52,7 @@ 'comments', '12', new Attribute('body', 'I like XML better'), - new SelfLink(new Url('http://example.com/comments/12')), + new SelfLink('http://example.com/comments/12'), new Relationship('author', new SingleLinkage($dan->identifier())) ); @@ -63,12 +62,12 @@ 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), - new SelfLink(new Url('http://example.com/articles/1')), + new SelfLink('http://example.com/articles/1'), new Relationship( 'author', new SingleLinkage($dan->identifier()), - new SelfLink(new Url('http://example.com/articles/1/relationships/author')), - new RelatedLink(new Url('http://example.com/articles/1/author')) + new SelfLink('http://example.com/articles/1/relationships/author'), + new RelatedLink('http://example.com/articles/1/author') ), new Relationship( 'comments', @@ -76,15 +75,15 @@ $comment05->identifier(), $comment12->identifier() ), - new SelfLink(new Url('http://example.com/articles/1/relationships/comments')), - new RelatedLink(new Url('http://example.com/articles/1/comments')) + new SelfLink('http://example.com/articles/1/relationships/comments'), + new RelatedLink('http://example.com/articles/1/comments') ) ) ), new Included($dan, $comment05, $comment12), - new SelfLink(new Url('http://example.com/articles')), - new NextLink(new Url('http://example.com/articles?page[offset]=2')), - new LastLink(new Url('http://example.com/articles?page[offset]=10')) + new SelfLink('http://example.com/articles'), + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') ); $data_doc_json = json_encode($data_document); @@ -94,9 +93,7 @@ $error_doc = new ErrorDocument( new Error( new Id('1'), - new AboutLink( - new Url('/errors/not_found') - ), + new AboutLink('/errors/not_found'), new Status('404'), new Code('not_found'), new Title('Resource not found'), From afc2c3424f0ee88ea7318df0e3074cf70151b01a Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 18:05:24 -0800 Subject: [PATCH 10/26] Performance improvements --- src/AttachableValue.php | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/AttachableValue.php diff --git a/src/AttachableValue.php b/src/AttachableValue.php deleted file mode 100644 index 4a2a9cb..0000000 --- a/src/AttachableValue.php +++ /dev/null @@ -1,28 +0,0 @@ -key = $key; - $this->value = $value; - } - - public function attachTo(object $o) - { - $o->{$this->key} = $this->value; - } - - public function jsonSerialize() - { - return $this->value; - } -} From fce0e738ddf6b2ce1f9e25cb7ffb2eb739a89be5 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Tue, 27 Feb 2018 22:17:43 -0800 Subject: [PATCH 11/26] Performance improvements --- examples/compound_doc.php | 26 ++++---- examples/simple_doc.php | 7 +-- src/Attribute.php | 10 ++- src/CompoundDocument.php | 2 +- ...tifierSet.php => IdentifierCollection.php} | 7 ++- src/Included.php | 7 ++- src/Link/FirstLink.php | 4 +- src/Link/LastLink.php | 4 +- src/Link/NextLink.php | 4 +- src/Link/PrevLink.php | 4 +- src/Link/RelatedLink.php | 5 +- src/Link/SelfLink.php | 5 +- src/Meta.php | 2 +- src/MultiLinkage.php | 33 ---------- src/NullData.php | 2 +- src/PrimaryData/ResourceField.php | 25 +++----- src/Relationship.php | 32 ---------- ...ceObjectSet.php => ResourceCollection.php} | 7 ++- src/ResourceIdentifier.php | 7 ++- src/ResourceObject.php | 13 ++-- src/SingleLinkage.php | 25 -------- src/ToMany.php | 43 +++++++++++++ ...elationshipMember.php => ToManyMember.php} | 2 +- src/ToNull.php | 26 ++++++++ src/ToOne.php | 33 ++++++++++ src/ToOneMember.php | 10 +++ test/CompoundDocumentTest.php | 44 ++++++------- .../ManyResourceIdentifiersTest.php | 6 +- test/DataDocument/ManyResourceObjectsTest.php | 6 +- test/PaginationLinksTest.php | 4 +- test/ResourceObjectTest.php | 62 ++++++++----------- test/benchmarks/compound10k.php | 25 ++++---- 32 files changed, 260 insertions(+), 232 deletions(-) rename src/{ResourceIdentifierSet.php => IdentifierCollection.php} (76%) delete mode 100644 src/MultiLinkage.php delete mode 100644 src/Relationship.php rename src/{ResourceObjectSet.php => ResourceCollection.php} (76%) delete mode 100644 src/SingleLinkage.php create mode 100644 src/ToMany.php rename src/{RelationshipMember.php => ToManyMember.php} (64%) create mode 100644 src/ToNull.php create mode 100644 src/ToOne.php create mode 100644 src/ToOneMember.php diff --git a/examples/compound_doc.php b/examples/compound_doc.php index 7d65b20..ed52996 100644 --- a/examples/compound_doc.php +++ b/examples/compound_doc.php @@ -1,4 +1,5 @@ identifier())) + new ToOne('author', $dan->identifier()) ); $document = new CompoundDocument( - new ResourceObjectSet( + new ResourceCollection( new ResourceObject( 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), new SelfLink('http://example.com/articles/1'), - new Relationship( + new ToOne( 'author', - new SingleLinkage($dan->identifier()), + $dan->identifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), - new Relationship( + new ToMany( 'comments', - new MultiLinkage( - $comment05->identifier(), - $comment12->identifier() - ), + $comment05->identifier(), + $comment12->identifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) diff --git a/examples/simple_doc.php b/examples/simple_doc.php index 4ebcc3f..a74263a 100644 --- a/examples/simple_doc.php +++ b/examples/simple_doc.php @@ -5,10 +5,9 @@ use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\SingleLinkage; +use JsonApiPhp\JsonApi\ToOne; echo json_encode( new DataDocument( @@ -16,9 +15,9 @@ 'articles', '1', new Attribute('title', 'Rails is Omakase'), - new Relationship( + new ToOne( 'author', - new SingleLinkage(new ResourceIdentifier('author', '9')), + new ResourceIdentifier('author', '9'), new SelfLink('/articles/1/relationships/author'), new RelatedLink('/articles/1/author') ) diff --git a/src/Attribute.php b/src/Attribute.php index dde5b80..6dcedf2 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -6,8 +6,16 @@ final class Attribute extends ResourceField { + private $val; + + public function __construct(string $name, $val) + { + parent::__construct($name); + $this->val = $val; + } + public function attachTo(object $o) { - parent::attachTo(child($o, 'attributes')); + child($o, 'attributes')->{$this->name()} = $this->val; } } diff --git a/src/CompoundDocument.php b/src/CompoundDocument.php index 66e50bf..96fdc8c 100644 --- a/src/CompoundDocument.php +++ b/src/CompoundDocument.php @@ -19,7 +19,7 @@ public function __construct(PrimaryData $data, Included $included, DataDocumentM continue 2; } } - throw new \DomainException('Full linkage required for '.json_encode($resource->identifier())); + throw new \DomainException('Full linkage required for '.$resource->uniqueId()); } $this->doc = combine($data, $included, ...$members); } diff --git a/src/ResourceIdentifierSet.php b/src/IdentifierCollection.php similarity index 76% rename from src/ResourceIdentifierSet.php rename to src/IdentifierCollection.php index 82a4f19..a5737b7 100644 --- a/src/ResourceIdentifierSet.php +++ b/src/IdentifierCollection.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceIdentifierSet implements PrimaryData +final class IdentifierCollection implements PrimaryData { /** * @var ResourceIdentifier[] @@ -28,6 +28,9 @@ public function identifies(ResourceObject $resource): bool public function attachTo(object $o) { - $o->data = $this->identifiers; + $o->data = []; + foreach ($this->identifiers as $identifier) { + $identifier->attachToCollection($o); + } } } diff --git a/src/Included.php b/src/Included.php index 566f4e8..14ba1a2 100644 --- a/src/Included.php +++ b/src/Included.php @@ -4,6 +4,9 @@ final class Included implements DataDocumentMember, \IteratorAggregate { + /** + * @var ResourceObject[] + */ private $resources = []; public function __construct(ResourceObject ...$resources) @@ -24,6 +27,8 @@ public function getIterator() public function attachTo(object $o) { - $o->included = array_values($this->resources); + foreach ($this->resources as $resource) { + $resource->attachAsIncludedTo($o); + } } } diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index 87c98d5..f243f18 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -4,9 +4,9 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class FirstLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember +final class FirstLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember { protected $name = 'first'; } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 7aa9880..791a159 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -4,9 +4,9 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class LastLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember +final class LastLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember { protected $name = 'last'; } diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index bdbf442..0c6a4e1 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -4,9 +4,9 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class NextLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember +final class NextLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember { protected $name = 'next'; } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index eb7fc7f..b103fdb 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -4,9 +4,9 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class PrevLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember +final class PrevLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember { protected $name = 'prev'; } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index de691e6..0857960 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -2,9 +2,10 @@ namespace JsonApiPhp\JsonApi\Link; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToManyMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class RelatedLink extends Link implements RelationshipMember +final class RelatedLink extends Link implements ToOneMember, ToManyMember { protected $name = 'related'; } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 05b2f7d..7447107 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -4,9 +4,10 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\RelationshipMember; +use JsonApiPhp\JsonApi\ToManyMember; +use JsonApiPhp\JsonApi\ToOneMember; -final class SelfLink extends Link implements DataDocumentMember, ResourceMember, RelationshipMember +final class SelfLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember, ToManyMember { protected $name = 'self'; } diff --git a/src/Meta.php b/src/Meta.php index 56316a6..b533002 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -5,7 +5,7 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class Meta implements ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember +final class Meta implements ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, ToOneMember { /** * @var string diff --git a/src/MultiLinkage.php b/src/MultiLinkage.php deleted file mode 100644 index 96b8269..0000000 --- a/src/MultiLinkage.php +++ /dev/null @@ -1,33 +0,0 @@ -identifiers = $identifiers; - } - - public function identifies(ResourceObject $resource): bool - { - foreach ($this->identifiers as $identifier) { - if ($identifier->identifies($resource)) { - return true; - } - } - return false; - } - - public function attachTo(object $o) - { - $o->data = $this->identifiers; - } -} diff --git a/src/NullData.php b/src/NullData.php index 5128a0a..f1049aa 100644 --- a/src/NullData.php +++ b/src/NullData.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class NullData implements PrimaryData +final class NullData implements PrimaryData, ToOneMember { public function identifies(ResourceObject $resource): bool { diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index 98e8e21..d91e7af 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -9,28 +9,21 @@ */ abstract class ResourceField implements ResourceMember { - private $key; - private $value; + private $name; - public function __construct(string $key, $value) + public function __construct(string $name) { - if (isValidName($key) === false) { - throw new \DomainException("Invalid character in a member name '$key'"); + if (isValidName($name) === false) { + throw new \DomainException("Invalid character in a member name '$name'"); } - if ($key === 'id' || $key === 'type') { - throw new \DomainException("Can not use '$key' as a resource field"); + if ($name === 'id' || $name === 'type') { + throw new \DomainException("Can not use '$name' as a resource field"); } - $this->key = $key; - $this->value = $value; + $this->name = $name; } - public function key(): string + public function name(): string { - return $this->key; - } - - public function attachTo(object $o) - { - $o->{$this->key} = $this->value; + return $this->name; } } diff --git a/src/Relationship.php b/src/Relationship.php deleted file mode 100644 index 7d70693..0000000 --- a/src/Relationship.php +++ /dev/null @@ -1,32 +0,0 @@ -members = [$member] + $members; - } - - public function attachTo(object $o) - { - parent::attachTo(child($o, 'relationships')); - } - - public function identifies(ResourceObject $resource): bool - { - foreach ($this->members as $member) { - if ($member instanceof Identifier && $member->identifies($resource)) { - return true; - } - } - return false; - } -} diff --git a/src/ResourceObjectSet.php b/src/ResourceCollection.php similarity index 76% rename from src/ResourceObjectSet.php rename to src/ResourceCollection.php index 678a75b..1458854 100644 --- a/src/ResourceObjectSet.php +++ b/src/ResourceCollection.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceObjectSet implements PrimaryData +final class ResourceCollection implements PrimaryData { /** * @var ResourceObject[] @@ -28,6 +28,9 @@ public function identifies(ResourceObject $resource): bool public function attachTo(object $o) { - $o->data = $this->resources; + $o->data = []; + foreach ($this->resources as $resource) { + $resource->attachToCollection($o); + } } } diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index c8d2e75..c7c20a1 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -4,7 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -final class ResourceIdentifier implements PrimaryData, \JsonSerializable +final class ResourceIdentifier implements PrimaryData, ToManyMember { private $type; private $id; @@ -38,6 +38,11 @@ public function attachTo(object $o) $o->data = $this->identifier; } + public function attachToCollection(object $o): void + { + $o->data[] = $this->identifier; + } + public function jsonSerialize() { return $this->identifier; diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 1328ac9..b6b2edc 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -7,7 +7,7 @@ use JsonApiPhp\JsonApi\PrimaryData\ResourceField; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -final class ResourceObject implements \JsonSerializable, PrimaryData +final class ResourceObject implements PrimaryData { private $res; private $type; @@ -20,7 +20,7 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ $keys = []; foreach ($members as $member) { if ($member instanceof ResourceField) { - $key = $member->key(); + $key = $member->name(); if (isset($keys[$key])) { throw new \LogicException("Field '$key' already exists'"); } @@ -56,9 +56,14 @@ public function attachTo(object $o) $o->data = $this->res; } - public function jsonSerialize() + public function attachAsIncludedTo(object $o): void { - return $this->res; + $o->included[] = $this->res; + } + + public function attachToCollection(object $o): void + { + $o->data[] = $this->res; } public function uniqueId(): string diff --git a/src/SingleLinkage.php b/src/SingleLinkage.php deleted file mode 100644 index 94c5d06..0000000 --- a/src/SingleLinkage.php +++ /dev/null @@ -1,25 +0,0 @@ -identifier = $identifier; - } - - public function identifies(ResourceObject $resource): bool - { - return $this->identifier && $this->identifier->identifies($resource); - } - - public function attachTo(object $o) - { - $o->data = $this->identifier; - } -} diff --git a/src/ToMany.php b/src/ToMany.php new file mode 100644 index 0000000..95b776a --- /dev/null +++ b/src/ToMany.php @@ -0,0 +1,43 @@ +members = $members; + } + + public function attachTo(object $o) + { + $rel = child(child($o, 'relationships'), $this->name()); + $rel->data = []; + foreach ($this->members as $member) { + if ($member instanceof ResourceIdentifier) { + $member->attachToCollection($rel); + } else { + $member->attachTo($rel); + } + } + } + + public function identifies(ResourceObject $resource): bool + { + foreach ($this->members as $member) { + if ($member instanceof Identifier && $member->identifies($resource)) { + return true; + } + } + return false; + } +} diff --git a/src/RelationshipMember.php b/src/ToManyMember.php similarity index 64% rename from src/RelationshipMember.php rename to src/ToManyMember.php index 81ac79d..d34b427 100644 --- a/src/RelationshipMember.php +++ b/src/ToManyMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface RelationshipMember extends Attachable +interface ToManyMember extends Attachable { } diff --git a/src/ToNull.php b/src/ToNull.php new file mode 100644 index 0000000..a92ac79 --- /dev/null +++ b/src/ToNull.php @@ -0,0 +1,26 @@ +members = $members; + } + + public function attachTo(object $o) + { + $val = combine(...$this->members); + $val->data = null; + child($o, 'relationships')->{$this->name()} = $val; + } +} diff --git a/src/ToOne.php b/src/ToOne.php new file mode 100644 index 0000000..e8f926c --- /dev/null +++ b/src/ToOne.php @@ -0,0 +1,33 @@ +val = combine($identifier, ...$members); + $this->identifier = $identifier; + } + + public function attachTo(object $o) + { + child($o, 'relationships')->{$this->name()} = $this->val; + } + + public function identifies(ResourceObject $resource): bool + { + return $this->identifier->identifies($resource); + } +} diff --git a/src/ToOneMember.php b/src/ToOneMember.php new file mode 100644 index 0000000..c537d4a --- /dev/null +++ b/src/ToOneMember.php @@ -0,0 +1,10 @@ +identifier())) + new ToOne('author', $dan->identifier()) ); $document = new CompoundDocument( - new ResourceObjectSet( + new ResourceCollection( new ResourceObject( 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), new SelfLink('http://example.com/articles/1'), - new Relationship( + new ToOne( 'author', - new SingleLinkage($dan->identifier()), + $dan->identifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), - new Relationship( + new ToMany( 'comments', - new MultiLinkage( - $comment05->identifier(), - $comment12->identifier() - ), + $comment05->identifier(), + $comment12->identifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) @@ -171,7 +168,7 @@ public function testOfficialDocsExample() public function testFullLinkage(callable $create_doc) { $this->expectException(\DomainException::class); - $this->expectExceptionMessage('Full linkage required for {"type":"apples","id":"1"}'); + $this->expectExceptionMessage('Full linkage required for apples:1'); $create_doc(); } @@ -186,7 +183,7 @@ function () use ($included) { ], [ function () use ($included) { - return new CompoundDocument(new ResourceObjectSet(), $included); + return new CompoundDocument(new ResourceCollection(), $included); }, ], [ @@ -197,7 +194,10 @@ function () use ($included) { [ function () use ($included) { return new CompoundDocument( - new ResourceIdentifierSet(new ResourceIdentifier('oranges', '1'), new ResourceIdentifier('oranges', '1')), + new IdentifierCollection( + new ResourceIdentifier('oranges', '1'), + new ResourceIdentifier('oranges', '1') + ), $included ); }, @@ -205,7 +205,7 @@ function () use ($included) { [ function () use ($included) { return new CompoundDocument( - new ResourceObjectSet(new ResourceObject('oranges', '1'), new ResourceObject('oranges', '1')), + new ResourceCollection(new ResourceObject('oranges', '1'), new ResourceObject('oranges', '1')), $included ); }, @@ -219,7 +219,7 @@ public function testIncludedResourceMayBeIdentifiedByLinkageInPrimaryData() $article = new ResourceObject( 'articles', '1', - new Relationship('author', new SingleLinkage($author->identifier())) + new ToOne('author', $author->identifier()) ); $doc = new CompoundDocument($article, new Included($author)); $this->assertNotEmpty($doc); @@ -232,12 +232,12 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() 'books', '2', new Attribute('name', 'Domain Driven Design'), - new Relationship('author', new SingleLinkage($writer->identifier())) + new ToOne('author', $writer->identifier()) ); $cart = new ResourceObject( 'shopping-carts', '1', - new Relationship('contents', new MultiLinkage($book->identifier())) + new ToMany('contents', $book->identifier()) ); $doc = new CompoundDocument($cart, new Included($book, $writer)); $this->assertNotEmpty($doc); diff --git a/test/DataDocument/ManyResourceIdentifiersTest.php b/test/DataDocument/ManyResourceIdentifiersTest.php index d4fb181..713fb65 100644 --- a/test/DataDocument/ManyResourceIdentifiersTest.php +++ b/test/DataDocument/ManyResourceIdentifiersTest.php @@ -3,11 +3,11 @@ namespace JsonApiPhp\JsonApi\Test\DataDocument; use JsonApiPhp\JsonApi\DataDocument; +use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; -use JsonApiPhp\JsonApi\ResourceIdentifierSet; use JsonApiPhp\JsonApi\Test\BaseTestCase; class ManyResourceIdentifiersTest extends BaseTestCase @@ -21,7 +21,7 @@ public function testMinimalDocument() } ', new DataDocument( - new ResourceIdentifierSet() + new IdentifierCollection() ) ); } @@ -50,7 +50,7 @@ public function testExtendedDocument() } ', new DataDocument( - new ResourceIdentifierSet( + new IdentifierCollection( new ResourceIdentifier( 'apples', '1', diff --git a/test/DataDocument/ManyResourceObjectsTest.php b/test/DataDocument/ManyResourceObjectsTest.php index 7ba9939..3a2be82 100644 --- a/test/DataDocument/ManyResourceObjectsTest.php +++ b/test/DataDocument/ManyResourceObjectsTest.php @@ -7,8 +7,8 @@ use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; +use JsonApiPhp\JsonApi\ResourceCollection; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\ResourceObjectSet; use JsonApiPhp\JsonApi\Test\BaseTestCase; class ManyResourceObjectsTest extends BaseTestCase @@ -22,7 +22,7 @@ public function testMinimalDocument() } ', new DataDocument( - new ResourceObjectSet() + new ResourceCollection() ) ); } @@ -59,7 +59,7 @@ public function testExtendedDocument() } ', new DataDocument( - new ResourceObjectSet( + new ResourceCollection( new ResourceObject( 'apples', '1', diff --git a/test/PaginationLinksTest.php b/test/PaginationLinksTest.php index c33b105..a75eb24 100644 --- a/test/PaginationLinksTest.php +++ b/test/PaginationLinksTest.php @@ -7,8 +7,8 @@ use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\PrevLink; +use JsonApiPhp\JsonApi\ResourceCollection; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\ResourceObjectSet; class PaginationLinksTest extends BaseTestCase { @@ -30,7 +30,7 @@ public function testPagination() } ', new DataDocument( - new ResourceObjectSet( + new ResourceCollection( new ResourceObject('apples', '1'), new ResourceObject('apples', '2') ), diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index 356f6d8..b3fc79a 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -7,11 +7,11 @@ use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; -use JsonApiPhp\JsonApi\MultiLinkage; -use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\SingleLinkage; +use JsonApiPhp\JsonApi\ToMany; +use JsonApiPhp\JsonApi\ToNull; +use JsonApiPhp\JsonApi\ToOne; class ResourceObjectTest extends BaseTestCase { @@ -50,12 +50,11 @@ public function testFullFledgedResourceObject() new Meta('foo', 'bar'), new Attribute('title', 'Rails is Omakase'), new SelfLink('http://self'), - new Relationship( + new ToNull( 'author', new Meta('foo', 'bar'), new SelfLink('http://rel/author'), - new RelatedLink('http://author'), - new SingleLinkage() + new RelatedLink('http://author') ) ) ) @@ -82,12 +81,7 @@ public function testRelationshipWithSingleIdLinkage() new ResourceObject( 'basket', '1', - new Relationship( - 'content', - new SingleLinkage( - new ResourceIdentifier('apples', '1') - ) - ) + new ToOne('content', new ResourceIdentifier('apples', '1')) ) ) ); @@ -119,12 +113,10 @@ public function testRelationshipWithMultiIdLinkage() new ResourceObject( 'basket', '1', - new Relationship( + new ToMany( 'content', - new MultiLinkage( - new ResourceIdentifier('apples', '1'), - new ResourceIdentifier('pears', '2') - ) + new ResourceIdentifier('apples', '1'), + new ResourceIdentifier('pears', '2') ) ) ) @@ -151,10 +143,7 @@ public function testRelationshipWithEmptyMultiIdLinkage() new ResourceObject( 'basket', '1', - new Relationship( - 'content', - new MultiLinkage() - ) + new ToMany('content') ) ) ); @@ -178,14 +167,14 @@ public function testCanNotCreateIdRelationship() { $this->expectException(\DomainException::class); $this->expectExceptionMessage("Can not use 'id' as a resource field"); - new Relationship('id', new SingleLinkage(new ResourceIdentifier('apples', '1'))); + new ToOne('id', new ResourceIdentifier('apples', '1')); } public function testCanNotCreateTypeRelationship() { $this->expectException(\DomainException::class); $this->expectExceptionMessage("Can not use 'type' as a resource field"); - new Relationship('type', new SingleLinkage(new ResourceIdentifier('apples', '1'))); + new ToOne('type', new ResourceIdentifier('apples', '1')); } /** @@ -207,7 +196,7 @@ public function testRelationshipMustOnlyHaveAllowedCharacters(string $invalid_ch { $this->expectException(\DomainException::class); $this->expectExceptionMessage('Invalid character in a member name'); - new Relationship("foo{$invalid_char}bar", new SingleLinkage()); + new ToNull("foo{$invalid_char}bar"); } public function invalidCharacters() @@ -229,7 +218,7 @@ public function testResourceFieldsMustBeUnique() 'apples', '1', new Attribute('foo', 'bar'), - new Relationship('foo', new SingleLinkage(new ResourceIdentifier('apples', '1'))) + new ToOne('foo', new ResourceIdentifier('apples', '1')) ); } @@ -240,19 +229,18 @@ public function testResourceFieldsMustBeUnique() public function testResourceIdCanBeOmitted() { $this->assertEncodesTo( - '{ - "type": "apples", - "id": null, - "attributes": { - "color": "red" + ' + { + "data": { + "type": "apples", + "id": null, + "attributes": { + "color": "red" + } } - }', - new ResourceObject('apples', null, new Attribute('color', 'red')) + } + ', + new DataDocument(new ResourceObject('apples', null, new Attribute('color', 'red'))) ); } - - public function testEmptySingleLinkageIdentifiesNothing() - { - $this->assertFalse((new SingleLinkage())->identifies(new ResourceObject('something', '1'))); - } } diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index c7224a5..29280b3 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -19,12 +19,11 @@ use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; -use JsonApiPhp\JsonApi\MultiLinkage; -use JsonApiPhp\JsonApi\Relationship; +use JsonApiPhp\JsonApi\ResourceCollection; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\ResourceObjectSet; -use JsonApiPhp\JsonApi\SingleLinkage; +use JsonApiPhp\JsonApi\ToMany; +use JsonApiPhp\JsonApi\ToOne; require_once __DIR__.'/../../vendor/autoload.php'; @@ -45,7 +44,7 @@ '5', new Attribute('body', 'First!'), new SelfLink('http://example.com/comments/5'), - new Relationship('author', new SingleLinkage(new ResourceIdentifier('people', '2'))) + new ToOne('author', new ResourceIdentifier('people', '2')) ); $comment12 = new ResourceObject( @@ -53,28 +52,26 @@ '12', new Attribute('body', 'I like XML better'), new SelfLink('http://example.com/comments/12'), - new Relationship('author', new SingleLinkage($dan->identifier())) + new ToOne('author', $dan->identifier()) ); $data_document = new CompoundDocument( - new ResourceObjectSet( + new ResourceCollection( new ResourceObject( 'articles', '1', new Attribute('title', 'JSON API paints my bikeshed!'), new SelfLink('http://example.com/articles/1'), - new Relationship( + new ToOne( 'author', - new SingleLinkage($dan->identifier()), + $dan->identifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), - new Relationship( + new ToMany( 'comments', - new MultiLinkage( - $comment05->identifier(), - $comment12->identifier() - ), + $comment05->identifier(), + $comment12->identifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) From 0c1592bbf43ae4a70031bec2410d6ae87f337290 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 00:59:09 -0800 Subject: [PATCH 12/26] Performance improvements --- src/CompoundDocument.php | 12 +---------- src/Error.php | 5 ++++- src/Error/Code.php | 2 +- src/Error/Detail.php | 2 +- src/Error/Id.php | 2 +- .../{Parameter.php => SourceParameter.php} | 4 ++-- src/Error/{Pointer.php => SourcePointer.php} | 4 ++-- src/Error/Status.php | 2 +- src/Error/Title.php | 2 +- src/Included.php | 18 ++++++++++++++--- src/ResourceIdentifier.php | 5 ----- src/ResourceObject.php | 20 +++++++++++-------- test/ErrorDocumentTest.php | 12 +++++------ test/benchmarks/compound10k.php | 8 ++++---- 14 files changed, 51 insertions(+), 47 deletions(-) rename src/Error/{Parameter.php => SourceParameter.php} (82%) rename src/Error/{Pointer.php => SourcePointer.php} (81%) diff --git a/src/CompoundDocument.php b/src/CompoundDocument.php index 96fdc8c..58b1917 100644 --- a/src/CompoundDocument.php +++ b/src/CompoundDocument.php @@ -10,17 +10,7 @@ final class CompoundDocument implements \JsonSerializable public function __construct(PrimaryData $data, Included $included, DataDocumentMember ...$members) { - foreach ($included as $resource) { - if ($data->identifies($resource)) { - continue; - } - foreach ($included as $anotherResource) { - if ($anotherResource->identifies($resource)) { - continue 2; - } - } - throw new \DomainException('Full linkage required for '.$resource->uniqueId()); - } + $included->validateLinkage($data); $this->doc = combine($data, $included, ...$members); } diff --git a/src/Error.php b/src/Error.php index 69b0c3b..f94ffcf 100644 --- a/src/Error.php +++ b/src/Error.php @@ -10,7 +10,10 @@ final class Error implements ErrorDocumentMember public function __construct(ErrorMember ...$members) { - $this->error = combine(...$members); + $this->error = (object) []; + foreach ($members as $member) { + $member->attachTo($this->error); + } } public function attachTo(object $o) diff --git a/src/Error/Code.php b/src/Error/Code.php index e8f5e65..e09a8c5 100644 --- a/src/Error/Code.php +++ b/src/Error/Code.php @@ -17,7 +17,7 @@ public function __construct(string $code) $this->code = $code; } - public function attachTo(object $o) + public function attachTo(object $o): void { $o->code = $this->code; } diff --git a/src/Error/Detail.php b/src/Error/Detail.php index 699c4c0..c2bbb69 100644 --- a/src/Error/Detail.php +++ b/src/Error/Detail.php @@ -17,7 +17,7 @@ public function __construct(string $detail) $this->detail = $detail; } - public function attachTo(object $o) + public function attachTo(object $o): void { $o->detail = $this->detail; } diff --git a/src/Error/Id.php b/src/Error/Id.php index ab817a6..9544a0a 100644 --- a/src/Error/Id.php +++ b/src/Error/Id.php @@ -17,7 +17,7 @@ public function __construct(string $id) $this->id = $id; } - public function attachTo(object $o) + public function attachTo(object $o): void { $o->id = $this->id; } diff --git a/src/Error/Parameter.php b/src/Error/SourceParameter.php similarity index 82% rename from src/Error/Parameter.php rename to src/Error/SourceParameter.php index 874b34c..d604b62 100644 --- a/src/Error/Parameter.php +++ b/src/Error/SourceParameter.php @@ -4,7 +4,7 @@ use function JsonApiPhp\JsonApi\child; -final class Parameter implements ErrorMember +final class SourceParameter implements ErrorMember { /** * @var string @@ -19,7 +19,7 @@ public function __construct(string $parameter) $this->parameter = $parameter; } - public function attachTo(object $o) + public function attachTo(object $o): void { child($o, 'source')->parameter = $this->parameter; } diff --git a/src/Error/Pointer.php b/src/Error/SourcePointer.php similarity index 81% rename from src/Error/Pointer.php rename to src/Error/SourcePointer.php index 957743f..70e7f6e 100644 --- a/src/Error/Pointer.php +++ b/src/Error/SourcePointer.php @@ -4,7 +4,7 @@ use function JsonApiPhp\JsonApi\child; -final class Pointer implements ErrorMember +final class SourcePointer implements ErrorMember { private $pointer; @@ -16,7 +16,7 @@ public function __construct(string $pointer) $this->pointer = $pointer; } - public function attachTo(object $o) + public function attachTo(object $o): void { child($o, 'source')->pointer = $this->pointer; } diff --git a/src/Error/Status.php b/src/Error/Status.php index db38ef4..dedd02b 100644 --- a/src/Error/Status.php +++ b/src/Error/Status.php @@ -17,7 +17,7 @@ public function __construct(string $status) $this->status = $status; } - public function attachTo(object $o) + public function attachTo(object $o): void { $o->status = $this->status; } diff --git a/src/Error/Title.php b/src/Error/Title.php index 23a03ff..e639e6d 100644 --- a/src/Error/Title.php +++ b/src/Error/Title.php @@ -18,7 +18,7 @@ public function __construct(string $title) $this->title = $title; } - public function attachTo(object $o) + public function attachTo(object $o): void { $o->title = $this->title; } diff --git a/src/Included.php b/src/Included.php index 14ba1a2..0175fd4 100644 --- a/src/Included.php +++ b/src/Included.php @@ -2,7 +2,9 @@ namespace JsonApiPhp\JsonApi; -final class Included implements DataDocumentMember, \IteratorAggregate +use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; + +final class Included implements Attachable { /** * @var ResourceObject[] @@ -20,9 +22,19 @@ public function __construct(ResourceObject ...$resources) } } - public function getIterator() + public function validateLinkage(PrimaryData $data): void { - return new \ArrayIterator($this->resources); + foreach ($this->resources as $resource) { + if ($data->identifies($resource)) { + continue; + } + foreach ($this->resources as $anotherResource) { + if ($resource !== $anotherResource && $anotherResource->identifies($resource)) { + continue 2; + } + } + throw new \DomainException('Full linkage required for '.$resource->uniqueId()); + } } public function attachTo(object $o) diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index c7c20a1..8b23e18 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -42,9 +42,4 @@ public function attachToCollection(object $o): void { $o->data[] = $this->identifier; } - - public function jsonSerialize() - { - return $this->identifier; - } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index b6b2edc..c5dcd21 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -9,7 +9,6 @@ final class ResourceObject implements PrimaryData { - private $res; private $type; private $id; @@ -31,14 +30,11 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ $this->members = $members; $this->type = $type; $this->id = $id; - $this->res = combine(...$members); - $this->res->type = $type; - $this->res->id = $id; } public function identifier(): ResourceIdentifier { - return new ResourceIdentifier($this->res->type, $this->res->id); + return new ResourceIdentifier($this->type, $this->id); } public function identifies(ResourceObject $resource): bool @@ -53,21 +49,29 @@ public function identifies(ResourceObject $resource): bool public function attachTo(object $o) { - $o->data = $this->res; + $o->data = $this->buildObject(); } public function attachAsIncludedTo(object $o): void { - $o->included[] = $this->res; + $o->included[] = $this->buildObject(); } public function attachToCollection(object $o): void { - $o->data[] = $this->res; + $o->data[] = $this->buildObject(); } public function uniqueId(): string { return "{$this->type}:{$this->id}"; } + + private function buildObject(): object + { + $obj = combine(...$this->members); + $obj->type = $this->type; + $obj->id = $this->id; + return $obj; + } } diff --git a/test/ErrorDocumentTest.php b/test/ErrorDocumentTest.php index bf6fc29..9a9131d 100644 --- a/test/ErrorDocumentTest.php +++ b/test/ErrorDocumentTest.php @@ -7,8 +7,8 @@ use JsonApiPhp\JsonApi\Error\Code; use JsonApiPhp\JsonApi\Error\Detail; use JsonApiPhp\JsonApi\Error\Id; -use JsonApiPhp\JsonApi\Error\Parameter; -use JsonApiPhp\JsonApi\Error\Pointer; +use JsonApiPhp\JsonApi\Error\SourceParameter; +use JsonApiPhp\JsonApi\Error\SourcePointer; use JsonApiPhp\JsonApi\Error\Status; use JsonApiPhp\JsonApi\Error\Title; use JsonApiPhp\JsonApi\ErrorDocument; @@ -72,8 +72,8 @@ public function testExtensiveExample() new Code('not_found'), new Title('Resource not found'), new Detail('We tried hard but could not find anything'), - new Pointer('/data'), - new Parameter('query_string'), + new SourcePointer('/data'), + new SourceParameter('query_string'), new Meta('purpose', 'test') ), new Meta('purpose', 'test'), @@ -106,12 +106,12 @@ public function testMultipleErrors() new Error( new Id('1'), new Code('invalid_parameter'), - new Parameter('foo') + new SourceParameter('foo') ), new Error( new Id('2'), new Code('invalid_parameter'), - new Parameter('bar') + new SourceParameter('bar') ) ) ); diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index 29280b3..e77188f 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -6,8 +6,8 @@ use JsonApiPhp\JsonApi\Error\Code; use JsonApiPhp\JsonApi\Error\Detail; use JsonApiPhp\JsonApi\Error\Id; -use JsonApiPhp\JsonApi\Error\Parameter; -use JsonApiPhp\JsonApi\Error\Pointer; +use JsonApiPhp\JsonApi\Error\SourceParameter; +use JsonApiPhp\JsonApi\Error\SourcePointer; use JsonApiPhp\JsonApi\Error\Status; use JsonApiPhp\JsonApi\Error\Title; use JsonApiPhp\JsonApi\ErrorDocument; @@ -95,8 +95,8 @@ new Code('not_found'), new Title('Resource not found'), new Detail('We tried hard but could not find anything'), - new Pointer('/data'), - new Parameter('query_string'), + new SourcePointer('/data'), + new SourceParameter('query_string'), new Meta('purpose', 'test') ), new Meta('purpose', 'test'), From 4215119c052e0b90ac4f8ec397c439a4317a66ec Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 19:22:29 -0800 Subject: [PATCH 13/26] Performance improvements --- examples/compound_doc.php | 8 +-- src/Attribute.php | 7 ++- src/Included.php | 2 +- src/JsonApi.php | 2 +- src/Link/FirstLink.php | 3 +- src/Link/LastLink.php | 3 +- src/Link/NextLink.php | 3 +- src/Link/PrevLink.php | 3 +- src/Link/SelfLink.php | 10 ++++ src/Meta.php | 12 ++++- src/MetaDocument.php | 2 +- ...umentMember.php => MetaDocumentMember.php} | 2 +- src/PrimaryData/ResourceField.php | 7 +-- src/PrimaryData/ResourceMember.php | 4 ++ src/ResourceIdentifier.php | 2 +- src/ResourceObject.php | 51 +++++++------------ src/ResourceObject/FieldRegistry.php | 20 ++++++++ src/ResourceObject/IdentifierRegistry.php | 33 ++++++++++++ src/ToMany.php | 8 ++- src/ToNull.php | 7 ++- src/ToOne.php | 8 ++- test/CompoundDocumentTest.php | 18 +++---- test/benchmarks/compound10k.php | 8 +-- tmp.php | 40 +++++++++++++++ 24 files changed, 191 insertions(+), 72 deletions(-) rename src/{TopLevelDocumentMember.php => MetaDocumentMember.php} (59%) create mode 100644 src/ResourceObject/FieldRegistry.php create mode 100644 src/ResourceObject/IdentifierRegistry.php create mode 100644 tmp.php diff --git a/examples/compound_doc.php b/examples/compound_doc.php index ed52996..4718da4 100644 --- a/examples/compound_doc.php +++ b/examples/compound_doc.php @@ -37,7 +37,7 @@ '12', new Attribute('body', 'I like XML better'), new SelfLink('http://example.com/comments/12'), - new ToOne('author', $dan->identifier()) + new ToOne('author', $dan->toIdentifier()) ); $document = new CompoundDocument( @@ -49,14 +49,14 @@ new SelfLink('http://example.com/articles/1'), new ToOne( 'author', - $dan->identifier(), + $dan->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), new ToMany( 'comments', - $comment05->identifier(), - $comment12->identifier(), + $comment05->toIdentifier(), + $comment12->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) diff --git a/src/Attribute.php b/src/Attribute.php index 6dcedf2..5bf6b4f 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -3,6 +3,7 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class Attribute extends ResourceField { @@ -16,6 +17,10 @@ public function __construct(string $name, $val) public function attachTo(object $o) { - child($o, 'attributes')->{$this->name()} = $this->val; + child($o, 'attributes')->{$this->name} = $this->val; + } + + public function registerIdentifier(IdentifierRegistry $registry) + { } } diff --git a/src/Included.php b/src/Included.php index 0175fd4..720153d 100644 --- a/src/Included.php +++ b/src/Included.php @@ -33,7 +33,7 @@ public function validateLinkage(PrimaryData $data): void continue 2; } } - throw new \DomainException('Full linkage required for '.$resource->uniqueId()); + throw new \LogicException('Full linkage required for '.$resource->uniqueId()); } } diff --git a/src/JsonApi.php b/src/JsonApi.php index f414d2a..aa1c9db 100644 --- a/src/JsonApi.php +++ b/src/JsonApi.php @@ -2,7 +2,7 @@ namespace JsonApiPhp\JsonApi; -final class JsonApi implements TopLevelDocumentMember, DataDocumentMember +final class JsonApi implements MetaDocumentMember, DataDocumentMember { private $jsonapi; diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index f243f18..144d070 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -3,10 +3,9 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\DataDocumentMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ToOneMember; -final class FirstLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember +final class FirstLink extends Link implements DataDocumentMember, ToOneMember { protected $name = 'first'; } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 791a159..6475228 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -3,10 +3,9 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\DataDocumentMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ToOneMember; -final class LastLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember +final class LastLink extends Link implements DataDocumentMember, ToOneMember { protected $name = 'last'; } diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index 0c6a4e1..cd5358f 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -3,10 +3,9 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\DataDocumentMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ToOneMember; -final class NextLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember +final class NextLink extends Link implements DataDocumentMember, ToOneMember { protected $name = 'next'; } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index b103fdb..2305444 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -3,10 +3,9 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\DataDocumentMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ToOneMember; -final class PrevLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember +final class PrevLink extends Link implements DataDocumentMember, ToOneMember { protected $name = 'prev'; } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 7447107..3144b29 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -4,10 +4,20 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; +use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; use JsonApiPhp\JsonApi\ToManyMember; use JsonApiPhp\JsonApi\ToOneMember; final class SelfLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember, ToManyMember { protected $name = 'self'; + + public function registerResourceField(FieldRegistry $registry) + { + } + + public function registerIdentifier(IdentifierRegistry $registry) + { + } } diff --git a/src/Meta.php b/src/Meta.php index b533002..c0317ff 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -4,8 +4,10 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; +use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; -final class Meta implements ErrorMember, TopLevelDocumentMember, DataDocumentMember, ResourceMember, ToOneMember +final class Meta implements ErrorMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember { /** * @var string @@ -26,4 +28,12 @@ public function attachTo(object $o) { child($o, 'meta')->{$this->key} = $this->value; } + + public function registerResourceField(FieldRegistry $registry) + { + } + + public function registerIdentifier(IdentifierRegistry $registry) + { + } } diff --git a/src/MetaDocument.php b/src/MetaDocument.php index d764bd4..f9c124a 100644 --- a/src/MetaDocument.php +++ b/src/MetaDocument.php @@ -6,7 +6,7 @@ final class MetaDocument implements \JsonSerializable { private $doc; - public function __construct(Meta $meta, TopLevelDocumentMember ...$members) + public function __construct(Meta $meta, MetaDocumentMember ...$members) { $this->doc = combine($meta, ...$members); } diff --git a/src/TopLevelDocumentMember.php b/src/MetaDocumentMember.php similarity index 59% rename from src/TopLevelDocumentMember.php rename to src/MetaDocumentMember.php index 57c8210..ab8674f 100644 --- a/src/TopLevelDocumentMember.php +++ b/src/MetaDocumentMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface TopLevelDocumentMember extends ErrorDocumentMember +interface MetaDocumentMember extends ErrorDocumentMember { } diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceField.php index d91e7af..8596903 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceField.php @@ -2,6 +2,7 @@ namespace JsonApiPhp\JsonApi\PrimaryData; +use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; use function JsonApiPhp\JsonApi\isValidName; /** @@ -9,7 +10,7 @@ */ abstract class ResourceField implements ResourceMember { - private $name; + protected $name; public function __construct(string $name) { @@ -22,8 +23,8 @@ public function __construct(string $name) $this->name = $name; } - public function name(): string + public function registerResourceField(FieldRegistry $registry) { - return $this->name; + $registry->register($this->name); } } diff --git a/src/PrimaryData/ResourceMember.php b/src/PrimaryData/ResourceMember.php index 02b51f9..6633d11 100644 --- a/src/PrimaryData/ResourceMember.php +++ b/src/PrimaryData/ResourceMember.php @@ -3,10 +3,14 @@ namespace JsonApiPhp\JsonApi\PrimaryData; use JsonApiPhp\JsonApi\Attachable; +use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; /** * @internal */ interface ResourceMember extends Attachable { + public function registerResourceField(FieldRegistry $registry); + public function registerIdentifier(IdentifierRegistry $registry); } diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index 8b23e18..08574bf 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -25,7 +25,7 @@ public function __construct(string $type, string $id, Meta $meta = null) public function identifies(ResourceObject $resource): bool { - return $resource->identifier()->equals($this); + return $resource->toIdentifier()->equals($this); } public function equals(ResourceIdentifier $that): bool diff --git a/src/ResourceObject.php b/src/ResourceObject.php index c5dcd21..a4a54d1 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -2,76 +2,59 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\Identifier; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -use JsonApiPhp\JsonApi\PrimaryData\ResourceField; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; +use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class ResourceObject implements PrimaryData { private $type; private $id; - - private $members = []; + private $obj; + private $identifiers; public function __construct(string $type, string $id = null, ResourceMember ...$members) { - $keys = []; - foreach ($members as $member) { - if ($member instanceof ResourceField) { - $key = $member->name(); - if (isset($keys[$key])) { - throw new \LogicException("Field '$key' already exists'"); - } - $keys[$key] = true; - } - } - - $this->members = $members; $this->type = $type; $this->id = $id; + $this->identifiers = new IdentifierRegistry(); + $this->obj = (object) ['type' => $type, 'id' => $id]; + $registry = new FieldRegistry(); + foreach ($members as $member) { + $member->registerResourceField($registry); + $member->registerIdentifier($this->identifiers); + $member->attachTo($this->obj); + } } - public function identifier(): ResourceIdentifier + public function toIdentifier(): ResourceIdentifier { return new ResourceIdentifier($this->type, $this->id); } public function identifies(ResourceObject $resource): bool { - foreach ($this->members as $member) { - if ($member instanceof Identifier && $member->identifies($resource)) { - return true; - } - } - return false; + return $this->identifiers->identifies($resource); } public function attachTo(object $o) { - $o->data = $this->buildObject(); + $o->data = $this->obj; } public function attachAsIncludedTo(object $o): void { - $o->included[] = $this->buildObject(); + $o->included[] = $this->obj; } public function attachToCollection(object $o): void { - $o->data[] = $this->buildObject(); + $o->data[] = $this->obj; } public function uniqueId(): string { return "{$this->type}:{$this->id}"; } - - private function buildObject(): object - { - $obj = combine(...$this->members); - $obj->type = $this->type; - $obj->id = $this->id; - return $obj; - } } diff --git a/src/ResourceObject/FieldRegistry.php b/src/ResourceObject/FieldRegistry.php new file mode 100644 index 0000000..b2d3a06 --- /dev/null +++ b/src/ResourceObject/FieldRegistry.php @@ -0,0 +1,20 @@ +keys[$key])) { + throw new \LogicException("Field '$key' already exists'"); + } + $this->keys[$key] = true; + } +} \ No newline at end of file diff --git a/src/ResourceObject/IdentifierRegistry.php b/src/ResourceObject/IdentifierRegistry.php new file mode 100644 index 0000000..a304fd4 --- /dev/null +++ b/src/ResourceObject/IdentifierRegistry.php @@ -0,0 +1,33 @@ +identifiers[] = $identifier; + } + + public function identifies(ResourceObject $resource): bool + { + foreach ($this->identifiers as $identifier) { + if ($identifier->identifies($resource)) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/ToMany.php b/src/ToMany.php index 95b776a..21301e1 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -4,6 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\Identifier; use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class ToMany extends ResourceField implements Identifier { @@ -20,7 +21,7 @@ public function __construct(string $name, ToManyMember ...$members) public function attachTo(object $o) { - $rel = child(child($o, 'relationships'), $this->name()); + $rel = child(child($o, 'relationships'), $this->name); $rel->data = []; foreach ($this->members as $member) { if ($member instanceof ResourceIdentifier) { @@ -40,4 +41,9 @@ public function identifies(ResourceObject $resource): bool } return false; } + + public function registerIdentifier(IdentifierRegistry $registry) + { + $registry->register($this); + } } diff --git a/src/ToNull.php b/src/ToNull.php index a92ac79..39fdde6 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -3,6 +3,7 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class ToNull extends ResourceField { @@ -21,6 +22,10 @@ public function attachTo(object $o) { $val = combine(...$this->members); $val->data = null; - child($o, 'relationships')->{$this->name()} = $val; + child($o, 'relationships')->{$this->name} = $val; + } + + public function registerIdentifier(IdentifierRegistry $registry) + { } } diff --git a/src/ToOne.php b/src/ToOne.php index e8f926c..d9f845b 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -4,6 +4,7 @@ use JsonApiPhp\JsonApi\PrimaryData\Identifier; use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class ToOne extends ResourceField implements Identifier { @@ -23,11 +24,16 @@ public function __construct(string $name, ResourceIdentifier $identifier, ToOneM public function attachTo(object $o) { - child($o, 'relationships')->{$this->name()} = $this->val; + child($o, 'relationships')->{$this->name} = $this->val; } public function identifies(ResourceObject $resource): bool { return $this->identifier->identifies($resource); } + + public function registerIdentifier(IdentifierRegistry $registry) + { + $registry->register($this->identifier); + } } diff --git a/test/CompoundDocumentTest.php b/test/CompoundDocumentTest.php index e738b75..b505163 100644 --- a/test/CompoundDocumentTest.php +++ b/test/CompoundDocumentTest.php @@ -43,7 +43,7 @@ public function testOfficialDocsExample() '12', new Attribute('body', 'I like XML better'), new SelfLink('http://example.com/comments/12'), - new ToOne('author', $dan->identifier()) + new ToOne('author', $dan->toIdentifier()) ); $document = new CompoundDocument( @@ -55,14 +55,14 @@ public function testOfficialDocsExample() new SelfLink('http://example.com/articles/1'), new ToOne( 'author', - $dan->identifier(), + $dan->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), new ToMany( 'comments', - $comment05->identifier(), - $comment12->identifier(), + $comment05->toIdentifier(), + $comment12->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) @@ -167,7 +167,7 @@ public function testOfficialDocsExample() */ public function testFullLinkage(callable $create_doc) { - $this->expectException(\DomainException::class); + $this->expectException(\LogicException::class); $this->expectExceptionMessage('Full linkage required for apples:1'); $create_doc(); } @@ -219,7 +219,7 @@ public function testIncludedResourceMayBeIdentifiedByLinkageInPrimaryData() $article = new ResourceObject( 'articles', '1', - new ToOne('author', $author->identifier()) + new ToOne('author', $author->toIdentifier()) ); $doc = new CompoundDocument($article, new Included($author)); $this->assertNotEmpty($doc); @@ -232,12 +232,12 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() 'books', '2', new Attribute('name', 'Domain Driven Design'), - new ToOne('author', $writer->identifier()) + new ToOne('author', $writer->toIdentifier()) ); $cart = new ResourceObject( 'shopping-carts', '1', - new ToMany('contents', $book->identifier()) + new ToMany('contents', $book->toIdentifier()) ); $doc = new CompoundDocument($cart, new Included($book, $writer)); $this->assertNotEmpty($doc); @@ -251,6 +251,6 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() public function testCanNotBeManyIncludedResourcesWithEqualIdentifiers() { $apple = new ResourceObject('apples', '1'); - new CompoundDocument($apple->identifier(), new Included($apple, $apple)); + new CompoundDocument($apple->toIdentifier(), new Included($apple, $apple)); } } diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index e77188f..f416fbd 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -52,7 +52,7 @@ '12', new Attribute('body', 'I like XML better'), new SelfLink('http://example.com/comments/12'), - new ToOne('author', $dan->identifier()) + new ToOne('author', $dan->toIdentifier()) ); $data_document = new CompoundDocument( @@ -64,14 +64,14 @@ new SelfLink('http://example.com/articles/1'), new ToOne( 'author', - $dan->identifier(), + $dan->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/author'), new RelatedLink('http://example.com/articles/1/author') ), new ToMany( 'comments', - $comment05->identifier(), - $comment12->identifier(), + $comment05->toIdentifier(), + $comment12->toIdentifier(), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) diff --git a/tmp.php b/tmp.php new file mode 100644 index 0000000..4caa457 --- /dev/null +++ b/tmp.php @@ -0,0 +1,40 @@ + Date: Wed, 28 Feb 2018 21:28:16 -0800 Subject: [PATCH 14/26] Performance improvements --- src/Attribute.php | 11 ++++--- src/Error/ErrorMember.php | 5 ++- src/ErrorDocument.php | 6 +++- src/ErrorDocumentMember.php | 3 +- src/IdentifierCollection.php | 14 ++++---- src/Included.php | 18 ++++++----- src/Link/AboutLink.php | 10 ++++-- src/Link/FirstLink.php | 10 ++++-- src/Link/LastLink.php | 10 ++++-- src/Link/Link.php | 32 ------------------- src/Link/LinkTrait.php | 29 +++++++++++++++++ src/Link/NextLink.php | 10 ++++-- src/Link/PrevLink.php | 10 ++++-- src/Link/RelatedLink.php | 10 ++++-- src/Link/SelfLink.php | 15 ++++----- src/Meta.php | 13 ++------ src/NullData.php | 8 ++--- src/PrimaryData/Identifier.php | 4 +-- src/PrimaryData/IdentityTrait.php | 29 +++++++++++++++++ ...sourceField.php => ResourceFieldTrait.php} | 9 +++--- src/PrimaryData/ResourceMember.php | 5 +-- src/PrimaryData/ResourceMemberTrait.php | 21 ++++++++++++ src/ResourceCollection.php | 16 ++++------ src/ResourceIdentifier.php | 32 +++++++++---------- src/ResourceObject.php | 26 +++++++-------- src/ResourceObject/FieldRegistry.php | 2 +- src/ResourceObject/IdentifierRegistry.php | 26 +++++++-------- src/ToMany.php | 21 ++++++------ src/ToNull.php | 11 ++++--- src/ToOne.php | 20 ++++++------ 30 files changed, 253 insertions(+), 183 deletions(-) delete mode 100644 src/Link/Link.php create mode 100644 src/Link/LinkTrait.php create mode 100644 src/PrimaryData/IdentityTrait.php rename src/PrimaryData/{ResourceField.php => ResourceFieldTrait.php} (71%) create mode 100644 src/PrimaryData/ResourceMemberTrait.php diff --git a/src/Attribute.php b/src/Attribute.php index 5bf6b4f..c54d3b6 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -2,16 +2,19 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; -final class Attribute extends ResourceField +final class Attribute implements ResourceMember { + use ResourceFieldTrait; private $val; public function __construct(string $name, $val) { - parent::__construct($name); + $this->validateFieldName($name); + $this->name = $name; $this->val = $val; } @@ -20,7 +23,7 @@ public function attachTo(object $o) child($o, 'attributes')->{$this->name} = $this->val; } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerAsIdentifier(IdentifierRegistry $registry) { } } diff --git a/src/Error/ErrorMember.php b/src/Error/ErrorMember.php index 7fc06b4..64949f9 100644 --- a/src/Error/ErrorMember.php +++ b/src/Error/ErrorMember.php @@ -2,11 +2,10 @@ namespace JsonApiPhp\JsonApi\Error; -use JsonApiPhp\JsonApi\Attachable; - /** * @internal */ -interface ErrorMember extends Attachable +interface ErrorMember { + public function attachTo(object $o); } diff --git a/src/ErrorDocument.php b/src/ErrorDocument.php index 84a5624..b99c350 100644 --- a/src/ErrorDocument.php +++ b/src/ErrorDocument.php @@ -8,7 +8,11 @@ final class ErrorDocument implements \JsonSerializable public function __construct(Error $error, ErrorDocumentMember ...$members) { - $this->doc = combine($error, ...$members); + $this->doc = (object) []; + $error->attachTo($this->doc); + foreach ($members as $member) { + $member->attachTo($this->doc); + } } public function jsonSerialize() diff --git a/src/ErrorDocumentMember.php b/src/ErrorDocumentMember.php index 01ec48d..5777bb8 100644 --- a/src/ErrorDocumentMember.php +++ b/src/ErrorDocumentMember.php @@ -5,6 +5,7 @@ /** * @internal */ -interface ErrorDocumentMember extends Attachable +interface ErrorDocumentMember { + public function attachTo(object $o); } diff --git a/src/IdentifierCollection.php b/src/IdentifierCollection.php index a5737b7..5c94200 100644 --- a/src/IdentifierCollection.php +++ b/src/IdentifierCollection.php @@ -3,6 +3,7 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class IdentifierCollection implements PrimaryData { @@ -16,21 +17,18 @@ public function __construct(ResourceIdentifier ...$identifiers) $this->identifiers = $identifiers; } - public function identifies(ResourceObject $resource): bool + public function attachTo(object $o) { + $o->data = []; foreach ($this->identifiers as $identifier) { - if ($identifier->identifies($resource)) { - return true; - } + $identifier->attachToCollection($o); } - return false; } - public function attachTo(object $o) + public function registerIn(IdentifierRegistry $registry) { - $o->data = []; foreach ($this->identifiers as $identifier) { - $identifier->attachToCollection($o); + $identifier->registerIn($registry); } } } diff --git a/src/Included.php b/src/Included.php index 720153d..434395c 100644 --- a/src/Included.php +++ b/src/Included.php @@ -3,6 +3,7 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class Included implements Attachable { @@ -11,29 +12,30 @@ final class Included implements Attachable */ private $resources = []; + private $ids; + public function __construct(ResourceObject ...$resources) { + $this->ids = new IdentifierRegistry(); foreach ($resources as $resource) { - $string_id = $resource->uniqueId(); + $string_id = $resource->identity(); if (isset($this->resources[$string_id])) { throw new \LogicException("Resource $string_id is already included"); } $this->resources[$string_id] = $resource; + $resource->registerIn($this->ids); } } public function validateLinkage(PrimaryData $data): void { + $dataRegistry = new IdentifierRegistry(); + $data->registerIn($dataRegistry); foreach ($this->resources as $resource) { - if ($data->identifies($resource)) { + if ($dataRegistry->has($resource->identity()) || $this->ids->has($resource->identity())) { continue; } - foreach ($this->resources as $anotherResource) { - if ($resource !== $anotherResource && $anotherResource->identifies($resource)) { - continue 2; - } - } - throw new \LogicException('Full linkage required for '.$resource->uniqueId()); + throw new \LogicException('Full linkage required for '.$resource->identity()); } } diff --git a/src/Link/AboutLink.php b/src/Link/AboutLink.php index 3005597..495bd3f 100644 --- a/src/Link/AboutLink.php +++ b/src/Link/AboutLink.php @@ -3,8 +3,14 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\Error\ErrorMember; +use function JsonApiPhp\JsonApi\child; -final class AboutLink extends Link implements ErrorMember +final class AboutLink implements ErrorMember { - protected $name = 'about'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->about = $this->link; + } } diff --git a/src/Link/FirstLink.php b/src/Link/FirstLink.php index 144d070..de7e16d 100644 --- a/src/Link/FirstLink.php +++ b/src/Link/FirstLink.php @@ -4,8 +4,14 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class FirstLink extends Link implements DataDocumentMember, ToOneMember +final class FirstLink implements DataDocumentMember, ToOneMember { - protected $name = 'first'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->first = $this->link; + } } diff --git a/src/Link/LastLink.php b/src/Link/LastLink.php index 6475228..f1d1d37 100644 --- a/src/Link/LastLink.php +++ b/src/Link/LastLink.php @@ -4,8 +4,14 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class LastLink extends Link implements DataDocumentMember, ToOneMember +final class LastLink implements DataDocumentMember, ToOneMember { - protected $name = 'last'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->last = $this->link; + } } diff --git a/src/Link/Link.php b/src/Link/Link.php deleted file mode 100644 index e64d941..0000000 --- a/src/Link/Link.php +++ /dev/null @@ -1,32 +0,0 @@ -link = combine(...$metas); - $this->link->href = $url; - } else { - $this->link = $url; - } - } - - public function attachTo(object $o) - { - child($o, 'links')->{$this->name} = $this->link; - } -} diff --git a/src/Link/LinkTrait.php b/src/Link/LinkTrait.php new file mode 100644 index 0000000..df88576 --- /dev/null +++ b/src/Link/LinkTrait.php @@ -0,0 +1,29 @@ +link = (object) ['href' => $url]; + foreach ($metas as $meta) { + $meta->attachTo($this->link); + } + } else { + $this->link = $url; + } + } +} diff --git a/src/Link/NextLink.php b/src/Link/NextLink.php index cd5358f..c9aba56 100644 --- a/src/Link/NextLink.php +++ b/src/Link/NextLink.php @@ -4,8 +4,14 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class NextLink extends Link implements DataDocumentMember, ToOneMember +final class NextLink implements DataDocumentMember, ToOneMember { - protected $name = 'next'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->next = $this->link; + } } diff --git a/src/Link/PrevLink.php b/src/Link/PrevLink.php index 2305444..6563f62 100644 --- a/src/Link/PrevLink.php +++ b/src/Link/PrevLink.php @@ -4,8 +4,14 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class PrevLink extends Link implements DataDocumentMember, ToOneMember +final class PrevLink implements DataDocumentMember, ToOneMember { - protected $name = 'prev'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->prev = $this->link; + } } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index 0857960..54276e9 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -4,8 +4,14 @@ use JsonApiPhp\JsonApi\ToManyMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class RelatedLink extends Link implements ToOneMember, ToManyMember +final class RelatedLink implements ToOneMember, ToManyMember { - protected $name = 'related'; + use LinkTrait; + + public function attachTo(object $o) + { + child($o, 'links')->related = $this->link; + } } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 3144b29..922178d 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -4,20 +4,17 @@ use JsonApiPhp\JsonApi\DataDocumentMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMemberTrait; use JsonApiPhp\JsonApi\ToManyMember; use JsonApiPhp\JsonApi\ToOneMember; +use function JsonApiPhp\JsonApi\child; -final class SelfLink extends Link implements DataDocumentMember, ResourceMember, ToOneMember, ToManyMember +final class SelfLink implements DataDocumentMember, ResourceMember, ToOneMember, ToManyMember { - protected $name = 'self'; + use ResourceMemberTrait, LinkTrait; - public function registerResourceField(FieldRegistry $registry) - { - } - - public function registerIdentifier(IdentifierRegistry $registry) + public function attachTo(object $o): void { + child($o, 'links')->self = $this->link; } } diff --git a/src/Meta.php b/src/Meta.php index c0317ff..efe95f5 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -4,11 +4,12 @@ use JsonApiPhp\JsonApi\Error\ErrorMember; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMemberTrait; final class Meta implements ErrorMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember { + use ResourceMemberTrait; + /** * @var string */ @@ -28,12 +29,4 @@ public function attachTo(object $o) { child($o, 'meta')->{$this->key} = $this->value; } - - public function registerResourceField(FieldRegistry $registry) - { - } - - public function registerIdentifier(IdentifierRegistry $registry) - { - } } diff --git a/src/NullData.php b/src/NullData.php index f1049aa..6fed749 100644 --- a/src/NullData.php +++ b/src/NullData.php @@ -3,16 +3,16 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class NullData implements PrimaryData, ToOneMember { - public function identifies(ResourceObject $resource): bool + public function attachTo(object $o) { - return false; + $o->data = null; } - public function attachTo(object $o) + public function registerIn(IdentifierRegistry $registry) { - $o->data = null; } } diff --git a/src/PrimaryData/Identifier.php b/src/PrimaryData/Identifier.php index d54565b..77d7807 100644 --- a/src/PrimaryData/Identifier.php +++ b/src/PrimaryData/Identifier.php @@ -2,12 +2,12 @@ namespace JsonApiPhp\JsonApi\PrimaryData; -use JsonApiPhp\JsonApi\ResourceObject; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; /** * @internal */ interface Identifier { - public function identifies(ResourceObject $resource): bool; + public function registerIn(IdentifierRegistry $registry); } diff --git a/src/PrimaryData/IdentityTrait.php b/src/PrimaryData/IdentityTrait.php new file mode 100644 index 0000000..f1b7c55 --- /dev/null +++ b/src/PrimaryData/IdentityTrait.php @@ -0,0 +1,29 @@ +type}:{$this->id}"; + } +} diff --git a/src/PrimaryData/ResourceField.php b/src/PrimaryData/ResourceFieldTrait.php similarity index 71% rename from src/PrimaryData/ResourceField.php rename to src/PrimaryData/ResourceFieldTrait.php index 8596903..282bc10 100644 --- a/src/PrimaryData/ResourceField.php +++ b/src/PrimaryData/ResourceFieldTrait.php @@ -8,11 +8,11 @@ /** * @internal */ -abstract class ResourceField implements ResourceMember +trait ResourceFieldTrait { - protected $name; + private $name; - public function __construct(string $name) + private function validateFieldName(string $name): void { if (isValidName($name) === false) { throw new \DomainException("Invalid character in a member name '$name'"); @@ -20,10 +20,9 @@ public function __construct(string $name) if ($name === 'id' || $name === 'type') { throw new \DomainException("Can not use '$name' as a resource field"); } - $this->name = $name; } - public function registerResourceField(FieldRegistry $registry) + public function registerField(FieldRegistry $registry) { $registry->register($this->name); } diff --git a/src/PrimaryData/ResourceMember.php b/src/PrimaryData/ResourceMember.php index 6633d11..618cb30 100644 --- a/src/PrimaryData/ResourceMember.php +++ b/src/PrimaryData/ResourceMember.php @@ -11,6 +11,7 @@ */ interface ResourceMember extends Attachable { - public function registerResourceField(FieldRegistry $registry); - public function registerIdentifier(IdentifierRegistry $registry); + public function registerField(FieldRegistry $registry); + + public function registerAsIdentifier(IdentifierRegistry $registry); } diff --git a/src/PrimaryData/ResourceMemberTrait.php b/src/PrimaryData/ResourceMemberTrait.php new file mode 100644 index 0000000..0cc53a4 --- /dev/null +++ b/src/PrimaryData/ResourceMemberTrait.php @@ -0,0 +1,21 @@ +resources = $resources; } - public function identifies(ResourceObject $resource): bool + public function attachTo(object $o) { - foreach ($this->resources as $myResource) { - if ($myResource->identifies($resource)) { - return true; - } + $o->data = []; + foreach ($this->resources as $resource) { + $resource->attachToCollection($o); } - return false; } - public function attachTo(object $o) + public function registerIn(IdentifierRegistry $registry) { - $o->data = []; foreach ($this->resources as $resource) { - $resource->attachToCollection($o); + $resource->registerIn($registry); } } } diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index 08574bf..9615a56 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -2,44 +2,44 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\PrimaryData\IdentityTrait; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; final class ResourceIdentifier implements PrimaryData, ToManyMember { - private $type; - private $id; - private $identifier; + use IdentityTrait; + private $obj; public function __construct(string $type, string $id, Meta $meta = null) { - $this->identifier = (object) [ + if (isValidName($type) === false) { + throw new \DomainException("Invalid type value: $type"); + } + + $this->obj = (object) [ 'type' => $type, 'id' => $id, ]; if ($meta) { - $meta->attachTo($this->identifier); + $meta->attachTo($this->obj); } $this->type = $type; $this->id = $id; } - public function identifies(ResourceObject $resource): bool - { - return $resource->toIdentifier()->equals($this); - } - - public function equals(ResourceIdentifier $that): bool + public function attachTo(object $o) { - return $this->type === $that->type && $this->id === $that->id; + $o->data = $this->obj; } - public function attachTo(object $o) + public function attachToCollection(object $o): void { - $o->data = $this->identifier; + $o->data[] = $this->obj; } - public function attachToCollection(object $o): void + public function registerIn(IdentifierRegistry $registry) { - $o->data[] = $this->identifier; + $registry->add($this->identity()); } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index a4a54d1..1260ff1 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -2,6 +2,7 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\PrimaryData\IdentityTrait; use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ResourceObject\FieldRegistry; @@ -9,21 +10,23 @@ final class ResourceObject implements PrimaryData { - private $type; - private $id; + use IdentityTrait; private $obj; - private $identifiers; + private $ids; public function __construct(string $type, string $id = null, ResourceMember ...$members) { + if (isValidName($type) === false) { + throw new \DomainException("Invalid type value: $type"); + } $this->type = $type; $this->id = $id; - $this->identifiers = new IdentifierRegistry(); + $this->ids = new IdentifierRegistry(); $this->obj = (object) ['type' => $type, 'id' => $id]; - $registry = new FieldRegistry(); + $fields = new FieldRegistry(); foreach ($members as $member) { - $member->registerResourceField($registry); - $member->registerIdentifier($this->identifiers); + $member->registerField($fields); + $member->registerAsIdentifier($this->ids); $member->attachTo($this->obj); } } @@ -33,9 +36,9 @@ public function toIdentifier(): ResourceIdentifier return new ResourceIdentifier($this->type, $this->id); } - public function identifies(ResourceObject $resource): bool + public function registerIn(IdentifierRegistry $registry) { - return $this->identifiers->identifies($resource); + $this->ids->registerIn($registry); } public function attachTo(object $o) @@ -52,9 +55,4 @@ public function attachToCollection(object $o): void { $o->data[] = $this->obj; } - - public function uniqueId(): string - { - return "{$this->type}:{$this->id}"; - } } diff --git a/src/ResourceObject/FieldRegistry.php b/src/ResourceObject/FieldRegistry.php index b2d3a06..d3ebca8 100644 --- a/src/ResourceObject/FieldRegistry.php +++ b/src/ResourceObject/FieldRegistry.php @@ -17,4 +17,4 @@ public function register(string $key): void } $this->keys[$key] = true; } -} \ No newline at end of file +} diff --git a/src/ResourceObject/IdentifierRegistry.php b/src/ResourceObject/IdentifierRegistry.php index a304fd4..b940864 100644 --- a/src/ResourceObject/IdentifierRegistry.php +++ b/src/ResourceObject/IdentifierRegistry.php @@ -4,30 +4,26 @@ namespace JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\PrimaryData\Identifier; -use JsonApiPhp\JsonApi\ResourceObject; /** * @internal */ final class IdentifierRegistry implements Identifier { - /** - * @var Identifier[] - */ - private $identifiers = []; + private $ids = []; - public function register(Identifier $identifier): void + public function add(string $id): void { - $this->identifiers[] = $identifier; + $this->ids[$id] = true; } - public function identifies(ResourceObject $resource): bool + public function has(string $id): bool { - foreach ($this->identifiers as $identifier) { - if ($identifier->identifies($resource)) { - return true; - } - } - return false; + return isset($this->ids[$id]); } -} \ No newline at end of file + + public function registerIn(IdentifierRegistry $registry) + { + $registry->ids = array_merge($registry->ids, $this->ids); + } +} diff --git a/src/ToMany.php b/src/ToMany.php index 21301e1..fff26c3 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -3,11 +3,13 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\PrimaryData\Identifier; -use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; -final class ToMany extends ResourceField implements Identifier +final class ToMany implements ResourceMember { + use ResourceFieldTrait; /** * @var ToOneMember[] */ @@ -15,7 +17,8 @@ final class ToMany extends ResourceField implements Identifier public function __construct(string $name, ToManyMember ...$members) { - parent::__construct($name); + $this->validateFieldName($name); + $this->name = $name; $this->members = $members; } @@ -32,18 +35,12 @@ public function attachTo(object $o) } } - public function identifies(ResourceObject $resource): bool + public function registerAsIdentifier(IdentifierRegistry $registry) { foreach ($this->members as $member) { - if ($member instanceof Identifier && $member->identifies($resource)) { - return true; + if ($member instanceof Identifier) { + $member->registerIn($registry); } } - return false; - } - - public function registerIdentifier(IdentifierRegistry $registry) - { - $registry->register($this); } } diff --git a/src/ToNull.php b/src/ToNull.php index 39fdde6..3d264c9 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -2,11 +2,13 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; -final class ToNull extends ResourceField +final class ToNull implements ResourceMember { + use ResourceFieldTrait; /** * @var ToOneMember[] */ @@ -14,7 +16,8 @@ final class ToNull extends ResourceField public function __construct(string $name, ToOneMember ...$members) { - parent::__construct($name); + $this->validateFieldName($name); + $this->name = $name; $this->members = $members; } @@ -25,7 +28,7 @@ public function attachTo(object $o) child($o, 'relationships')->{$this->name} = $val; } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerAsIdentifier(IdentifierRegistry $registry) { } } diff --git a/src/ToOne.php b/src/ToOne.php index d9f845b..44176eb 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -2,12 +2,14 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\Identifier; -use JsonApiPhp\JsonApi\PrimaryData\ResourceField; +use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; +use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; -final class ToOne extends ResourceField implements Identifier +final class ToOne implements ResourceMember { + use ResourceFieldTrait; + /** * @var ResourceIdentifier */ @@ -17,7 +19,8 @@ final class ToOne extends ResourceField implements Identifier public function __construct(string $name, ResourceIdentifier $identifier, ToOneMember ...$members) { - parent::__construct($name); + $this->validateFieldName($name); + $this->name = $name; $this->val = combine($identifier, ...$members); $this->identifier = $identifier; } @@ -27,13 +30,8 @@ public function attachTo(object $o) child($o, 'relationships')->{$this->name} = $this->val; } - public function identifies(ResourceObject $resource): bool - { - return $this->identifier->identifies($resource); - } - - public function registerIdentifier(IdentifierRegistry $registry) + public function registerAsIdentifier(IdentifierRegistry $registry) { - $registry->register($this->identifier); + $this->identifier->registerIn($registry); } } From 8eec268c9d2024f3d8fbee4375190cdaa5ef4016 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 22:08:17 -0800 Subject: [PATCH 15/26] Performance improvements --- examples/compound_doc.php | 7 +++-- src/Attribute.php | 8 +++--- src/CompoundDocument.php | 3 ++- src/DataDocument.php | 3 ++- src/Error.php | 3 ++- src/Error/Code.php | 2 ++ src/Error/Detail.php | 2 ++ src/Error/Id.php | 2 ++ src/Error/SourceParameter.php | 1 + src/Error/SourcePointer.php | 1 + src/Error/Status.php | 2 ++ src/Error/Title.php | 2 ++ src/ErrorDocument.php | 2 ++ src/IdentifierCollection.php | 7 ++--- src/Included.php | 5 ++-- src/{ => Internal}/Attachable.php | 2 +- src/{ => Internal}/DataDocumentMember.php | 2 +- src/{ => Internal}/ErrorDocumentMember.php | 2 +- src/{Error => Internal}/ErrorMember.php | 2 +- .../FieldRegistry.php | 2 +- src/{PrimaryData => Internal}/Identifier.php | 4 +-- .../IdentifierRegistry.php | 4 +-- .../IdentityTrait.php | 2 +- src/{Link => Internal}/LinkTrait.php | 2 +- src/Internal/MetaDocumentMember.php | 10 +++++++ src/{PrimaryData => Internal}/PrimaryData.php | 4 +-- .../ResourceFieldTrait.php | 3 +-- src/Internal/ResourceMember.php | 13 +++++++++ src/{ => Internal}/ToManyMember.php | 2 +- src/{ => Internal}/ToOneMember.php | 2 +- src/JsonApi.php | 6 ++++- src/Link/AboutLink.php | 3 ++- src/Link/FirstLink.php | 6 ++--- src/Link/LastLink.php | 6 ++--- src/Link/NextLink.php | 6 ++--- src/Link/PrevLink.php | 6 ++--- src/Link/RelatedLink.php | 5 ++-- src/Link/SelfLink.php | 27 ++++++++++++++----- src/Meta.php | 23 +++++++++++----- src/MetaDocument.php | 2 ++ src/MetaDocumentMember.php | 10 ------- src/NullData.php | 6 ++--- src/PrimaryData/ResourceMember.php | 17 ------------ src/PrimaryData/ResourceMemberTrait.php | 21 --------------- src/ResourceCollection.php | 4 +-- src/ResourceIdentifier.php | 8 +++--- src/ResourceObject.php | 12 ++++----- src/ToMany.php | 12 +++++---- src/ToNull.php | 15 ++++++----- src/ToOne.php | 15 ++++++----- src/functions.php | 2 ++ test/CompoundDocumentTest.php | 8 +++--- test/ResourceObjectTest.php | 7 +++-- test/benchmarks/compound10k.php | 7 +++-- 54 files changed, 189 insertions(+), 151 deletions(-) rename src/{ => Internal}/Attachable.php (75%) rename src/{ => Internal}/DataDocumentMember.php (73%) rename src/{ => Internal}/ErrorDocumentMember.php (76%) rename src/{Error => Internal}/ErrorMember.php (75%) rename src/{ResourceObject => Internal}/FieldRegistry.php (87%) rename src/{PrimaryData => Internal}/Identifier.php (58%) rename src/{ResourceObject => Internal}/IdentifierRegistry.php (83%) rename src/{PrimaryData => Internal}/IdentityTrait.php (88%) rename src/{Link => Internal}/LinkTrait.php (92%) create mode 100644 src/Internal/MetaDocumentMember.php rename src/{PrimaryData => Internal}/PrimaryData.php (58%) rename src/{PrimaryData => Internal}/ResourceFieldTrait.php (86%) create mode 100644 src/Internal/ResourceMember.php rename src/{ => Internal}/ToManyMember.php (71%) rename src/{ => Internal}/ToOneMember.php (71%) delete mode 100644 src/MetaDocumentMember.php delete mode 100644 src/PrimaryData/ResourceMember.php delete mode 100644 src/PrimaryData/ResourceMemberTrait.php diff --git a/examples/compound_doc.php b/examples/compound_doc.php index 4718da4..d93e8b3 100644 --- a/examples/compound_doc.php +++ b/examples/compound_doc.php @@ -2,6 +2,7 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\CompoundDocument; +use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Included; use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; @@ -55,8 +56,10 @@ ), new ToMany( 'comments', - $comment05->toIdentifier(), - $comment12->toIdentifier(), + new IdentifierCollection( + $comment05->toIdentifier(), + $comment12->toIdentifier() + ), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) diff --git a/src/Attribute.php b/src/Attribute.php index c54d3b6..bbefe72 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -2,9 +2,9 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; +use JsonApiPhp\JsonApi\Internal\ResourceMember; final class Attribute implements ResourceMember { @@ -23,7 +23,7 @@ public function attachTo(object $o) child($o, 'attributes')->{$this->name} = $this->val; } - public function registerAsIdentifier(IdentifierRegistry $registry) + public function registerIdentifier(IdentifierRegistry $registry) { } } diff --git a/src/CompoundDocument.php b/src/CompoundDocument.php index 58b1917..05bc119 100644 --- a/src/CompoundDocument.php +++ b/src/CompoundDocument.php @@ -2,7 +2,8 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\Internal\DataDocumentMember; +use JsonApiPhp\JsonApi\Internal\PrimaryData; final class CompoundDocument implements \JsonSerializable { diff --git a/src/DataDocument.php b/src/DataDocument.php index 130ff86..68fa2cd 100644 --- a/src/DataDocument.php +++ b/src/DataDocument.php @@ -2,7 +2,8 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; +use JsonApiPhp\JsonApi\Internal\DataDocumentMember; +use JsonApiPhp\JsonApi\Internal\PrimaryData; final class DataDocument implements \JsonSerializable { diff --git a/src/Error.php b/src/Error.php index f94ffcf..65b3071 100644 --- a/src/Error.php +++ b/src/Error.php @@ -2,7 +2,8 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Error\ErrorMember; +use JsonApiPhp\JsonApi\Internal\ErrorDocumentMember; +use JsonApiPhp\JsonApi\Internal\ErrorMember; final class Error implements ErrorDocumentMember { diff --git a/src/Error/Code.php b/src/Error/Code.php index e09a8c5..eafbc72 100644 --- a/src/Error/Code.php +++ b/src/Error/Code.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; + final class Code implements ErrorMember { /** diff --git a/src/Error/Detail.php b/src/Error/Detail.php index c2bbb69..5950b46 100644 --- a/src/Error/Detail.php +++ b/src/Error/Detail.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; + final class Detail implements ErrorMember { /** diff --git a/src/Error/Id.php b/src/Error/Id.php index 9544a0a..3553f02 100644 --- a/src/Error/Id.php +++ b/src/Error/Id.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; + final class Id implements ErrorMember { /** diff --git a/src/Error/SourceParameter.php b/src/Error/SourceParameter.php index d604b62..613967a 100644 --- a/src/Error/SourceParameter.php +++ b/src/Error/SourceParameter.php @@ -2,6 +2,7 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; use function JsonApiPhp\JsonApi\child; final class SourceParameter implements ErrorMember diff --git a/src/Error/SourcePointer.php b/src/Error/SourcePointer.php index 70e7f6e..bfc6394 100644 --- a/src/Error/SourcePointer.php +++ b/src/Error/SourcePointer.php @@ -2,6 +2,7 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; use function JsonApiPhp\JsonApi\child; final class SourcePointer implements ErrorMember diff --git a/src/Error/Status.php b/src/Error/Status.php index dedd02b..a61031f 100644 --- a/src/Error/Status.php +++ b/src/Error/Status.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; + final class Status implements ErrorMember { /** diff --git a/src/Error/Title.php b/src/Error/Title.php index e639e6d..d61a706 100644 --- a/src/Error/Title.php +++ b/src/Error/Title.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi\Error; +use JsonApiPhp\JsonApi\Internal\ErrorMember; + final class Title implements ErrorMember { /** diff --git a/src/ErrorDocument.php b/src/ErrorDocument.php index b99c350..382d5a6 100644 --- a/src/ErrorDocument.php +++ b/src/ErrorDocument.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\ErrorDocumentMember; + final class ErrorDocument implements \JsonSerializable { private $doc; diff --git a/src/IdentifierCollection.php b/src/IdentifierCollection.php index 5c94200..0d6fc0e 100644 --- a/src/IdentifierCollection.php +++ b/src/IdentifierCollection.php @@ -2,10 +2,11 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\PrimaryData; +use JsonApiPhp\JsonApi\Internal\ToManyMember; -final class IdentifierCollection implements PrimaryData +final class IdentifierCollection implements PrimaryData, ToManyMember { /** * @var ResourceIdentifier[] diff --git a/src/Included.php b/src/Included.php index 434395c..f4f4800 100644 --- a/src/Included.php +++ b/src/Included.php @@ -2,8 +2,9 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\PrimaryData; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\Attachable; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\PrimaryData; final class Included implements Attachable { diff --git a/src/Attachable.php b/src/Internal/Attachable.php similarity index 75% rename from src/Attachable.php rename to src/Internal/Attachable.php index ac3f6bf..fbbe24c 100644 --- a/src/Attachable.php +++ b/src/Internal/Attachable.php @@ -1,6 +1,6 @@ self = $this->link; } + + public function registerField(FieldRegistry $registry) + { + } + + public function registerIdentifier(IdentifierRegistry $registry) + { + } + + public function attachToCollection(object $o) + { + // TODO: Implement attachToCollection() method. + } } diff --git a/src/Meta.php b/src/Meta.php index efe95f5..632babf 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -2,14 +2,17 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Error\ErrorMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMemberTrait; +use JsonApiPhp\JsonApi\Internal\DataDocumentMember; +use JsonApiPhp\JsonApi\Internal\ErrorDocumentMember; +use JsonApiPhp\JsonApi\Internal\ErrorMember; +use JsonApiPhp\JsonApi\Internal\FieldRegistry; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\MetaDocumentMember; +use JsonApiPhp\JsonApi\Internal\ResourceMember; +use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class Meta implements ErrorMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember +final class Meta implements ErrorMember, ErrorDocumentMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember { - use ResourceMemberTrait; - /** * @var string */ @@ -29,4 +32,12 @@ public function attachTo(object $o) { child($o, 'meta')->{$this->key} = $this->value; } + + public function registerField(FieldRegistry $registry) + { + } + + public function registerIdentifier(IdentifierRegistry $registry) + { + } } diff --git a/src/MetaDocument.php b/src/MetaDocument.php index f9c124a..72ca320 100644 --- a/src/MetaDocument.php +++ b/src/MetaDocument.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\MetaDocumentMember; + final class MetaDocument implements \JsonSerializable { private $doc; diff --git a/src/MetaDocumentMember.php b/src/MetaDocumentMember.php deleted file mode 100644 index ab8674f..0000000 --- a/src/MetaDocumentMember.php +++ /dev/null @@ -1,10 +0,0 @@ -registerField($fields); - $member->registerAsIdentifier($this->ids); + $member->registerIdentifier($this->ids); $member->attachTo($this->obj); } } diff --git a/src/ToMany.php b/src/ToMany.php index fff26c3..d7ced47 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -2,10 +2,12 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\Identifier; -use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\Identifier; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; +use JsonApiPhp\JsonApi\Internal\ResourceMember; +use JsonApiPhp\JsonApi\Internal\ToManyMember; +use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToMany implements ResourceMember { @@ -35,7 +37,7 @@ public function attachTo(object $o) } } - public function registerAsIdentifier(IdentifierRegistry $registry) + public function registerIdentifier(IdentifierRegistry $registry) { foreach ($this->members as $member) { if ($member instanceof Identifier) { diff --git a/src/ToNull.php b/src/ToNull.php index 3d264c9..28c1993 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -2,9 +2,10 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; +use JsonApiPhp\JsonApi\Internal\ResourceMember; +use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToNull implements ResourceMember { @@ -23,12 +24,12 @@ public function __construct(string $name, ToOneMember ...$members) public function attachTo(object $o) { - $val = combine(...$this->members); - $val->data = null; - child($o, 'relationships')->{$this->name} = $val; + $obj = combine(...$this->members); + $obj->data = null; + child($o, 'relationships')->{$this->name} = $obj; } - public function registerAsIdentifier(IdentifierRegistry $registry) + public function registerIdentifier(IdentifierRegistry $registry) { } } diff --git a/src/ToOne.php b/src/ToOne.php index 44176eb..80a5113 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -2,9 +2,10 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\PrimaryData\ResourceFieldTrait; -use JsonApiPhp\JsonApi\PrimaryData\ResourceMember; -use JsonApiPhp\JsonApi\ResourceObject\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; +use JsonApiPhp\JsonApi\Internal\ResourceMember; +use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToOne implements ResourceMember { @@ -15,22 +16,22 @@ final class ToOne implements ResourceMember */ private $identifier; - private $val; + private $obj; public function __construct(string $name, ResourceIdentifier $identifier, ToOneMember ...$members) { $this->validateFieldName($name); $this->name = $name; - $this->val = combine($identifier, ...$members); + $this->obj = combine($identifier, ...$members); $this->identifier = $identifier; } public function attachTo(object $o) { - child($o, 'relationships')->{$this->name} = $this->val; + child($o, 'relationships')->{$this->name} = $this->obj; } - public function registerAsIdentifier(IdentifierRegistry $registry) + public function registerIdentifier(IdentifierRegistry $registry) { $this->identifier->registerIn($registry); } diff --git a/src/functions.php b/src/functions.php index 69bb00d..907fab1 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,6 +2,8 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\Attachable; + function combine(Attachable ...$members): object { $obj = (object) []; diff --git a/test/CompoundDocumentTest.php b/test/CompoundDocumentTest.php index b505163..c50b25f 100644 --- a/test/CompoundDocumentTest.php +++ b/test/CompoundDocumentTest.php @@ -61,8 +61,10 @@ public function testOfficialDocsExample() ), new ToMany( 'comments', - $comment05->toIdentifier(), - $comment12->toIdentifier(), + new IdentifierCollection( + $comment05->toIdentifier(), + $comment12->toIdentifier() + ), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) @@ -237,7 +239,7 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() $cart = new ResourceObject( 'shopping-carts', '1', - new ToMany('contents', $book->toIdentifier()) + new ToMany('contents', new IdentifierCollection($book->toIdentifier())) ); $doc = new CompoundDocument($cart, new Included($book, $writer)); $this->assertNotEmpty($doc); diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index b3fc79a..9bb6355 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -4,6 +4,7 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\DataDocument; +use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; @@ -115,8 +116,10 @@ public function testRelationshipWithMultiIdLinkage() '1', new ToMany( 'content', - new ResourceIdentifier('apples', '1'), - new ResourceIdentifier('pears', '2') + new IdentifierCollection( + new ResourceIdentifier('apples', '1'), + new ResourceIdentifier('pears', '2') + ) ) ) ) diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index f416fbd..270f112 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -11,6 +11,7 @@ use JsonApiPhp\JsonApi\Error\Status; use JsonApiPhp\JsonApi\Error\Title; use JsonApiPhp\JsonApi\ErrorDocument; +use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Included; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\AboutLink; @@ -70,8 +71,10 @@ ), new ToMany( 'comments', - $comment05->toIdentifier(), - $comment12->toIdentifier(), + new IdentifierCollection( + $comment05->toIdentifier(), + $comment12->toIdentifier() + ), new SelfLink('http://example.com/articles/1/relationships/comments'), new RelatedLink('http://example.com/articles/1/comments') ) From a949291a7d5ef00cd9f06ef9d6b52b40e7ea813f Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 22:40:58 -0800 Subject: [PATCH 16/26] Performance improvements --- src/Internal/ErrorDocumentMember.php | 3 +-- src/Internal/ErrorMember.php | 3 +-- src/Internal/IdentifierRegistry.php | 7 +++---- src/ResourceObject.php | 8 ++++---- test/PaginationLinksTest.php | 4 ++-- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Internal/ErrorDocumentMember.php b/src/Internal/ErrorDocumentMember.php index 05d528e..b0d01c1 100644 --- a/src/Internal/ErrorDocumentMember.php +++ b/src/Internal/ErrorDocumentMember.php @@ -5,7 +5,6 @@ /** * @internal */ -interface ErrorDocumentMember +interface ErrorDocumentMember extends Attachable { - public function attachTo(object $o); } diff --git a/src/Internal/ErrorMember.php b/src/Internal/ErrorMember.php index c906415..0ea2c5d 100644 --- a/src/Internal/ErrorMember.php +++ b/src/Internal/ErrorMember.php @@ -5,7 +5,6 @@ /** * @internal */ -interface ErrorMember +interface ErrorMember extends Attachable { - public function attachTo(object $o); } diff --git a/src/Internal/IdentifierRegistry.php b/src/Internal/IdentifierRegistry.php index 4e503ce..a7646d6 100644 --- a/src/Internal/IdentifierRegistry.php +++ b/src/Internal/IdentifierRegistry.php @@ -6,7 +6,7 @@ /** * @internal */ -final class IdentifierRegistry implements Identifier +final class IdentifierRegistry { private $ids = []; @@ -19,9 +19,8 @@ public function has(string $id): bool { return isset($this->ids[$id]); } - - public function registerIn(IdentifierRegistry $registry) + public function merge(IdentifierRegistry $registry) { - $registry->ids = array_merge($registry->ids, $this->ids); + $this->ids = array_merge($this->ids, $registry->ids); } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index d66ec69..c5e132d 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -12,7 +12,7 @@ final class ResourceObject implements PrimaryData { use IdentityTrait; private $obj; - private $ids; + private $registry; public function __construct(string $type, string $id = null, ResourceMember ...$members) { @@ -21,12 +21,12 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ } $this->type = $type; $this->id = $id; - $this->ids = new IdentifierRegistry(); + $this->registry = new IdentifierRegistry(); $this->obj = (object) ['type' => $type, 'id' => $id]; $fields = new FieldRegistry(); foreach ($members as $member) { $member->registerField($fields); - $member->registerIdentifier($this->ids); + $member->registerIdentifier($this->registry); $member->attachTo($this->obj); } } @@ -38,7 +38,7 @@ public function toIdentifier(): ResourceIdentifier public function registerIn(IdentifierRegistry $registry) { - $this->ids->registerIn($registry); + $registry->merge($this->registry); } public function attachTo(object $o) diff --git a/test/PaginationLinksTest.php b/test/PaginationLinksTest.php index a75eb24..3ba40bd 100644 --- a/test/PaginationLinksTest.php +++ b/test/PaginationLinksTest.php @@ -35,9 +35,9 @@ public function testPagination() new ResourceObject('apples', '2') ), new FirstLink('http://example.com/fruits?page=first'), - new LastLink('http://example.com/fruits?page=last'), new PrevLink('http://example.com/fruits?page=3'), - new NextLink('http://example.com/fruits?page=5') + new NextLink('http://example.com/fruits?page=5'), + new LastLink('http://example.com/fruits?page=last') ) ); } From bff9d5372fe2658ba0b5d0015d5af20294eb9d5c Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 23:32:44 -0800 Subject: [PATCH 17/26] Performance improvements --- examples/compound_doc.php | 17 +++--- src/Included.php | 6 +-- src/Internal/IdentifierRegistry.php | 1 + src/Internal/IdentityTrait.php | 2 +- src/Internal/PaginationLink.php | 8 +++ src/Link/FirstLink.php | 4 +- src/Link/LastLink.php | 4 +- src/Link/NextLink.php | 4 +- src/Link/PrevLink.php | 4 +- src/PaginatedResourceCollection.php | 24 +++++++++ src/PaginatedResourceIdentifierCollection.php | 24 +++++++++ src/Pagination.php | 27 ++++++++++ src/ResourceCollection.php | 2 +- src/ResourceIdentifier.php | 2 +- ...n.php => ResourceIdentifierCollection.php} | 2 +- test/CompoundDocumentTest.php | 20 ++++--- .../ManyResourceIdentifiersTest.php | 6 +-- test/MetaTest.php | 4 +- test/PaginationLinksTest.php | 53 ++++++++++++++++--- test/ResourceObjectTest.php | 4 +- test/benchmarks/compound10k.php | 17 +++--- 21 files changed, 183 insertions(+), 52 deletions(-) create mode 100644 src/Internal/PaginationLink.php create mode 100644 src/PaginatedResourceCollection.php create mode 100644 src/PaginatedResourceIdentifierCollection.php create mode 100644 src/Pagination.php rename src/{IdentifierCollection.php => ResourceIdentifierCollection.php} (91%) diff --git a/examples/compound_doc.php b/examples/compound_doc.php index d93e8b3..61842ef 100644 --- a/examples/compound_doc.php +++ b/examples/compound_doc.php @@ -2,14 +2,15 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\CompoundDocument; -use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Included; use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\ResourceCollection; +use JsonApiPhp\JsonApi\PaginatedResourceCollection; +use JsonApiPhp\JsonApi\Pagination; use JsonApiPhp\JsonApi\ResourceIdentifier; +use JsonApiPhp\JsonApi\ResourceIdentifierCollection; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ToMany; use JsonApiPhp\JsonApi\ToOne; @@ -42,7 +43,11 @@ ); $document = new CompoundDocument( - new ResourceCollection( + new PaginatedResourceCollection( + new Pagination( + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') + ), new ResourceObject( 'articles', '1', @@ -56,7 +61,7 @@ ), new ToMany( 'comments', - new IdentifierCollection( + new ResourceIdentifierCollection( $comment05->toIdentifier(), $comment12->toIdentifier() ), @@ -66,9 +71,7 @@ ) ), new Included($dan, $comment05, $comment12), - new SelfLink('http://example.com/articles'), - new NextLink('http://example.com/articles?page[offset]=2'), - new LastLink('http://example.com/articles?page[offset]=10') + new SelfLink('http://example.com/articles') ); echo json_encode($document, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); diff --git a/src/Included.php b/src/Included.php index f4f4800..30da0c0 100644 --- a/src/Included.php +++ b/src/Included.php @@ -19,7 +19,7 @@ public function __construct(ResourceObject ...$resources) { $this->ids = new IdentifierRegistry(); foreach ($resources as $resource) { - $string_id = $resource->identity(); + $string_id = $resource->key(); if (isset($this->resources[$string_id])) { throw new \LogicException("Resource $string_id is already included"); } @@ -33,10 +33,10 @@ public function validateLinkage(PrimaryData $data): void $dataRegistry = new IdentifierRegistry(); $data->registerIn($dataRegistry); foreach ($this->resources as $resource) { - if ($dataRegistry->has($resource->identity()) || $this->ids->has($resource->identity())) { + if ($dataRegistry->has($resource->key()) || $this->ids->has($resource->key())) { continue; } - throw new \LogicException('Full linkage required for '.$resource->identity()); + throw new \LogicException('Full linkage required for '.$resource->key()); } } diff --git a/src/Internal/IdentifierRegistry.php b/src/Internal/IdentifierRegistry.php index a7646d6..e79e474 100644 --- a/src/Internal/IdentifierRegistry.php +++ b/src/Internal/IdentifierRegistry.php @@ -19,6 +19,7 @@ public function has(string $id): bool { return isset($this->ids[$id]); } + public function merge(IdentifierRegistry $registry) { $this->ids = array_merge($this->ids, $registry->ids); diff --git a/src/Internal/IdentityTrait.php b/src/Internal/IdentityTrait.php index ec5f120..b46ecd4 100644 --- a/src/Internal/IdentityTrait.php +++ b/src/Internal/IdentityTrait.php @@ -22,7 +22,7 @@ trait IdentityTrait * @internal * @return string */ - public function identity(): string + public function key(): string { return "{$this->type}:{$this->id}"; } diff --git a/src/Internal/PaginationLink.php b/src/Internal/PaginationLink.php new file mode 100644 index 0000000..00727d5 --- /dev/null +++ b/src/Internal/PaginationLink.php @@ -0,0 +1,8 @@ +pagination = $pagination; + } + + public function attachTo(object $o): void + { + parent::attachTo($o); + $this->pagination->attachTo($o); + } +} diff --git a/src/PaginatedResourceIdentifierCollection.php b/src/PaginatedResourceIdentifierCollection.php new file mode 100644 index 0000000..ea4e432 --- /dev/null +++ b/src/PaginatedResourceIdentifierCollection.php @@ -0,0 +1,24 @@ +pagination = $pagination; + } + + public function attachTo(object $o) + { + parent::attachTo($o); + $this->pagination->attachTo($o); + } +} diff --git a/src/Pagination.php b/src/Pagination.php new file mode 100644 index 0000000..ba8ab41 --- /dev/null +++ b/src/Pagination.php @@ -0,0 +1,27 @@ +links = $links; + } + + public function attachTo(object $o) + { + foreach ($this->links as $link) { + $link->attachTo($o); + } + } +} diff --git a/src/ResourceCollection.php b/src/ResourceCollection.php index 0db4d64..e29ee55 100644 --- a/src/ResourceCollection.php +++ b/src/ResourceCollection.php @@ -5,7 +5,7 @@ use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\PrimaryData; -final class ResourceCollection implements PrimaryData +class ResourceCollection implements PrimaryData { /** * @var ResourceObject[] diff --git a/src/ResourceIdentifier.php b/src/ResourceIdentifier.php index 6135e16..7d170b0 100644 --- a/src/ResourceIdentifier.php +++ b/src/ResourceIdentifier.php @@ -40,6 +40,6 @@ public function attachToCollection(object $o): void public function registerIn(IdentifierRegistry $registry) { - $registry->add($this->identity()); + $registry->add($this->key()); } } diff --git a/src/IdentifierCollection.php b/src/ResourceIdentifierCollection.php similarity index 91% rename from src/IdentifierCollection.php rename to src/ResourceIdentifierCollection.php index 0d6fc0e..4e08ae7 100644 --- a/src/IdentifierCollection.php +++ b/src/ResourceIdentifierCollection.php @@ -6,7 +6,7 @@ use JsonApiPhp\JsonApi\Internal\PrimaryData; use JsonApiPhp\JsonApi\Internal\ToManyMember; -final class IdentifierCollection implements PrimaryData, ToManyMember +class ResourceIdentifierCollection implements PrimaryData, ToManyMember { /** * @var ResourceIdentifier[] diff --git a/test/CompoundDocumentTest.php b/test/CompoundDocumentTest.php index c50b25f..01ede9c 100644 --- a/test/CompoundDocumentTest.php +++ b/test/CompoundDocumentTest.php @@ -4,15 +4,17 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\CompoundDocument; -use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Included; use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\NullData; +use JsonApiPhp\JsonApi\PaginatedResourceCollection; +use JsonApiPhp\JsonApi\Pagination; use JsonApiPhp\JsonApi\ResourceCollection; use JsonApiPhp\JsonApi\ResourceIdentifier; +use JsonApiPhp\JsonApi\ResourceIdentifierCollection; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ToMany; use JsonApiPhp\JsonApi\ToOne; @@ -47,7 +49,11 @@ public function testOfficialDocsExample() ); $document = new CompoundDocument( - new ResourceCollection( + new PaginatedResourceCollection( + new Pagination( + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') + ), new ResourceObject( 'articles', '1', @@ -61,7 +67,7 @@ public function testOfficialDocsExample() ), new ToMany( 'comments', - new IdentifierCollection( + new ResourceIdentifierCollection( $comment05->toIdentifier(), $comment12->toIdentifier() ), @@ -71,9 +77,7 @@ public function testOfficialDocsExample() ) ), new Included($dan, $comment05, $comment12), - new SelfLink('http://example.com/articles'), - new NextLink('http://example.com/articles?page[offset]=2'), - new LastLink('http://example.com/articles?page[offset]=10') + new SelfLink('http://example.com/articles') ); $this->assertEncodesTo( ' @@ -196,7 +200,7 @@ function () use ($included) { [ function () use ($included) { return new CompoundDocument( - new IdentifierCollection( + new ResourceIdentifierCollection( new ResourceIdentifier('oranges', '1'), new ResourceIdentifier('oranges', '1') ), @@ -239,7 +243,7 @@ public function testIncludedResourceMayBeIdentifiedByAnotherLinkedResource() $cart = new ResourceObject( 'shopping-carts', '1', - new ToMany('contents', new IdentifierCollection($book->toIdentifier())) + new ToMany('contents', new ResourceIdentifierCollection($book->toIdentifier())) ); $doc = new CompoundDocument($cart, new Included($book, $writer)); $this->assertNotEmpty($doc); diff --git a/test/DataDocument/ManyResourceIdentifiersTest.php b/test/DataDocument/ManyResourceIdentifiersTest.php index 713fb65..eb12973 100644 --- a/test/DataDocument/ManyResourceIdentifiersTest.php +++ b/test/DataDocument/ManyResourceIdentifiersTest.php @@ -3,11 +3,11 @@ namespace JsonApiPhp\JsonApi\Test\DataDocument; use JsonApiPhp\JsonApi\DataDocument; -use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; +use JsonApiPhp\JsonApi\ResourceIdentifierCollection; use JsonApiPhp\JsonApi\Test\BaseTestCase; class ManyResourceIdentifiersTest extends BaseTestCase @@ -21,7 +21,7 @@ public function testMinimalDocument() } ', new DataDocument( - new IdentifierCollection() + new ResourceIdentifierCollection() ) ); } @@ -50,7 +50,7 @@ public function testExtendedDocument() } ', new DataDocument( - new IdentifierCollection( + new ResourceIdentifierCollection( new ResourceIdentifier( 'apples', '1', diff --git a/test/MetaTest.php b/test/MetaTest.php index 8ea6b1b..67d3097 100644 --- a/test/MetaTest.php +++ b/test/MetaTest.php @@ -10,7 +10,7 @@ class MetaTest extends TestCase public function testKeyMustBeValid() { $this->expectException(\DomainException::class); - $this->expectExceptionMessage("Invalid character in a member name 'this+name&is'"); - new Meta('this+name&is', '1'); + $this->expectExceptionMessage("Invalid character in a member name 'invalid:name'"); + new Meta('invalid:name', '1'); } } diff --git a/test/PaginationLinksTest.php b/test/PaginationLinksTest.php index 3ba40bd..681675e 100644 --- a/test/PaginationLinksTest.php +++ b/test/PaginationLinksTest.php @@ -7,12 +7,15 @@ use JsonApiPhp\JsonApi\Link\LastLink; use JsonApiPhp\JsonApi\Link\NextLink; use JsonApiPhp\JsonApi\Link\PrevLink; -use JsonApiPhp\JsonApi\ResourceCollection; +use JsonApiPhp\JsonApi\PaginatedResourceCollection; +use JsonApiPhp\JsonApi\PaginatedResourceIdentifierCollection; +use JsonApiPhp\JsonApi\Pagination; +use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; class PaginationLinksTest extends BaseTestCase { - public function testPagination() + public function testPaginatedResourceCollection() { $this->assertEncodesTo( ' @@ -30,14 +33,48 @@ public function testPagination() } ', new DataDocument( - new ResourceCollection( + new PaginatedResourceCollection( + new Pagination( + new FirstLink('http://example.com/fruits?page=first'), + new PrevLink('http://example.com/fruits?page=3'), + new NextLink('http://example.com/fruits?page=5'), + new LastLink('http://example.com/fruits?page=last') + ), new ResourceObject('apples', '1'), new ResourceObject('apples', '2') - ), - new FirstLink('http://example.com/fruits?page=first'), - new PrevLink('http://example.com/fruits?page=3'), - new NextLink('http://example.com/fruits?page=5'), - new LastLink('http://example.com/fruits?page=last') + ) + ) + ); + } + + public function testPaginatedResourceIdentifierCollection() + { + $this->assertEncodesTo( + ' + { + "data": [ + {"type": "apples", "id": "1"}, + {"type": "apples", "id": "2"} + ], + "links": { + "first": "http://example.com/fruits?page=first", + "last": "http://example.com/fruits?page=last", + "prev": "http://example.com/fruits?page=3", + "next": "http://example.com/fruits?page=5" + } + } + ', + new DataDocument( + new PaginatedResourceIdentifierCollection( + new Pagination( + new FirstLink('http://example.com/fruits?page=first'), + new PrevLink('http://example.com/fruits?page=3'), + new NextLink('http://example.com/fruits?page=5'), + new LastLink('http://example.com/fruits?page=last') + ), + new ResourceIdentifier('apples', '1'), + new ResourceIdentifier('apples', '2') + ) ) ); } diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index 9bb6355..68af554 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -4,11 +4,11 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\DataDocument; -use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; use JsonApiPhp\JsonApi\ResourceIdentifier; +use JsonApiPhp\JsonApi\ResourceIdentifierCollection; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ToMany; use JsonApiPhp\JsonApi\ToNull; @@ -116,7 +116,7 @@ public function testRelationshipWithMultiIdLinkage() '1', new ToMany( 'content', - new IdentifierCollection( + new ResourceIdentifierCollection( new ResourceIdentifier('apples', '1'), new ResourceIdentifier('pears', '2') ) diff --git a/test/benchmarks/compound10k.php b/test/benchmarks/compound10k.php index 270f112..8f2fad4 100644 --- a/test/benchmarks/compound10k.php +++ b/test/benchmarks/compound10k.php @@ -11,7 +11,6 @@ use JsonApiPhp\JsonApi\Error\Status; use JsonApiPhp\JsonApi\Error\Title; use JsonApiPhp\JsonApi\ErrorDocument; -use JsonApiPhp\JsonApi\IdentifierCollection; use JsonApiPhp\JsonApi\Included; use JsonApiPhp\JsonApi\JsonApi; use JsonApiPhp\JsonApi\Link\AboutLink; @@ -20,8 +19,10 @@ use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; use JsonApiPhp\JsonApi\Meta; -use JsonApiPhp\JsonApi\ResourceCollection; +use JsonApiPhp\JsonApi\PaginatedResourceCollection; +use JsonApiPhp\JsonApi\Pagination; use JsonApiPhp\JsonApi\ResourceIdentifier; +use JsonApiPhp\JsonApi\ResourceIdentifierCollection; use JsonApiPhp\JsonApi\ResourceObject; use JsonApiPhp\JsonApi\ToMany; use JsonApiPhp\JsonApi\ToOne; @@ -57,7 +58,11 @@ ); $data_document = new CompoundDocument( - new ResourceCollection( + new PaginatedResourceCollection( + new Pagination( + new NextLink('http://example.com/articles?page[offset]=2'), + new LastLink('http://example.com/articles?page[offset]=10') + ), new ResourceObject( 'articles', '1', @@ -71,7 +76,7 @@ ), new ToMany( 'comments', - new IdentifierCollection( + new ResourceIdentifierCollection( $comment05->toIdentifier(), $comment12->toIdentifier() ), @@ -81,9 +86,7 @@ ) ), new Included($dan, $comment05, $comment12), - new SelfLink('http://example.com/articles'), - new NextLink('http://example.com/articles?page[offset]=2'), - new LastLink('http://example.com/articles?page[offset]=10') + new SelfLink('http://example.com/articles') ); $data_doc_json = json_encode($data_document); From 09d37df9c5e34747003a4024c5c712d70e10a451 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Wed, 28 Feb 2018 23:53:50 -0800 Subject: [PATCH 18/26] Performance improvements --- src/Link/SelfLink.php | 5 ----- src/ToMany.php | 6 +----- src/functions.php | 2 +- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 55ef1bb..4cecb1f 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -27,9 +27,4 @@ public function registerField(FieldRegistry $registry) public function registerIdentifier(IdentifierRegistry $registry) { } - - public function attachToCollection(object $o) - { - // TODO: Implement attachToCollection() method. - } } diff --git a/src/ToMany.php b/src/ToMany.php index d7ced47..926f285 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -29,11 +29,7 @@ public function attachTo(object $o) $rel = child(child($o, 'relationships'), $this->name); $rel->data = []; foreach ($this->members as $member) { - if ($member instanceof ResourceIdentifier) { - $member->attachToCollection($rel); - } else { - $member->attachTo($rel); - } + $member->attachTo($rel); } } diff --git a/src/functions.php b/src/functions.php index 907fab1..458cb53 100644 --- a/src/functions.php +++ b/src/functions.php @@ -15,7 +15,7 @@ function combine(Attachable ...$members): object function child(object $o, string $name): object { - if (empty($o->{$name})) { + if (!isset($o->{$name})) { $o->{$name} = (object) []; } return $o->{$name}; From 07c4aebadd8322523ab915c3d4721ae123a97f12 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 00:11:45 -0800 Subject: [PATCH 19/26] Performance improvements --- src/Attribute.php | 2 +- src/Internal/ResourceMember.php | 4 +--- src/Internal/ToManyMember.php | 2 +- src/Link/RelatedLink.php | 5 +++++ src/Link/SelfLink.php | 2 +- src/Meta.php | 2 +- src/ResourceObject.php | 2 +- src/ToMany.php | 7 ++----- src/ToNull.php | 2 +- src/ToOne.php | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Attribute.php b/src/Attribute.php index bbefe72..1175c14 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -23,7 +23,7 @@ public function attachTo(object $o) child($o, 'attributes')->{$this->name} = $this->val; } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { } } diff --git a/src/Internal/ResourceMember.php b/src/Internal/ResourceMember.php index 009c0fb..0e519d1 100644 --- a/src/Internal/ResourceMember.php +++ b/src/Internal/ResourceMember.php @@ -5,9 +5,7 @@ /** * @internal */ -interface ResourceMember extends Attachable +interface ResourceMember extends Attachable, Identifier { public function registerField(FieldRegistry $registry); - - public function registerIdentifier(IdentifierRegistry $registry); } diff --git a/src/Internal/ToManyMember.php b/src/Internal/ToManyMember.php index d812f11..98639d4 100644 --- a/src/Internal/ToManyMember.php +++ b/src/Internal/ToManyMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface ToManyMember extends Attachable +interface ToManyMember extends Attachable, Identifier { } diff --git a/src/Link/RelatedLink.php b/src/Link/RelatedLink.php index 17999ab..4e4c473 100644 --- a/src/Link/RelatedLink.php +++ b/src/Link/RelatedLink.php @@ -2,6 +2,7 @@ namespace JsonApiPhp\JsonApi\Link; +use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\LinkTrait; use JsonApiPhp\JsonApi\Internal\ToManyMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; @@ -15,4 +16,8 @@ public function attachTo(object $o) { child($o, 'links')->related = $this->link; } + + public function registerIn(IdentifierRegistry $registry) + { + } } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 4cecb1f..f543c6f 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -24,7 +24,7 @@ public function registerField(FieldRegistry $registry) { } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { } } diff --git a/src/Meta.php b/src/Meta.php index 632babf..12c9121 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -37,7 +37,7 @@ public function registerField(FieldRegistry $registry) { } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index c5e132d..29d8f40 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -26,7 +26,7 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ $fields = new FieldRegistry(); foreach ($members as $member) { $member->registerField($fields); - $member->registerIdentifier($this->registry); + $member->registerIn($this->registry); $member->attachTo($this->obj); } } diff --git a/src/ToMany.php b/src/ToMany.php index 926f285..abc3057 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -2,7 +2,6 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; use JsonApiPhp\JsonApi\Internal\ResourceMember; @@ -33,12 +32,10 @@ public function attachTo(object $o) } } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { foreach ($this->members as $member) { - if ($member instanceof Identifier) { - $member->registerIn($registry); - } + $member->registerIn($registry); } } } diff --git a/src/ToNull.php b/src/ToNull.php index 28c1993..0cb2fb0 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -29,7 +29,7 @@ public function attachTo(object $o) child($o, 'relationships')->{$this->name} = $obj; } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { } } diff --git a/src/ToOne.php b/src/ToOne.php index 80a5113..b86a565 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -31,7 +31,7 @@ public function attachTo(object $o) child($o, 'relationships')->{$this->name} = $this->obj; } - public function registerIdentifier(IdentifierRegistry $registry) + public function registerIn(IdentifierRegistry $registry) { $this->identifier->registerIn($registry); } From 3c4cb79061311ea19a053475ec1e71da85a2704b Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 00:41:20 -0800 Subject: [PATCH 20/26] Performance improvements --- src/Attribute.php | 9 ++------- src/Internal/FieldRegistry.php | 20 -------------------- src/Internal/ResourceField.php | 9 +++++++++ src/Internal/ResourceFieldTrait.php | 4 ++-- src/Internal/ResourceMember.php | 3 +-- src/Internal/ToManyMember.php | 2 +- src/Link/SelfLink.php | 5 ----- src/Meta.php | 7 ++----- src/ResourceObject.php | 16 +++++++++++++--- src/ToMany.php | 17 +++++++++++------ src/ToNull.php | 7 ++----- src/ToOne.php | 4 +++- test/ResourceObjectTest.php | 2 +- 13 files changed, 47 insertions(+), 58 deletions(-) delete mode 100644 src/Internal/FieldRegistry.php create mode 100644 src/Internal/ResourceField.php diff --git a/src/Attribute.php b/src/Attribute.php index 1175c14..fb2984f 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -2,11 +2,10 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ResourceMember; -final class Attribute implements ResourceMember +final class Attribute implements ResourceField { use ResourceFieldTrait; private $val; @@ -22,8 +21,4 @@ public function attachTo(object $o) { child($o, 'attributes')->{$this->name} = $this->val; } - - public function registerIn(IdentifierRegistry $registry) - { - } } diff --git a/src/Internal/FieldRegistry.php b/src/Internal/FieldRegistry.php deleted file mode 100644 index 592a57a..0000000 --- a/src/Internal/FieldRegistry.php +++ /dev/null @@ -1,20 +0,0 @@ -keys[$key])) { - throw new \LogicException("Field '$key' already exists'"); - } - $this->keys[$key] = true; - } -} diff --git a/src/Internal/ResourceField.php b/src/Internal/ResourceField.php new file mode 100644 index 0000000..c6fefab --- /dev/null +++ b/src/Internal/ResourceField.php @@ -0,0 +1,9 @@ +register($this->name); + return $this->name; } } diff --git a/src/Internal/ResourceMember.php b/src/Internal/ResourceMember.php index 0e519d1..b20e3b0 100644 --- a/src/Internal/ResourceMember.php +++ b/src/Internal/ResourceMember.php @@ -5,7 +5,6 @@ /** * @internal */ -interface ResourceMember extends Attachable, Identifier +interface ResourceMember extends Attachable { - public function registerField(FieldRegistry $registry); } diff --git a/src/Internal/ToManyMember.php b/src/Internal/ToManyMember.php index 98639d4..d812f11 100644 --- a/src/Internal/ToManyMember.php +++ b/src/Internal/ToManyMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface ToManyMember extends Attachable, Identifier +interface ToManyMember extends Attachable { } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index f543c6f..0319991 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -4,7 +4,6 @@ use JsonApiPhp\JsonApi\Internal\DataDocumentMember; use JsonApiPhp\JsonApi\Internal\FieldRegistry; -use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\LinkTrait; use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToManyMember; @@ -23,8 +22,4 @@ public function attachTo(object $o): void public function registerField(FieldRegistry $registry) { } - - public function registerIn(IdentifierRegistry $registry) - { - } } diff --git a/src/Meta.php b/src/Meta.php index 12c9121..9efe3fb 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -9,9 +9,10 @@ use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\MetaDocumentMember; use JsonApiPhp\JsonApi\Internal\ResourceMember; +use JsonApiPhp\JsonApi\Internal\ToManyMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class Meta implements ErrorMember, ErrorDocumentMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember +final class Meta implements ErrorMember, ErrorDocumentMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember, ToManyMember { /** * @var string @@ -36,8 +37,4 @@ public function attachTo(object $o) public function registerField(FieldRegistry $registry) { } - - public function registerIn(IdentifierRegistry $registry) - { - } } diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 29d8f40..9092f6e 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -3,9 +3,11 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\Internal\FieldRegistry; +use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\IdentityTrait; use JsonApiPhp\JsonApi\Internal\PrimaryData; +use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceMember; final class ResourceObject implements PrimaryData @@ -23,10 +25,18 @@ public function __construct(string $type, string $id = null, ResourceMember ...$ $this->id = $id; $this->registry = new IdentifierRegistry(); $this->obj = (object) ['type' => $type, 'id' => $id]; - $fields = new FieldRegistry(); + $fields = []; foreach ($members as $member) { - $member->registerField($fields); - $member->registerIn($this->registry); + 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); } } diff --git a/src/ToMany.php b/src/ToMany.php index abc3057..4538353 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -2,31 +2,38 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToManyMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class ToMany implements ResourceMember +final class ToMany implements Identifier, ResourceField { use ResourceFieldTrait; /** * @var ToOneMember[] */ private $members; + /** + * @var ResourceIdentifierCollection + */ + private $collection; - public function __construct(string $name, ToManyMember ...$members) + public function __construct(string $name, ResourceIdentifierCollection $collection, ToManyMember ...$members) { $this->validateFieldName($name); $this->name = $name; $this->members = $members; + $this->collection = $collection; } public function attachTo(object $o) { $rel = child(child($o, 'relationships'), $this->name); $rel->data = []; + $this->collection->attachTo($rel); foreach ($this->members as $member) { $member->attachTo($rel); } @@ -34,8 +41,6 @@ public function attachTo(object $o) public function registerIn(IdentifierRegistry $registry) { - foreach ($this->members as $member) { - $member->registerIn($registry); - } + $this->collection->registerIn($registry); } } diff --git a/src/ToNull.php b/src/ToNull.php index 0cb2fb0..4b70c83 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -3,11 +3,12 @@ namespace JsonApiPhp\JsonApi; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class ToNull implements ResourceMember +final class ToNull implements ResourceField { use ResourceFieldTrait; /** @@ -28,8 +29,4 @@ public function attachTo(object $o) $obj->data = null; child($o, 'relationships')->{$this->name} = $obj; } - - public function registerIn(IdentifierRegistry $registry) - { - } } diff --git a/src/ToOne.php b/src/ToOne.php index b86a565..8fbe0e0 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -2,12 +2,14 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class ToOne implements ResourceMember +final class ToOne implements Identifier, ResourceField { use ResourceFieldTrait; diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index 68af554..c52693d 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -146,7 +146,7 @@ public function testRelationshipWithEmptyMultiIdLinkage() new ResourceObject( 'basket', '1', - new ToMany('content') + new ToMany('content', new ResourceIdentifierCollection()) ) ) ); From a814d6a16ab33d5181e7c65141f8e34bf980066e Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 00:41:27 -0800 Subject: [PATCH 21/26] Performance improvements --- src/Internal/ResourceField.php | 2 +- src/Meta.php | 1 - src/ResourceObject.php | 1 - src/ToNull.php | 2 -- src/ToOne.php | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Internal/ResourceField.php b/src/Internal/ResourceField.php index c6fefab..2d68634 100644 --- a/src/Internal/ResourceField.php +++ b/src/Internal/ResourceField.php @@ -6,4 +6,4 @@ interface ResourceField extends ResourceMember { public function name(): string; -} \ No newline at end of file +} diff --git a/src/Meta.php b/src/Meta.php index 9efe3fb..71abe9f 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\Internal\ErrorDocumentMember; use JsonApiPhp\JsonApi\Internal\ErrorMember; use JsonApiPhp\JsonApi\Internal\FieldRegistry; -use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\MetaDocumentMember; use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToManyMember; diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 9092f6e..6074844 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -2,7 +2,6 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Internal\FieldRegistry; use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\IdentityTrait; diff --git a/src/ToNull.php b/src/ToNull.php index 4b70c83..417179c 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -2,10 +2,8 @@ namespace JsonApiPhp\JsonApi; -use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToNull implements ResourceField diff --git a/src/ToOne.php b/src/ToOne.php index 8fbe0e0..b51f9e9 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -6,7 +6,6 @@ use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ResourceMember; use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToOne implements Identifier, ResourceField From 4064e92d1aade383cb840cd5e546e248ad586fda Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 00:58:03 -0800 Subject: [PATCH 22/26] Performance improvements --- composer.json | 2 +- .../{ToManyMember.php => RelationshipMember.php} | 2 +- src/Internal/ToOneMember.php | 10 ---------- src/Link/RelatedLink.php | 10 ++-------- src/Link/SelfLink.php | 10 ++-------- src/Meta.php | 10 ++-------- src/ResourceIdentifierCollection.php | 3 +-- src/ToMany.php | 7 +++---- src/ToNull.php | 6 +++--- src/ToOne.php | 4 ++-- test/ResourceIdentifierTest.php | 15 +++++++++++++++ test/ResourceObjectTest.php | 6 ++++++ 12 files changed, 38 insertions(+), 47 deletions(-) rename src/Internal/{ToManyMember.php => RelationshipMember.php} (66%) delete mode 100644 src/Internal/ToOneMember.php create mode 100644 test/ResourceIdentifierTest.php diff --git a/composer.json b/composer.json index a83d94f..1cdeb90 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "php": ">=7.2" }, "require-dev": { - "phpunit/phpunit": "^6.0", + "phpunit/phpunit": "^7.0", "friendsofphp/php-cs-fixer": "^2.2" }, "autoload": { diff --git a/src/Internal/ToManyMember.php b/src/Internal/RelationshipMember.php similarity index 66% rename from src/Internal/ToManyMember.php rename to src/Internal/RelationshipMember.php index d812f11..092e78b 100644 --- a/src/Internal/ToManyMember.php +++ b/src/Internal/RelationshipMember.php @@ -5,6 +5,6 @@ /** * @internal */ -interface ToManyMember extends Attachable +interface RelationshipMember extends Attachable { } diff --git a/src/Internal/ToOneMember.php b/src/Internal/ToOneMember.php deleted file mode 100644 index f65acd4..0000000 --- a/src/Internal/ToOneMember.php +++ /dev/null @@ -1,10 +0,0 @@ -related = $this->link; } - - public function registerIn(IdentifierRegistry $registry) - { - } } diff --git a/src/Link/SelfLink.php b/src/Link/SelfLink.php index 0319991..3817dd3 100644 --- a/src/Link/SelfLink.php +++ b/src/Link/SelfLink.php @@ -3,14 +3,12 @@ namespace JsonApiPhp\JsonApi\Link; use JsonApiPhp\JsonApi\Internal\DataDocumentMember; -use JsonApiPhp\JsonApi\Internal\FieldRegistry; use JsonApiPhp\JsonApi\Internal\LinkTrait; +use JsonApiPhp\JsonApi\Internal\RelationshipMember; use JsonApiPhp\JsonApi\Internal\ResourceMember; -use JsonApiPhp\JsonApi\Internal\ToManyMember; -use JsonApiPhp\JsonApi\Internal\ToOneMember; use function JsonApiPhp\JsonApi\child; -final class SelfLink implements DataDocumentMember, ResourceMember, ToOneMember, ToManyMember +final class SelfLink implements DataDocumentMember, ResourceMember, RelationshipMember { use LinkTrait; @@ -18,8 +16,4 @@ public function attachTo(object $o): void { child($o, 'links')->self = $this->link; } - - public function registerField(FieldRegistry $registry) - { - } } diff --git a/src/Meta.php b/src/Meta.php index 71abe9f..b8252cb 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -5,13 +5,11 @@ use JsonApiPhp\JsonApi\Internal\DataDocumentMember; use JsonApiPhp\JsonApi\Internal\ErrorDocumentMember; use JsonApiPhp\JsonApi\Internal\ErrorMember; -use JsonApiPhp\JsonApi\Internal\FieldRegistry; use JsonApiPhp\JsonApi\Internal\MetaDocumentMember; +use JsonApiPhp\JsonApi\Internal\RelationshipMember; use JsonApiPhp\JsonApi\Internal\ResourceMember; -use JsonApiPhp\JsonApi\Internal\ToManyMember; -use JsonApiPhp\JsonApi\Internal\ToOneMember; -final class Meta implements ErrorMember, ErrorDocumentMember, MetaDocumentMember, DataDocumentMember, ResourceMember, ToOneMember, ToManyMember +final class Meta implements ErrorMember, ErrorDocumentMember, MetaDocumentMember, DataDocumentMember, ResourceMember, RelationshipMember { /** * @var string @@ -32,8 +30,4 @@ public function attachTo(object $o) { child($o, 'meta')->{$this->key} = $this->value; } - - public function registerField(FieldRegistry $registry) - { - } } diff --git a/src/ResourceIdentifierCollection.php b/src/ResourceIdentifierCollection.php index 4e08ae7..1786c1d 100644 --- a/src/ResourceIdentifierCollection.php +++ b/src/ResourceIdentifierCollection.php @@ -4,9 +4,8 @@ use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; use JsonApiPhp\JsonApi\Internal\PrimaryData; -use JsonApiPhp\JsonApi\Internal\ToManyMember; -class ResourceIdentifierCollection implements PrimaryData, ToManyMember +class ResourceIdentifierCollection implements PrimaryData { /** * @var ResourceIdentifier[] diff --git a/src/ToMany.php b/src/ToMany.php index 4538353..d8b2ba3 100644 --- a/src/ToMany.php +++ b/src/ToMany.php @@ -4,16 +4,15 @@ use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\RelationshipMember; use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ToManyMember; -use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToMany implements Identifier, ResourceField { use ResourceFieldTrait; /** - * @var ToOneMember[] + * @var RelationshipMember[] */ private $members; /** @@ -21,7 +20,7 @@ final class ToMany implements Identifier, ResourceField */ private $collection; - public function __construct(string $name, ResourceIdentifierCollection $collection, ToManyMember ...$members) + public function __construct(string $name, ResourceIdentifierCollection $collection, RelationshipMember ...$members) { $this->validateFieldName($name); $this->name = $name; diff --git a/src/ToNull.php b/src/ToNull.php index 417179c..c163d67 100644 --- a/src/ToNull.php +++ b/src/ToNull.php @@ -2,19 +2,19 @@ namespace JsonApiPhp\JsonApi; +use JsonApiPhp\JsonApi\Internal\RelationshipMember; use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToNull implements ResourceField { use ResourceFieldTrait; /** - * @var ToOneMember[] + * @var RelationshipMember[] */ private $members; - public function __construct(string $name, ToOneMember ...$members) + public function __construct(string $name, RelationshipMember ...$members) { $this->validateFieldName($name); $this->name = $name; diff --git a/src/ToOne.php b/src/ToOne.php index b51f9e9..b696710 100644 --- a/src/ToOne.php +++ b/src/ToOne.php @@ -4,9 +4,9 @@ use JsonApiPhp\JsonApi\Internal\Identifier; use JsonApiPhp\JsonApi\Internal\IdentifierRegistry; +use JsonApiPhp\JsonApi\Internal\RelationshipMember; use JsonApiPhp\JsonApi\Internal\ResourceField; use JsonApiPhp\JsonApi\Internal\ResourceFieldTrait; -use JsonApiPhp\JsonApi\Internal\ToOneMember; final class ToOne implements Identifier, ResourceField { @@ -19,7 +19,7 @@ final class ToOne implements Identifier, ResourceField private $obj; - public function __construct(string $name, ResourceIdentifier $identifier, ToOneMember ...$members) + public function __construct(string $name, ResourceIdentifier $identifier, RelationshipMember ...$members) { $this->validateFieldName($name); $this->name = $name; diff --git a/test/ResourceIdentifierTest.php b/test/ResourceIdentifierTest.php new file mode 100644 index 0000000..5dcd959 --- /dev/null +++ b/test/ResourceIdentifierTest.php @@ -0,0 +1,15 @@ +expectException(\DomainException::class); + new ResourceIdentifier('invalid:id', 'foo'); + } +} diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index c52693d..fcf5e00 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -246,4 +246,10 @@ public function testResourceIdCanBeOmitted() new DataDocument(new ResourceObject('apples', null, new Attribute('color', 'red'))) ); } + + public function testNameValidation() + { + $this->expectException(\DomainException::class); + new ResourceObject('invalid:id', 'foo'); + } } From 7aef1d69a3997c9aa28e3d7c19a849a686b93fff Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 01:33:06 -0800 Subject: [PATCH 23/26] Performance improvements --- src/ResourceObject.php | 2 +- test/ResourceObjectTest.php | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/ResourceObject.php b/src/ResourceObject.php index 6074844..02701d2 100644 --- a/src/ResourceObject.php +++ b/src/ResourceObject.php @@ -15,7 +15,7 @@ final class ResourceObject implements PrimaryData private $obj; private $registry; - public function __construct(string $type, string $id = null, ResourceMember ...$members) + public function __construct(string $type, string $id, ResourceMember ...$members) { if (isValidName($type) === false) { throw new \DomainException("Invalid type value: $type"); diff --git a/test/ResourceObjectTest.php b/test/ResourceObjectTest.php index fcf5e00..37e845f 100644 --- a/test/ResourceObjectTest.php +++ b/test/ResourceObjectTest.php @@ -225,28 +225,6 @@ public function testResourceFieldsMustBeUnique() ); } - /** - * The id member is not required when the resource object originates at the client and represents - * a new resource to be created on the server. - */ - public function testResourceIdCanBeOmitted() - { - $this->assertEncodesTo( - ' - { - "data": { - "type": "apples", - "id": null, - "attributes": { - "color": "red" - } - } - } - ', - new DataDocument(new ResourceObject('apples', null, new Attribute('color', 'red'))) - ); - } - public function testNameValidation() { $this->expectException(\DomainException::class); From 34bcb6954e9d1f79a15cad7d58e4d9a2becbaaf9 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 01:36:36 -0800 Subject: [PATCH 24/26] Performance improvements --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9dc0e30..2f1a878 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,9 @@ use JsonApiPhp\JsonApi\Attribute; use JsonApiPhp\JsonApi\DataDocument; use JsonApiPhp\JsonApi\Link\RelatedLink; use JsonApiPhp\JsonApi\Link\SelfLink; -use JsonApiPhp\JsonApi\Relationship; use JsonApiPhp\JsonApi\ResourceIdentifier; use JsonApiPhp\JsonApi\ResourceObject; -use JsonApiPhp\JsonApi\SingleLinkage; +use JsonApiPhp\JsonApi\ToOne; echo json_encode( new DataDocument( @@ -46,9 +45,9 @@ echo json_encode( 'articles', '1', new Attribute('title', 'Rails is Omakase'), - new Relationship( + new ToOne( 'author', - new SingleLinkage(new ResourceIdentifier('author', '9')), + new ResourceIdentifier('author', '9'), new SelfLink('/articles/1/relationships/author'), new RelatedLink('/articles/1/author') ) From 05f57bd54b47ed5123644c48089990667bfc7391 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 01:49:19 -0800 Subject: [PATCH 25/26] Performance improvements --- README.md | 2 +- test/PaginationLinksTest.php | 81 -------------------------- test/PaginationTest.php | 108 +++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 82 deletions(-) delete mode 100644 test/PaginationLinksTest.php create mode 100644 test/PaginationTest.php diff --git a/README.md b/README.md index 2f1a878..4fe41d4 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ The library API and use-cases are expressed in comprehensive suite of tests. - [Compound Documents](./test/CompoundDocumentTest.php) - [Error Documents](./test/ErrorDocumentTest.php) - [Meta Documents (containing neither data nor errors)](./test/MetaDocumentTest.php) -- [Pagination links](./test/PaginationLinksTest.php) +- [Pagination](./test/PaginationTest.php) - [Link Objects](./test/LinkObjectTest.php) - [JSON API Object](./test/JsonApiTest.php) - [Meta Objects](./test/MetaTest.php) diff --git a/test/PaginationLinksTest.php b/test/PaginationLinksTest.php deleted file mode 100644 index 681675e..0000000 --- a/test/PaginationLinksTest.php +++ /dev/null @@ -1,81 +0,0 @@ -assertEncodesTo( - ' - { - "data": [ - {"type": "apples", "id": "1"}, - {"type": "apples", "id": "2"} - ], - "links": { - "first": "http://example.com/fruits?page=first", - "last": "http://example.com/fruits?page=last", - "prev": "http://example.com/fruits?page=3", - "next": "http://example.com/fruits?page=5" - } - } - ', - new DataDocument( - new PaginatedResourceCollection( - new Pagination( - new FirstLink('http://example.com/fruits?page=first'), - new PrevLink('http://example.com/fruits?page=3'), - new NextLink('http://example.com/fruits?page=5'), - new LastLink('http://example.com/fruits?page=last') - ), - new ResourceObject('apples', '1'), - new ResourceObject('apples', '2') - ) - ) - ); - } - - public function testPaginatedResourceIdentifierCollection() - { - $this->assertEncodesTo( - ' - { - "data": [ - {"type": "apples", "id": "1"}, - {"type": "apples", "id": "2"} - ], - "links": { - "first": "http://example.com/fruits?page=first", - "last": "http://example.com/fruits?page=last", - "prev": "http://example.com/fruits?page=3", - "next": "http://example.com/fruits?page=5" - } - } - ', - new DataDocument( - new PaginatedResourceIdentifierCollection( - new Pagination( - new FirstLink('http://example.com/fruits?page=first'), - new PrevLink('http://example.com/fruits?page=3'), - new NextLink('http://example.com/fruits?page=5'), - new LastLink('http://example.com/fruits?page=last') - ), - new ResourceIdentifier('apples', '1'), - new ResourceIdentifier('apples', '2') - ) - ) - ); - } -} diff --git a/test/PaginationTest.php b/test/PaginationTest.php new file mode 100644 index 0000000..e00ab53 --- /dev/null +++ b/test/PaginationTest.php @@ -0,0 +1,108 @@ +assertEncodesTo( + ' + { + "data": [ + {"type": "apples", "id": "1"}, + {"type": "apples", "id": "2"} + ], + "links": { + "first": "http://example.com/fruits?page=first", + "last": "http://example.com/fruits?page=last", + "prev": "http://example.com/fruits?page=3", + "next": "http://example.com/fruits?page=5" + } + } + ', + new DataDocument( + new PaginatedResourceCollection( + new Pagination( + new FirstLink('http://example.com/fruits?page=first'), + new PrevLink('http://example.com/fruits?page=3'), + new NextLink('http://example.com/fruits?page=5'), + new LastLink('http://example.com/fruits?page=last') + ), + new ResourceObject('apples', '1'), + new ResourceObject('apples', '2') + ) + ) + ); + } + + public function testPaginatedResourceIdentifierCollection() + { + $this->assertEncodesTo( + ' + { + "data": { + "type": "baskets", + "id": "1", + "relationships": { + "fruits": { + "data": [ + {"type": "apples", "id": "1"}, + {"type": "apples", "id": "2"} + ], + "links": { + "first": "http://example.com/basket/1/fruits?page=first", + "last": "http://example.com/basket/1/fruits?page=last", + "prev": "http://example.com/basket/1/fruits?page=3", + "next": "http://example.com/basket/1/fruits?page=5" + } + } + } + }, + "included": [ + {"type": "apples", "id": "1", "attributes": {"color": "red"}}, + {"type": "apples", "id": "2", "attributes": {"color": "yellow"}} + ] + } + ', + new CompoundDocument( + new ResourceObject( + 'baskets', + '1', + new ToMany( + 'fruits', + new PaginatedResourceIdentifierCollection( + new Pagination( + new FirstLink('http://example.com/basket/1/fruits?page=first'), + new PrevLink('http://example.com/basket/1/fruits?page=3'), + new NextLink('http://example.com/basket/1/fruits?page=5'), + new LastLink('http://example.com/basket/1/fruits?page=last') + ), + new ResourceIdentifier('apples', '1'), + new ResourceIdentifier('apples', '2') + ) + ) + ), + new Included( + new ResourceObject('apples', '1', new Attribute('color', 'red')), + new ResourceObject('apples', '2', new Attribute('color', 'yellow')) + ) + ) + ); + } +} From 4774558e34869768833ce9aa8b582261ab3b7148 Mon Sep 17 00:00:00 2001 From: Alexey Karapetov Date: Thu, 1 Mar 2018 01:53:03 -0800 Subject: [PATCH 26/26] Performance improvements --- tmp.php | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 tmp.php diff --git a/tmp.php b/tmp.php deleted file mode 100644 index 4caa457..0000000 --- a/tmp.php +++ /dev/null @@ -1,40 +0,0 @@ -