|
10 | 10 | use Illuminate\Http\JsonResponse;
|
11 | 11 | use Illuminate\Http\Request;
|
12 | 12 | use Illuminate\Support\Arr;
|
| 13 | +use Illuminate\Support\Collection; |
13 | 14 | use Illuminate\Support\Facades\App;
|
14 | 15 | use Illuminate\Support\Facades\Response as ResponseFactory;
|
15 | 16 | use Illuminate\Support\Str;
|
@@ -188,6 +189,7 @@ public function toResponse($request)
|
188 | 189 | $this->resolveMergeProps($request),
|
189 | 190 | $this->resolveDeferredProps($request),
|
190 | 191 | $this->resolveCacheDirections($request),
|
| 192 | + $this->resolveScrollProps($request), |
191 | 193 | );
|
192 | 194 |
|
193 | 195 | if ($request->header(Header::INERTIA)) {
|
@@ -371,13 +373,18 @@ public function resolveAlways(array $props): array
|
371 | 373 | public function resolvePropertyInstances(array $props, Request $request, ?string $parentKey = null): array
|
372 | 374 | {
|
373 | 375 | foreach ($props as $key => $value) {
|
| 376 | + if ($value instanceof ScrollProp) { |
| 377 | + $value->configureMergeIntent($request); |
| 378 | + } |
| 379 | + |
374 | 380 | $resolveViaApp = collect([
|
375 | 381 | Closure::class,
|
376 | 382 | LazyProp::class,
|
377 | 383 | OptionalProp::class,
|
378 | 384 | DeferProp::class,
|
379 | 385 | AlwaysProp::class,
|
380 | 386 | MergeProp::class,
|
| 387 | + ScrollProp::class, |
381 | 388 | ])->first(fn ($class) => $value instanceof $class);
|
382 | 389 |
|
383 | 390 | if ($resolveViaApp) {
|
@@ -439,45 +446,112 @@ public function resolveCacheDirections(Request $request): array
|
439 | 446 | }
|
440 | 447 |
|
441 | 448 | /**
|
442 |
| - * Resolve merge props configuration for client-side prop merging. |
| 449 | + * Get the props that should be considered for merging based on the request headers. |
443 | 450 | *
|
444 |
| - * @return array<string, mixed> |
| 451 | + * @return \Illuminate\Support\Collection<string, \Inertia\Mergeable> |
445 | 452 | */
|
446 |
| - public function resolveMergeProps(Request $request): array |
| 453 | + protected function getMergePropsForRequest(Request $request): Collection |
447 | 454 | {
|
448 | 455 | $resetProps = array_filter(explode(',', $request->header(Header::RESET, '')));
|
449 | 456 | $onlyProps = array_filter(explode(',', $request->header(Header::PARTIAL_ONLY, '')));
|
450 | 457 | $exceptProps = array_filter(explode(',', $request->header(Header::PARTIAL_EXCEPT, '')));
|
451 | 458 |
|
452 |
| - $mergeProps = collect($this->props) |
| 459 | + return collect($this->props) |
453 | 460 | ->filter(fn ($prop) => $prop instanceof Mergeable)
|
454 |
| - ->filter(fn ($prop) => $prop->shouldMerge()) |
455 |
| - ->reject(fn ($_, $key) => in_array($key, $resetProps)) |
456 |
| - ->filter(fn ($_, $key) => count($onlyProps) === 0 || in_array($key, $onlyProps)) |
457 |
| - ->reject(fn ($_, $key) => in_array($key, $exceptProps)); |
| 461 | + ->filter(fn (Mergeable $prop) => $prop->shouldMerge()) |
| 462 | + ->reject(fn ($_, string $key) => in_array($key, $resetProps)) |
| 463 | + ->filter(fn ($_, string $key) => count($onlyProps) === 0 || in_array($key, $onlyProps)) |
| 464 | + ->reject(fn ($_, string $key) => in_array($key, $exceptProps)); |
| 465 | + } |
| 466 | + |
| 467 | + /** |
| 468 | + * Resolve merge props configuration for client-side prop merging. |
| 469 | + * |
| 470 | + * @return array<string, mixed> |
| 471 | + */ |
| 472 | + public function resolveMergeProps(Request $request): array |
| 473 | + { |
| 474 | + $mergeProps = $this->getMergePropsForRequest($request); |
458 | 475 |
|
459 |
| - $deepMergeProps = $mergeProps |
460 |
| - ->filter(fn ($prop) => $prop->shouldDeepMerge()) |
461 |
| - ->keys(); |
| 476 | + return array_filter([ |
| 477 | + 'mergeProps' => $this->resolveAppendMergeProps($mergeProps), |
| 478 | + 'prependProps' => $this->resolvePrependMergeProps($mergeProps), |
| 479 | + 'deepMergeProps' => $this->resolveDeepMergeProps($mergeProps), |
| 480 | + 'matchPropsOn' => $this->resolveMergeMatchingKeys($mergeProps), |
| 481 | + ], fn ($prop) => count($prop) > 0); |
| 482 | + } |
462 | 483 |
|
463 |
| - $matchPropsOn = $mergeProps |
| 484 | + /** |
| 485 | + * Resolve props that should be appended during merging. |
| 486 | + * |
| 487 | + * @param \Illuminate\Support\Collection<string, \Inertia\Mergeable> $mergeProps |
| 488 | + * @return array<int, string> |
| 489 | + */ |
| 490 | + protected function resolveAppendMergeProps(Collection $mergeProps): array |
| 491 | + { |
| 492 | + [$rootAppendProps, $nestedAppendProps] = $mergeProps |
| 493 | + ->reject(fn (Mergeable $prop) => $prop->shouldDeepMerge()) |
| 494 | + ->partition(fn (Mergeable $prop) => $prop->appendsAtRoot()); |
| 495 | + |
| 496 | + return $nestedAppendProps |
| 497 | + ->flatMap(fn (Mergeable $prop, string $key) => collect($prop->appendsAtPaths())->map(fn ($path) => $key.'.'.$path)) |
| 498 | + ->merge($rootAppendProps->keys()) |
| 499 | + ->unique() |
| 500 | + ->values() |
| 501 | + ->toArray(); |
| 502 | + } |
| 503 | + |
| 504 | + /** |
| 505 | + * Resolve props that should be prepended during merging. |
| 506 | + * |
| 507 | + * @param \Illuminate\Support\Collection<string, \Inertia\Mergeable> $mergeProps |
| 508 | + * @return array<int, string> |
| 509 | + */ |
| 510 | + protected function resolvePrependMergeProps(Collection $mergeProps): array |
| 511 | + { |
| 512 | + [$rootPrependProps, $nestedPrependProps] = $mergeProps |
| 513 | + ->reject(fn (Mergeable $prop) => $prop->shouldDeepMerge()) |
| 514 | + ->partition(fn (Mergeable $prop) => $prop->prependsAtRoot()); |
| 515 | + |
| 516 | + return $nestedPrependProps |
| 517 | + ->flatMap(fn (Mergeable $prop, string $key) => collect($prop->prependsAtPaths())->map(fn ($path) => $key.'.'.$path)) |
| 518 | + ->merge($rootPrependProps->keys()) |
| 519 | + ->unique() |
| 520 | + ->values() |
| 521 | + ->toArray(); |
| 522 | + } |
| 523 | + |
| 524 | + /** |
| 525 | + * Resolve props that should be deep merged. |
| 526 | + * |
| 527 | + * @param \Illuminate\Support\Collection<string, \Inertia\Mergeable> $mergeProps |
| 528 | + * @return array<int, string> |
| 529 | + */ |
| 530 | + protected function resolveDeepMergeProps(Collection $mergeProps): array |
| 531 | + { |
| 532 | + return $mergeProps |
| 533 | + ->filter(fn (Mergeable $prop) => $prop->shouldDeepMerge()) |
| 534 | + ->keys() |
| 535 | + ->toArray(); |
| 536 | + } |
| 537 | + |
| 538 | + /** |
| 539 | + * Resolve the matching keys for merge props. |
| 540 | + * |
| 541 | + * @param \Illuminate\Support\Collection<string, \Inertia\Mergeable> $mergeProps |
| 542 | + * @return array<int, string> |
| 543 | + */ |
| 544 | + protected function resolveMergeMatchingKeys(Collection $mergeProps): array |
| 545 | + { |
| 546 | + return $mergeProps |
464 | 547 | ->map(function (Mergeable $prop, $key) {
|
465 | 548 | return collect($prop->matchesOn())
|
466 | 549 | ->map(fn ($strategy) => $key.'.'.$strategy)
|
467 | 550 | ->toArray();
|
468 | 551 | })
|
469 | 552 | ->flatten()
|
470 |
| - ->values(); |
471 |
| - |
472 |
| - $mergeProps = $mergeProps |
473 |
| - ->filter(fn ($prop) => ! $prop->shouldDeepMerge()) |
474 |
| - ->keys(); |
475 |
| - |
476 |
| - return array_filter([ |
477 |
| - 'mergeProps' => $mergeProps->toArray(), |
478 |
| - 'deepMergeProps' => $deepMergeProps->toArray(), |
479 |
| - 'matchPropsOn' => $matchPropsOn->toArray(), |
480 |
| - ], fn ($prop) => count($prop) > 0); |
| 553 | + ->values() |
| 554 | + ->toArray(); |
481 | 555 | }
|
482 | 556 |
|
483 | 557 | /**
|
@@ -508,6 +582,20 @@ public function resolveDeferredProps(Request $request): array
|
508 | 582 | return $deferredProps->isNotEmpty() ? ['deferredProps' => $deferredProps->toArray()] : [];
|
509 | 583 | }
|
510 | 584 |
|
| 585 | + /** |
| 586 | + * Resolve scroll props configuration for client-side infinite scrolling. |
| 587 | + * |
| 588 | + * @return array<string, mixed> |
| 589 | + */ |
| 590 | + public function resolveScrollProps(Request $request): array |
| 591 | + { |
| 592 | + $scrollProps = $this->getMergePropsForRequest($request) |
| 593 | + ->filter(fn (Mergeable $prop) => $prop instanceof ScrollProp) |
| 594 | + ->mapWithKeys(fn (ScrollProp $prop, string $key) => [$key => $prop->metadata()]); |
| 595 | + |
| 596 | + return $scrollProps->isNotEmpty() ? ['scrollProps' => $scrollProps->toArray()] : []; |
| 597 | + } |
| 598 | + |
511 | 599 | /**
|
512 | 600 | * Determine if the request is a partial request.
|
513 | 601 | */
|
|
0 commit comments