1515use JsonApiPhp \JsonApi \Document \LinksTrait ;
1616use JsonApiPhp \JsonApi \Document \Meta ;
1717use JsonApiPhp \JsonApi \Document \MetaTrait ;
18- use JsonApiPhp \JsonApi \Document \Resource \ResourceInterface ;
18+ use JsonApiPhp \JsonApi \Document \PrimaryData \MultiIdentifierData ;
19+ use JsonApiPhp \JsonApi \Document \PrimaryData \MultiResourceData ;
20+ use JsonApiPhp \JsonApi \Document \PrimaryData \NullData ;
21+ use JsonApiPhp \JsonApi \Document \PrimaryData \PrimaryDataInterface ;
22+ use JsonApiPhp \JsonApi \Document \PrimaryData \SingleIdentifierData ;
23+ use JsonApiPhp \JsonApi \Document \PrimaryData \SingleResourceData ;
24+ use JsonApiPhp \JsonApi \Document \Resource \ResourceIdentifier ;
1925use JsonApiPhp \JsonApi \Document \Resource \ResourceObject ;
2026
2127class Document implements \JsonSerializable
@@ -26,11 +32,23 @@ class Document implements \JsonSerializable
2632 use LinksTrait;
2733 use MetaTrait;
2834
35+ /**
36+ * @var PrimaryDataInterface
37+ */
2938 private $ data ;
39+
40+ /**
41+ * @var Error[]
42+ */
3043 private $ errors ;
44+
3145 private $ api ;
46+
47+ /**
48+ * @var ResourceObject[]
49+ */
3250 private $ included ;
33- private $ is_sparse = false ;
51+ private $ sparse = false ;
3452
3553 private function __construct ()
3654 {
@@ -50,17 +68,38 @@ public static function fromErrors(Error ...$errors): self
5068 return $ doc ;
5169 }
5270
53- public static function fromResource (ResourceInterface $ data ): self
71+ public static function fromResource (ResourceObject $ resource ): self
72+ {
73+ $ doc = new self ;
74+ $ doc ->data = new SingleResourceData ($ resource );
75+ return $ doc ;
76+ }
77+
78+ public static function fromResources (ResourceObject ...$ resources ): self
79+ {
80+ $ doc = new self ;
81+ $ doc ->data = new MultiResourceData (...$ resources );
82+ return $ doc ;
83+ }
84+
85+ public static function fromIdentifier (ResourceIdentifier $ identifier )
86+ {
87+ $ doc = new self ;
88+ $ doc ->data = new SingleIdentifierData ($ identifier );
89+ return $ doc ;
90+ }
91+
92+ public static function fromIdentifiers (ResourceIdentifier ... $ identifiers )
5493 {
5594 $ doc = new self ;
56- $ doc ->data = $ data ;
95+ $ doc ->data = new MultiIdentifierData (... $ identifiers ) ;
5796 return $ doc ;
5897 }
5998
60- public static function fromResources ( ResourceInterface ... $ data ): self
99+ public static function nullDocument ()
61100 {
62101 $ doc = new self ;
63- $ doc ->data = $ data ;
102+ $ doc ->data = new NullData () ;
64103 return $ doc ;
65104 }
66105
@@ -69,19 +108,27 @@ public function setApiVersion(string $version = self::DEFAULT_API_VERSION)
69108 $ this ->api ['version ' ] = $ version ;
70109 }
71110
72- public function setApiMeta (array $ meta )
111+ public function setApiMeta (Meta $ meta )
73112 {
74113 $ this ->api ['meta ' ] = $ meta ;
75114 }
76115
77- public function setIncluded (ResourceObject ...$ included )
116+ public function setIncluded (ResourceObject ...$ resources )
78117 {
79- $ this ->included = $ included ;
118+ if (null === $ this ->data ) {
119+ throw new \LogicException ('Document with no data cannot contain included resources ' );
120+ }
121+ foreach ($ resources as $ resource ) {
122+ if (isset ($ this ->included [(string ) $ resource ->toIdentifier ()])) {
123+ throw new \LogicException ("Resource {$ resource ->toIdentifier ()} is already included " );
124+ }
125+ $ this ->included [(string ) $ resource ->toIdentifier ()] = $ resource ;
126+ }
80127 }
81128
82129 public function markSparse ()
83130 {
84- $ this ->is_sparse = true ;
131+ $ this ->sparse = true ;
85132 }
86133
87134 public function jsonSerialize ()
@@ -94,7 +141,7 @@ public function jsonSerialize()
94141 'meta ' => $ this ->meta ,
95142 'jsonapi ' => $ this ->api ,
96143 'links ' => $ this ->links ,
97- 'included ' => $ this ->included ,
144+ 'included ' => $ this ->included ? array_values ( $ this -> included ) : null ,
98145 ],
99146 function ($ v ) {
100147 return null !== $ v ;
@@ -104,47 +151,19 @@ function ($v) {
104151
105152 private function enforceFullLinkage ()
106153 {
107- if ($ this ->is_sparse || empty ($ this ->included )) {
154+ if ($ this ->sparse || empty ($ this ->included )) {
108155 return ;
109156 }
110- foreach ($ this ->included as $ included_resource ) {
111- if ($ this ->hasLinkTo ( $ included_resource ) || $ this -> anotherIncludedResourceIdentifies ( $ included_resource )) {
157+ foreach ($ this ->included as $ included ) {
158+ if ($ this ->data -> hasLinkTo ( $ included )) {
112159 continue ;
113160 }
114- throw new \LogicException ("Full linkage is required for $ included_resource " );
115- }
116- }
117-
118- private function anotherIncludedResourceIdentifies (ResourceObject $ resource ): bool
119- {
120- /** @var ResourceObject $included_resource */
121- foreach ($ this ->included as $ included_resource ) {
122- if ($ included_resource !== $ resource && $ included_resource ->identifies ($ resource )) {
123- return true ;
124- }
125- }
126- return false ;
127- }
128-
129- private function hasLinkTo (ResourceObject $ resource ): bool
130- {
131- /** @var ResourceInterface $my_resource */
132- foreach ($ this ->toResources () as $ my_resource ) {
133- if ($ my_resource ->identifies ($ resource )) {
134- return true ;
135- }
136- }
137- return false ;
138- }
139-
140- private function toResources (): \Iterator
141- {
142- if ($ this ->data instanceof ResourceInterface) {
143- yield $ this ->data ;
144- } elseif (is_array ($ this ->data )) {
145- foreach ($ this ->data as $ datum ) {
146- yield $ datum ;
161+ foreach ($ this ->included as $ anotherIncluded ) {
162+ if ($ anotherIncluded ->identifies ($ included )) {
163+ continue 2 ;
164+ }
147165 }
166+ throw new \LogicException ("Full linkage is required for {$ included ->toIdentifier ()}" );
148167 }
149168 }
150169}
0 commit comments