99use Tobyz \JsonApiServer \Exception \Sourceable ;
1010use Tobyz \JsonApiServer \Exception \UnprocessableEntityException ;
1111use Tobyz \JsonApiServer \Schema \Field \Field ;
12+ use Tobyz \JsonApiServer \Schema \Id ;
1213
14+ use function Tobyz \JsonApiServer \field_path ;
1315use function Tobyz \JsonApiServer \get_value ;
1416use function Tobyz \JsonApiServer \has_value ;
15- use function Tobyz \JsonApiServer \location ;
1617use function Tobyz \JsonApiServer \set_value ;
1718
1819trait SavesData
@@ -47,15 +48,11 @@ private function parseData(Context $context): array
4748 ]);
4849 }
4950
50- if ($ body ['data ' ]['id ' ] !== $ context ->resource -> getId ($ context ->model , $ context )) {
51+ if ($ body ['data ' ]['id ' ] !== $ context ->id ($ context ->resource , $ context-> model )) {
5152 throw (new ConflictException ('data.id does not match the resource ID ' ))->setSource ([
5253 'pointer ' => '/data/id ' ,
5354 ]);
5455 }
55- } elseif (isset ($ body ['data ' ]['id ' ])) {
56- throw (new ForbiddenException ('Client-generated IDs are not supported ' ))->setSource ([
57- 'pointer ' => '/data/id ' ,
58- ]);
5956 }
6057
6158 if (!in_array ($ body ['data ' ]['type ' ], $ context ->collection ->resources ())) {
@@ -85,6 +82,17 @@ private function parseData(Context $context): array
8582 return array_merge (['attributes ' => [], 'relationships ' => []], $ body ['data ' ]);
8683 }
8784
85+ private function getFields (Context $ context , bool $ creating = false ): array
86+ {
87+ $ fields = $ context ->fields ($ context ->resource );
88+
89+ if ($ creating ) {
90+ array_unshift ($ fields , $ context ->resource ->id ());
91+ }
92+
93+ return $ fields ;
94+ }
95+
8896 /**
8997 * Assert that the fields contained within a data object are valid.
9098 */
@@ -101,13 +109,13 @@ private function assertFieldsValid(Context $context, array $data, bool $creating
101109 */
102110 private function assertFieldsExist (Context $ context , array $ data ): void
103111 {
104- $ fields = $ context -> fields ($ context-> resource );
112+ $ fields = $ this -> getFields ($ context );
105113
106114 foreach (['attributes ' , 'relationships ' ] as $ location ) {
107115 foreach ($ data [$ location ] as $ name => $ value ) {
108- if (!isset ($ fields [$ name ]) || $ location !== location ( $ fields [$ name ])) {
116+ if (!isset ($ fields [$ name ]) || $ location !== $ fields [$ name ]-> location ( )) {
109117 throw (new BadRequestException ("Unknown field [ $ name] " ))->setSource ([
110- 'pointer ' => " /data/ $ location/ $ name" ,
118+ 'pointer ' => ' /data/ ' . implode ( ' / ' , array_filter ([ $ location, $ name])) ,
111119 ]);
112120 }
113121 }
@@ -124,17 +132,15 @@ private function assertFieldsWritable(
124132 array $ data ,
125133 bool $ creating = false ,
126134 ): void {
127- foreach ($ context -> fields ($ context-> resource ) as $ field ) {
135+ foreach ($ this -> getFields ($ context, $ creating ) as $ field ) {
128136 if (!has_value ($ data , $ field )) {
129137 continue ;
130138 }
131139
132140 try {
133141 $ this ->assertFieldWritable ($ context , $ field , $ creating );
134142 } catch (Sourceable $ e ) {
135- throw $ e ->prependSource ([
136- 'pointer ' => '/data/ ' . location ($ field ) . '/ ' . $ field ->name ,
137- ]);
143+ throw $ e ->prependSource (['pointer ' => '/data ' . field_path ($ field )]);
138144 }
139145 }
140146 }
@@ -156,9 +162,9 @@ private function assertFieldWritable(
156162 /**
157163 *
158164 */
159- private function deserializeValues (Context $ context , array &$ data ): void
165+ private function deserializeValues (Context $ context , array &$ data, bool $ creating = false ): void
160166 {
161- foreach ($ context -> fields ($ context-> resource ) as $ field ) {
167+ foreach ($ this -> getFields ($ context, $ creating ) as $ field ) {
162168 if (!has_value ($ data , $ field )) {
163169 continue ;
164170 }
@@ -168,9 +174,7 @@ private function deserializeValues(Context $context, array &$data): void
168174 try {
169175 set_value ($ data , $ field , $ field ->deserializeValue ($ value , $ context ));
170176 } catch (Sourceable $ e ) {
171- throw $ e ->prependSource ([
172- 'pointer ' => '/data/ ' . location ($ field ) . '/ ' . $ field ->name ,
173- ]);
177+ throw $ e ->prependSource (['pointer ' => '/data ' . field_path ($ field )]);
174178 }
175179 }
176180 }
@@ -184,7 +188,7 @@ private function assertDataValid(Context $context, array $data, bool $validateAl
184188 {
185189 $ errors = [];
186190
187- foreach ($ context -> fields ($ context-> resource ) as $ field ) {
191+ foreach ($ this -> getFields ($ context, $ validateAll ) as $ field ) {
188192 $ present = has_value ($ data , $ field );
189193
190194 if (!$ present && (!$ field ->required || !$ validateAll )) {
@@ -201,7 +205,7 @@ private function assertDataValid(Context $context, array $data, bool $validateAl
201205 $ errors ,
202206 array_map (
203207 fn ($ error ) => $ error + [
204- 'source ' => ['pointer ' => '/data/ ' . location ($ field ) . ' / ' . $ field -> name ],
208+ 'source ' => ['pointer ' => '/data ' . field_path ($ field )],
205209 ],
206210 $ fieldErrors ,
207211 ),
@@ -213,7 +217,7 @@ private function assertDataValid(Context $context, array $data, bool $validateAl
213217 }
214218 }
215219
216- private function validateField (Context $ context , Field $ field , mixed $ value ): array
220+ private function validateField (Context $ context , Field | Id $ field , mixed $ value ): array
217221 {
218222 $ errors = [];
219223
@@ -229,9 +233,9 @@ private function validateField(Context $context, Field $field, mixed $value): ar
229233 /**
230234 * Set field values from a data object to the model instance.
231235 */
232- private function setValues (Context $ context , array $ data ): void
236+ private function setValues (Context $ context , array $ data, bool $ creating = false ): void
233237 {
234- foreach ($ context -> fields ($ context-> resource ) as $ field ) {
238+ foreach ($ this -> getFields ($ context, $ creating ) as $ field ) {
235239 if (!has_value ($ data , $ field )) {
236240 continue ;
237241 }
@@ -245,9 +249,9 @@ private function setValues(Context $context, array $data): void
245249 /**
246250 * Run any field save callbacks.
247251 */
248- private function saveFields (Context $ context , array $ data ): void
252+ private function saveFields (Context $ context , array $ data, bool $ creating = false ): void
249253 {
250- foreach ($ context -> fields ($ context-> resource ) as $ field ) {
254+ foreach ($ this -> getFields ($ context, $ creating ) as $ field ) {
251255 if (!has_value ($ data , $ field )) {
252256 continue ;
253257 }
0 commit comments