Skip to content

Commit 38833d1

Browse files
committed
[Live] Adding 2 errors related to an invalid component set up
1) A better error if you have an uninitiailzed property, though there are still other cases of uninitialized properties that aren't handled yet. 2) A better error if there is a problem hydrating an object through the serializer.
1 parent 7498398 commit 38833d1

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

src/LiveComponent/src/LiveComponentHydrator.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
1515
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
16+
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
1617
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
18+
use Symfony\Component\Serializer\Exception\ExceptionInterface;
1719
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
1820
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
1921
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
@@ -71,7 +73,11 @@ public function dehydrate(MountedComponent $mounted): DehydratedComponent
7173
$frontendPropertyNames[$frontendName] = $name;
7274

7375
// TODO: improve error message if not readable
74-
$value = $this->propertyAccessor->getValue($component, $name);
76+
try {
77+
$value = $this->propertyAccessor->getValue($component, $name);
78+
} catch (UninitializedPropertyException $exception) {
79+
throw new \LogicException(sprintf('The "%s" property on the "%s" component is uninitialized. Did you forget to pass this into the component?', $name, \get_class($component)), 0, $exception);
80+
}
7581
$dehydratedValue = null;
7682

7783
if ($method = $liveProp->dehydrateMethod()) {
@@ -153,7 +159,24 @@ public function hydrate(object $component, array $data, string $componentName):
153159
} elseif (!$value && $type && $type->allowsNull() && is_a($type->getName(), \BackedEnum::class, true) && !\in_array($value, array_map(fn (\BackedEnum $e) => $e->value, $type->getName()::cases()))) {
154160
$value = null;
155161
} elseif (null !== $value && $type && !$type->isBuiltin()) {
156-
$value = $this->normalizer->denormalize($value, $type->getName(), 'json', [self::LIVE_CONTEXT => true]);
162+
try {
163+
$value = $this->normalizer->denormalize($value, $type->getName(), 'json', [self::LIVE_CONTEXT => true]);
164+
} catch (ExceptionInterface $exception) {
165+
$json = json_encode($value);
166+
$message = sprintf(
167+
'The normalizer was used to hydrate/denormalize the "%s" property on your "%s" live component, but it failed: %s',
168+
$name,
169+
\get_class($component),
170+
$exception->getMessage()
171+
);
172+
173+
// unless the data is gigantic, include it in the error to help
174+
if (\strlen($json) < 1000) {
175+
$message .= sprintf(' The data sent from the frontend was: %s', $json);
176+
}
177+
178+
throw new \LogicException($message, 0, $exception);
179+
}
157180
}
158181

159182
if ($dehydratedComponent->hasExposed($frontendName)) {

0 commit comments

Comments
 (0)