diff --git a/src/TwigComponent/src/ComponentAttributes.php b/src/TwigComponent/src/ComponentAttributes.php
index ecd8f97918a..7ac148bb509 100644
--- a/src/TwigComponent/src/ComponentAttributes.php
+++ b/src/TwigComponent/src/ComponentAttributes.php
@@ -35,6 +35,10 @@ public function __toString(): string
function (string $carry, string $key) {
$value = $this->attributes[$key];
+ if (!\is_scalar($value) && null !== $value) {
+ throw new \LogicException(sprintf('A "%s" prop was passed when creating the component. No matching "%s" property or mount() argument was found, so we attempted to use this as an HTML attribute. But, the value is not a scalar (it\'s a %s). Did you mean to pass this to your component or is there a typo on its name?', $key, $key, get_debug_type($value)));
+ }
+
if (null === $value) {
trigger_deprecation('symfony/ux-twig-component', '2.8.0', 'Passing "null" as an attribute value is deprecated and will throw an exception in 3.0.');
$value = true;
@@ -144,4 +148,13 @@ public function add($stimulusDto): self
// add the remaining attributes for values/classes
return $clone->defaults($controllersAttributes);
}
+
+ public function remove($key): self
+ {
+ $attributes = $this->attributes;
+
+ unset($attributes[$key]);
+
+ return new self($attributes);
+ }
}
diff --git a/src/TwigComponent/src/ComponentFactory.php b/src/TwigComponent/src/ComponentFactory.php
index 3877889f888..b75fc32f19f 100644
--- a/src/TwigComponent/src/ComponentFactory.php
+++ b/src/TwigComponent/src/ComponentFactory.php
@@ -102,9 +102,7 @@ public function mountFromObject(object $component, array $data, ComponentMetadat
continue;
}
- if (!\is_scalar($value) && null !== $value) {
- throw new \LogicException(sprintf('A "%s" prop was passed when creating the "%s" component. No matching %s property or mount() argument was found, so we attempted to use this as an HTML attribute. But, the value is not a scalar (it\'s a %s). Did you mean to pass this to your component or is there a typo on its name?', $key, $componentMetadata->getName(), $key, get_debug_type($value)));
- }
+ $data[$key] = $value;
}
return new MountedComponent(
diff --git a/src/TwigComponent/src/Twig/PropsNode.php b/src/TwigComponent/src/Twig/PropsNode.php
index 91208c5195e..92932a5d53f 100644
--- a/src/TwigComponent/src/Twig/PropsNode.php
+++ b/src/TwigComponent/src/Twig/PropsNode.php
@@ -28,17 +28,21 @@ public function __construct(array $propsNames, array $values, $lineno = 0, strin
public function compile(Compiler $compiler): void
{
+ $compiler
+ ->addDebugInfo($this)
+ ->write('$propsNames = [];')
+ ;
+
foreach ($this->getAttribute('names') as $name) {
$compiler
- ->addDebugInfo($this)
- ->write('if (!isset($context[\''.$name.'\'])) {')
- ;
+ ->write('$propsNames[] = \''.$name.'\';')
+ ->write('$context[\'attributes\'] = $context[\'attributes\']->remove(\''.$name.'\');')
+ ->write('if (!isset($context[\''.$name.'\'])) {');
if (!$this->hasNode($name)) {
$compiler
->write('throw new \Twig\Error\RuntimeError("'.$name.' should be defined for component '.$this->getTemplateName().'");')
- ->write('}')
- ;
+ ->write('}');
continue;
}
@@ -47,8 +51,20 @@ public function compile(Compiler $compiler): void
->write('$context[\''.$name.'\'] = ')
->subcompile($this->getNode($name))
->raw(";\n")
- ->write('}')
- ;
+ ->write('}');
}
+
+ $compiler
+ ->write('$attributesKeys = array_keys($context[\'attributes\']->all());')
+ ->raw("\n")
+ ->write('foreach ($context as $key => $value) {')
+ ->raw("\n")
+ ->write('if (in_array($key, $attributesKeys) && !in_array($key, $propsNames)) {')
+ ->raw("\n")
+ ->raw('unset($context[$key]);')
+ ->raw("\n")
+ ->write('}')
+ ->write('}')
+ ;
}
}
diff --git a/src/TwigComponent/tests/Fixtures/User.php b/src/TwigComponent/tests/Fixtures/User.php
new file mode 100644
index 00000000000..eb25026072a
--- /dev/null
+++ b/src/TwigComponent/tests/Fixtures/User.php
@@ -0,0 +1,21 @@
+name;
+ }
+
+ public function getEmail(): string
+ {
+ return $this->email;
+ }
+}
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Fixtures/templates/anonymous_component_none_scalar_prop.html.twig b/src/TwigComponent/tests/Fixtures/templates/anonymous_component_none_scalar_prop.html.twig
new file mode 100644
index 00000000000..4bbccfb3fb7
--- /dev/null
+++ b/src/TwigComponent/tests/Fixtures/templates/anonymous_component_none_scalar_prop.html.twig
@@ -0,0 +1 @@
+
{{ user.name }}
+{{ user.email }}
+class variable defined? {{ class is defined ? 'yes': 'no' }}
+