2424use Illuminate \Database \Eloquent \Model ;
2525use Illuminate \Http \Response ;
2626use LaravelJsonApi \Contracts \Auth \Authorizer ;
27- use LaravelJsonApi \Contracts \Resources \ Container as ResourceContainer ;
27+ use LaravelJsonApi \Contracts \Schema \ Relation ;
2828use LaravelJsonApi \Core \Document \ResourceObject ;
2929use LaravelJsonApi \Core \Exceptions \JsonApiException ;
30- use LaravelJsonApi \Core \Resources \JsonApiResource ;
31- use LaravelJsonApi \Core \Resources \Relation ;
30+ use LaravelJsonApi \Core \Query \IncludePaths ;
3231use LaravelJsonApi \Core \Support \Str ;
3332use LaravelJsonApi \Spec \RelationBuilder ;
3433use LaravelJsonApi \Spec \ResourceBuilder ;
4140class ResourceRequest extends FormRequest
4241{
4342
44- /**
45- * @var bool
46- */
47- protected bool $ validateExisting = true ;
48-
4943 /**
5044 * @var callable|null
5145 */
@@ -353,43 +347,37 @@ protected function dataForCreate(array $document): array
353347 * @param Model|object $model
354348 * the model being updated.
355349 * @param array $document
356- * the JSON API document to validate.
350+ * the JSON: API document to validate.
357351 * @return array
358352 */
359353 protected function dataForUpdate (object $ model , array $ document ): array
360354 {
361- $ data = $ document ['data ' ] ?? [];
362-
363- if ($ this ->mustValidateExisting ($ model , $ document )) {
364- $ data ['attributes ' ] = $ this ->extractAttributes (
365- $ model ,
366- $ data ['attributes ' ] ?? []
367- );
355+ $ existing = $ this ->extractForUpdate ($ model );
368356
369- $ data ['relationships ' ] = $ this ->extractRelationships (
370- $ model ,
371- $ data ['relationships ' ] ?? []
372- );
357+ if (method_exists ($ this , 'withExisting ' )) {
358+ $ existing = $ this ->withExisting ($ model , $ existing ) ?? $ existing ;
373359 }
374360
375- return $ data ;
361+ return ResourceObject::fromArray ($ existing )->merge (
362+ $ document ['data ' ]
363+ )->jsonSerialize ();
376364 }
377365
378366 /**
379367 * Get validation data for modifying a relationship.
380368 *
381- * @param Model|object $record
369+ * @param Model|object $model
382370 * @param string $fieldName
383371 * @param array $document
384372 * @return array
385373 */
386- protected function dataForRelationship (object $ record , string $ fieldName , array $ document ): array
374+ protected function dataForRelationship (object $ model , string $ fieldName , array $ document ): array
387375 {
388- $ resource = $ this ->resources ()->create ( $ record );
376+ $ route = $ this ->jsonApi ()->route ( );
389377
390378 return [
391- 'type ' => $ resource -> type (),
392- 'id ' => $ resource -> id (),
379+ 'type ' => $ route -> resourceType (),
380+ 'id ' => $ route -> resourceId (),
393381 'relationships ' => [
394382 $ fieldName => [
395383 'data ' => $ document ['data ' ],
@@ -406,14 +394,7 @@ protected function dataForRelationship(object $record, string $fieldName, array
406394 */
407395 protected function dataForDelete (object $ record ): array
408396 {
409- $ route = $ this ->jsonApi ()->route ();
410-
411- $ data = $ this ->dataForUpdate ($ record , [
412- 'data ' => [
413- 'type ' => $ route ->resourceType (),
414- 'id ' => $ route ->resourceId (),
415- ],
416- ]);
397+ $ data = $ this ->extractForUpdate ($ record );
417398
418399 if (method_exists ($ this , 'metaForDelete ' )) {
419400 $ data ['meta ' ] = (array ) $ this ->metaForDelete ($ record );
@@ -423,80 +404,36 @@ protected function dataForDelete(object $record): array
423404 }
424405
425406 /**
426- * Should existing resource values be provided to the validator for an update request?
407+ * Extract the existing values for the provided model.
427408 *
428- * Child classes can overload this method if they need to programmatically work out
429- * if existing values must be provided to the validator instance for an update request.
430- *
431- * @param Model|object $model
432- * the model being updated
433- * @param array $document
434- * the JSON API document provided by the client.
435- * @return bool
436- */
437- protected function mustValidateExisting (object $ model , array $ document ): bool
438- {
439- return false !== $ this ->validateExisting ;
440- }
441-
442- /**
443- * Extract existing attributes for the provided model.
444- *
445- * @param Model|object $model
446- * @return iterable
409+ * @param object $model
410+ * @return array
447411 */
448- protected function existingAttributes (object $ model ): iterable
412+ private function extractForUpdate (object $ model ): array
449413 {
450- $ resource = $ this ->resources ()->create ( $ model );
414+ $ encoder = $ this ->jsonApi ()->server ()-> encoder ( );
451415
452- return $ resource ->attributes ($ this );
416+ return $ encoder
417+ ->withRequest ($ this )
418+ ->withIncludePaths ($ this ->includePathsToExtract ($ model ))
419+ ->withResource ($ model )
420+ ->toArray ()['data ' ];
453421 }
454422
455423 /**
456- * Extract existing relationships for the provided model .
424+ * Get the relationship paths that must be included when extracting the current field values .
457425 *
458- * @param Model| object $model
459- * @return iterable
426+ * @param object $model
427+ * @return IncludePaths
460428 */
461- protected function existingRelationships (object $ model ): iterable
429+ private function includePathsToExtract (object $ model ): IncludePaths
462430 {
463- $ resource = $ this ->resources ()->create ($ model );
464-
465- /** @var Relation $relationship */
466- foreach ($ resource ->relationships ($ this ) as $ relationship ) {
467- if ($ relationship ->isValidated ()) {
468- yield $ relationship ->fieldName () => $ relationship ->data ();
469- }
470- }
471- }
431+ $ paths = collect ($ this ->schema ()->relationships ())
432+ ->filter (fn (Relation $ relation ) => $ relation ->isValidated ())
433+ ->map (fn (Relation $ relation ) => $ relation ->name ())
434+ ->values ();
472435
473- /**
474- * Extract attributes for a resource update.
475- *
476- * @param Model|object $model
477- * @param array $new
478- * @return array
479- */
480- private function extractAttributes (object $ model , array $ new ): array
481- {
482- return collect ($ this ->existingAttributes ($ model ))
483- ->merge ($ new )
484- ->all ();
485- }
486-
487- /**
488- * Extract relationships for a resource update.
489- *
490- * @param Model|object $model
491- * @param array $new
492- * @return array
493- */
494- private function extractRelationships (object $ model , array $ new ): array
495- {
496- return collect ($ this ->existingRelationships ($ model ))
497- ->map (fn ($ value ) => $ this ->convertExistingRelationships ($ value ))
498- ->merge ($ new )
499- ->all ();
436+ return IncludePaths::fromArray ($ paths );
500437 }
501438
502439 /**
@@ -514,64 +451,6 @@ private function relationshipRules(): array
514451 ->all ();
515452 }
516453
517- /**
518- * Convert relationships returned by the `existingRelationships()` method.
519- *
520- * We support the method returning JSON API formatted relationships, e.g.:
521- *
522- * ```
523- * return [
524- * 'author' => [
525- * 'data' => [
526- * 'type' => 'users',
527- * 'id' => (string) $record->author->getRouteKey(),
528- * ],
529- * ],
530- * ];
531- * ```
532- *
533- * Or this shorthand:
534- *
535- * ```php
536- * return [
537- * 'author' => $record->author,
538- * ];
539- * ```
540- *
541- * This method converts the shorthand into the JSON API formatted relationships.
542- *
543- * @param $value
544- * @return array
545- */
546- private function convertExistingRelationships ($ value )
547- {
548- if (is_array ($ value ) && array_key_exists ('data ' , $ value )) {
549- return $ value ;
550- }
551-
552- if (is_null ($ value )) {
553- return ['data ' => null ];
554- }
555-
556- $ value = $ this ->resources ()->resolve ($ value );
557-
558- if ($ value instanceof JsonApiResource) {
559- return [
560- 'data ' => [
561- 'type ' => $ value ->type (),
562- 'id ' => $ value ->id (),
563- ],
564- ];
565- }
566-
567- return [
568- 'data ' => collect ($ value )->map (fn (JsonApiResource $ resource ) => [
569- 'type ' => $ resource ->type (),
570- 'id ' => $ resource ->id ()
571- ])->all (),
572- ];
573- }
574-
575454 /**
576455 * Validate the JSON API document for a resource request.
577456 *
@@ -618,12 +497,4 @@ private function validateRelationshipDocument(): void
618497 }
619498 }
620499
621- /**
622- * @return ResourceContainer
623- */
624- final protected function resources (): ResourceContainer
625- {
626- return $ this ->jsonApi ()->server ()->resources ();
627- }
628-
629500}
0 commit comments