|
20 | 20 | use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; |
21 | 21 | use Symfony\Component\Serializer\Normalizer\NormalizerInterface; |
22 | 22 | use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; |
| 23 | +use Symfony\UX\LiveComponent\Attribute\LiveProp; |
23 | 24 | use Symfony\UX\LiveComponent\Exception\HydrationException; |
24 | 25 | use Symfony\UX\LiveComponent\Hydration\HydrationExtensionInterface; |
25 | 26 | use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadata; |
@@ -208,6 +209,10 @@ public function hydrate(object $component, array $props, array $updatedProps, Li |
208 | 209 | // unexpected and can't be set - e.g. a string field for an `int` property. |
209 | 210 | // We ignore this, and allow the original value to remain set. |
210 | 211 | } |
| 212 | + |
| 213 | + if ($propMetadata->onUpdated()) { |
| 214 | + $this->processOnUpdatedHook($component, $frontendName, $propMetadata, $dehydratedUpdatedProps, $dehydratedOriginalProps); |
| 215 | + } |
211 | 216 | } |
212 | 217 |
|
213 | 218 | foreach (AsLiveComponent::postHydrateMethods($component) as $method) { |
@@ -559,4 +564,52 @@ private function recursiveKeySort(array &$data): void |
559 | 564 | } |
560 | 565 | ksort($data); |
561 | 566 | } |
| 567 | + |
| 568 | + private function ensureOnUpdatedMethodExists(object $component, string $methodName): void |
| 569 | + { |
| 570 | + if (method_exists($component, $methodName)) { |
| 571 | + return; |
| 572 | + } |
| 573 | + |
| 574 | + throw new \Exception(sprintf('Method "%s:%s()" specified as LiveProp "onUpdated" hook does not exist.', $component::class, $methodName)); |
| 575 | + } |
| 576 | + |
| 577 | + /** |
| 578 | + * A special hook that will be called if the LiveProp was changed |
| 579 | + * and $onUpdated argument is set on its attribute. |
| 580 | + */ |
| 581 | + private function processOnUpdatedHook(object $component, string $frontendName, LivePropMetadata $propMetadata, DehydratedProps $dehydratedUpdatedProps, DehydratedProps $dehydratedOriginalProps): void |
| 582 | + { |
| 583 | + $onUpdated = $propMetadata->onUpdated(); |
| 584 | + if (\is_string($onUpdated)) { |
| 585 | + $onUpdated = [LiveProp::IDENTITY => $onUpdated]; |
| 586 | + } |
| 587 | + |
| 588 | + foreach ($onUpdated as $propName => $funcName) { |
| 589 | + if (LiveProp::IDENTITY === $propName) { |
| 590 | + if (!$dehydratedUpdatedProps->hasPropValue($frontendName)) { |
| 591 | + continue; |
| 592 | + } |
| 593 | + |
| 594 | + $this->ensureOnUpdatedMethodExists($component, $funcName); |
| 595 | + $propertyOldValue = $this->hydrateValue( |
| 596 | + $dehydratedOriginalProps->getPropValue($frontendName), |
| 597 | + $propMetadata, |
| 598 | + $component, |
| 599 | + ); |
| 600 | + $component->{$funcName}($propertyOldValue); |
| 601 | + |
| 602 | + continue; |
| 603 | + } |
| 604 | + |
| 605 | + $key = sprintf('%s.%s', $frontendName, $propName); |
| 606 | + if (!$dehydratedUpdatedProps->hasPropValue($key)) { |
| 607 | + continue; |
| 608 | + } |
| 609 | + |
| 610 | + $this->ensureOnUpdatedMethodExists($component, $funcName); |
| 611 | + $propertyOldValue = $dehydratedOriginalProps->getPropValue($key); |
| 612 | + $component->{$funcName}($propertyOldValue); |
| 613 | + } |
| 614 | + } |
562 | 615 | } |
0 commit comments