|
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