shapecode/hidden-entity-type-bundle
A Symfony bundle that adds a hidden entity form type, letting you pass entity IDs through hidden fields and have them automatically transformed back into Doctrine entities on submit—useful for forms that reference entities without showing a visible selector.
Install the bundle with Composer and register it (Symfony 4/5 style; with Symfony 6+ Flex, add it to config/bundles.php):
composer require shapecode/hidden-entity-type-bundle
// config/bundles.php
return [
// ...
Shapecode\Bundle\HiddenEntityTypeBundle\ShapecodeHiddenEntityTypeBundle::class => ['all' => true],
];
Requirements are Symfony Forms plus Doctrine (ManagerRegistry); the bundle does nothing without an entity manager available.
First use case — passing an entity reference through a form as an <input type="hidden"> instead of a visible select. For example, "create a comment for this post" where the post is known server-side and should not be user-selectable:
use Shapecode\Bundle\HiddenEntityTypeBundle\Form\Type\HiddenEntityType;
$builder->add('post', HiddenEntityType::class, [
'class' => Post::class,
]);
In Twig, {{ form_row(form.post) }} emits a single hidden input whose value is the entity ID, and on submit the ID is transformed back into a managed entity.
Where to look first:
src/Form/Type/HiddenEntityType.php — the form type and its configurable options.class and manager options.Prepopulate on edit/create forms. The type reads its value from the underlying data object or the data option. Set the entity before rendering:
$comment = new Comment();
$comment->setPost($post); // underlying object
$form = $this->createForm(CommentType::class, $comment);
// or explicitly on the field
$builder->add('post', HiddenEntityType::class, [
'class' => Post::class,
'data' => $post,
]);
Multiple entity managers. If your project uses several Doctrine managers, pick the right one explicitly; otherwise the default manager is used and lookups may fail:
$builder->add('tenant', HiddenEntityType::class, [
'class' => Tenant::class,
'manager' => 'tenant',
]);
Validate ownership, not just existence. The type only guarantees the ID resolves to an entity. In the controller (or a form event/constraint), assert the resolved entity is allowed for the current user:
if ($form->isSubmitted() && $form->isValid()) {
$comment = $form->getData();
if ($comment->getPost()->getAuthor() !== $this->getUser()) {
throw $this->createAccessDeniedException();
}
}
Combine with constraints. Since the type has no query filtering, add NotBlank/NotNull and a custom Callback or Choice-style constraint on the field to enforce membership rules.
Inject on PRE_SUBMIT. When the field isn't rendered at all (e.g., API-driven forms), add a listener to set the raw ID before transformation:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($post) {
$data = $event->getData();
$data['post'] = $post->getId();
$event->setData($data);
});
Keep it simple in collections. Each entry of a CollectionType can use HiddenEntityType, but watch for duplicate/blank IDs when entries are added dynamically.
TransformationFailedException on bad IDs. A deleted or non-existent ID surfaces as a form error on the field ("This value is not valid"). Check $form->get('post')->getErrors() when debugging, and make sure your error rendering covers hidden fields.null. If the underlying object has no entity and no data option, the hidden input renders empty; submitting it yields null. A non-nullable association will then fail validation before your controller runs, which can be confusing.class and manager, most EntityType options (query_builder, choice_label, multiple, expanded) are not supported. For multi-select or filtered choices, use EntityType with a hidden style, or handle it yourself.multiple is not supported. Don't try to bind an ArrayCollection through this type; you'll get a single entity or an error.HiddenEntityType and its transformer into your app and register it as a tagged form.type service — no framework magic is required.modelToView returns the identifier, viewToModel performs the repository lookup and throws TransformationFailedException when not found.dump($form->get('post')->getData()) after submit to confirm transformation; enable the profiler's Forms panel to see submitted vs. transformed data; verify the manager name matches a configured Doctrine manager; and check the entity's ID is accessible (not @internal or lazy-proxy-only) when modelToView runs.How can I help you explore Laravel packages today?