|
19 | 19 | use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; |
20 | 20 | use Symfony\Component\PropertyInfo\PropertyInfoExtractor; |
21 | 21 | use Symfony\Component\PropertyInfo\Type; |
| 22 | +use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerExceptionInterface; |
22 | 23 | use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; |
23 | 24 | use Symfony\Component\Serializer\Normalizer\NormalizerInterface; |
24 | 25 | use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; |
@@ -226,6 +227,55 @@ public function hydrate(object $component, array $props, array $updatedProps, Li |
226 | 227 | return $attributes; |
227 | 228 | } |
228 | 229 |
|
| 230 | + /** |
| 231 | + * Hydrate a value from a dehydrated value. |
| 232 | + * |
| 233 | + * Depending on the prop configuration, the value may be hydrated by a custom method or the Serializer component. |
| 234 | + * |
| 235 | + * @throws SerializerExceptionInterface |
| 236 | + */ |
| 237 | + public function hydrateValue(mixed $value, LivePropMetadata $propMetadata, object $parentObject): mixed |
| 238 | + { |
| 239 | + if ($propMetadata->hydrateMethod()) { |
| 240 | + if (!method_exists($parentObject, $propMetadata->hydrateMethod())) { |
| 241 | + throw new \LogicException(sprintf('The "%s" object has a hydrateMethod of "%s" but the method does not exist.', $parentObject::class, $propMetadata->hydrateMethod())); |
| 242 | + } |
| 243 | + |
| 244 | + return $parentObject->{$propMetadata->hydrateMethod()}($value); |
| 245 | + } |
| 246 | + |
| 247 | + if ($propMetadata->useSerializerForHydration()) { |
| 248 | + return $this->normalizer->denormalize($value, $propMetadata->getType(), 'json', $propMetadata->serializationContext()); |
| 249 | + } |
| 250 | + |
| 251 | + if ($propMetadata->collectionValueType() && Type::BUILTIN_TYPE_OBJECT === $propMetadata->collectionValueType()->getBuiltinType()) { |
| 252 | + $collectionClass = $propMetadata->collectionValueType()->getClassName(); |
| 253 | + foreach ($value as $key => $objectItem) { |
| 254 | + $value[$key] = $this->hydrateObjectValue($objectItem, $collectionClass, true, $parentObject::class, sprintf('%s.%s', $propMetadata->getName(), $key), $parentObject); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + // no type? no hydration |
| 259 | + if (!$propMetadata->getType()) { |
| 260 | + return $value; |
| 261 | + } |
| 262 | + |
| 263 | + if (null === $value) { |
| 264 | + return null; |
| 265 | + } |
| 266 | + |
| 267 | + if (\is_string($value) && $propMetadata->isBuiltIn() && \in_array($propMetadata->getType(), ['int', 'float', 'bool'], true)) { |
| 268 | + return self::coerceStringValue($value, $propMetadata->getType(), $propMetadata->allowsNull()); |
| 269 | + } |
| 270 | + |
| 271 | + // for all other built-ins: int, boolean, array, return as is |
| 272 | + if ($propMetadata->isBuiltIn()) { |
| 273 | + return $value; |
| 274 | + } |
| 275 | + |
| 276 | + return $this->hydrateObjectValue($value, $propMetadata->getType(), $propMetadata->allowsNull(), $parentObject::class, $propMetadata->getName(), $parentObject); |
| 277 | + } |
| 278 | + |
229 | 279 | public function addChecksumToData(array $data): array |
230 | 280 | { |
231 | 281 | $data[self::CHECKSUM_KEY] = $this->calculateChecksum($data); |
@@ -410,48 +460,6 @@ private function dehydrateObjectValue(object $value, string $classType, ?string |
410 | 460 | return $dehydratedObjectValues; |
411 | 461 | } |
412 | 462 |
|
413 | | - public function hydrateValue(mixed $value, LivePropMetadata $propMetadata, object $parentObject): mixed |
414 | | - { |
415 | | - if ($propMetadata->hydrateMethod()) { |
416 | | - if (!method_exists($parentObject, $propMetadata->hydrateMethod())) { |
417 | | - throw new \LogicException(sprintf('The "%s" object has a hydrateMethod of "%s" but the method does not exist.', $parentObject::class, $propMetadata->hydrateMethod())); |
418 | | - } |
419 | | - |
420 | | - return $parentObject->{$propMetadata->hydrateMethod()}($value); |
421 | | - } |
422 | | - |
423 | | - if ($propMetadata->useSerializerForHydration()) { |
424 | | - return $this->normalizer->denormalize($value, $propMetadata->getType(), 'json', $propMetadata->serializationContext()); |
425 | | - } |
426 | | - |
427 | | - if ($propMetadata->collectionValueType() && Type::BUILTIN_TYPE_OBJECT === $propMetadata->collectionValueType()->getBuiltinType()) { |
428 | | - $collectionClass = $propMetadata->collectionValueType()->getClassName(); |
429 | | - foreach ($value as $key => $objectItem) { |
430 | | - $value[$key] = $this->hydrateObjectValue($objectItem, $collectionClass, true, $parentObject::class, sprintf('%s.%s', $propMetadata->getName(), $key), $parentObject); |
431 | | - } |
432 | | - } |
433 | | - |
434 | | - // no type? no hydration |
435 | | - if (!$propMetadata->getType()) { |
436 | | - return $value; |
437 | | - } |
438 | | - |
439 | | - if (null === $value) { |
440 | | - return null; |
441 | | - } |
442 | | - |
443 | | - if (\is_string($value) && $propMetadata->isBuiltIn() && \in_array($propMetadata->getType(), ['int', 'float', 'bool'], true)) { |
444 | | - return self::coerceStringValue($value, $propMetadata->getType(), $propMetadata->allowsNull()); |
445 | | - } |
446 | | - |
447 | | - // for all other built-ins: int, boolean, array, return as is |
448 | | - if ($propMetadata->isBuiltIn()) { |
449 | | - return $value; |
450 | | - } |
451 | | - |
452 | | - return $this->hydrateObjectValue($value, $propMetadata->getType(), $propMetadata->allowsNull(), $parentObject::class, $propMetadata->getName(), $parentObject); |
453 | | - } |
454 | | - |
455 | 463 | private function hydrateObjectValue(mixed $value, string $className, bool $allowsNull, string $componentClassForError, string $propertyPathForError, object $component): ?object |
456 | 464 | { |
457 | 465 | // enum |
|
0 commit comments