sulu/form-bundle
SuluFormBundle adds dynamic form creation to Sulu Admin. Content managers build and arrange fields in a grid, configure email notifications, and power contact/sweepstake forms. Built on the Symfony Form Component with theming support.
Installation:
composer require sulu/form-bundle
Ensure your project meets the requirements (PHP 8.2+, Symfony 6.4+, Sulu 3.0+).
Enable the Bundle:
Add to config/bundles.php:
return [
// ...
Sulu\Form\SuluFormBundle::class => ['all' => true],
];
Run Migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Generate a Form:
php bin/console sulu:form:generate
This creates a basic form structure in the Sulu Admin UI under Forms.
Admin UI Setup:
Text, Email, Submit) in the drag-and-drop editor.Frontend Integration: Embed the form in a Twig template:
{{ render(controller('SuluFormBundle:Form:render', {
'formId': 'your_form_id',
'action': path('sulu_form_submit', {'formId': 'your_form_id'})
})) }}
Handle Submissions: Extend the form handler to process submissions:
// config/services.yaml
Sulu\Form\Handler\FormHandlerInterface: '@App\Service\CustomFormHandler'
Field Configuration:
Text, Checkbox, Media).required, email) via the UI.Email Notifications:
{{ formData.name }} to dynamically populate emails.# config/packages/sulu_form.yaml
sulu_form:
sendinblue:
enabled: true
api_key: '%env(SENDINBLUE_API_KEY)%'
Form Submission Handling:
namespace App\Service;
use Sulu\Form\Handler\FormHandlerInterface;
use Sulu\Form\Handler\FormHandlerResult;
use Sulu\Form\Handler\FormHandlerResultInterface;
class CustomFormHandler implements FormHandlerInterface
{
public function handle(array $formData, string $formId): FormHandlerResultInterface
{
// Custom logic (e.g., save to database, trigger events)
return new FormHandlerResult(true, ['message' => 'Form submitted!']);
}
}
Frontend Rendering:
{% form_theme form _self %}
{{ form_row(form.field_name) }}
sulu_form_submit route with a CSRF token:
fetch('/form/submit', {
method: 'POST',
body: JSON.stringify({ formData, _csrf_token: '{{ csrf_token('sulu_form_submit') }}' }),
headers: { 'Content-Type': 'application/json' }
});
Media Fields:
Media field type to attach files/images.Localization:
Workflows:
# config/packages/sulu_workflow.yaml
sulu_workflow:
resources:
Sulu\Form\Rest\Resource\FormResource: ~
Testing:
generate-form command to create test forms:
php bin/console sulu:form:generate --name="Test Form" --locale="en"
$client = static::createClient();
$crawler = $client->request('GET', '/form/render');
$form = $crawler->selectButton('Submit')->form([
'formData[email]' => 'test@example.com',
]);
$client->submit($form);
CSRF Token Issues:
# config/packages/sulu_form.yaml
sulu_form:
csrf_protection:
disabled: true
Field Validation:
Hidden) and spacers (Spacer) ignore the required constraint by default.Constraints.Media Uploads:
MediaManagerInterface is properly configured in your services.yaml:
Sulu\Form\Handler\FormHandlerInterface:
arguments:
$mediaManager: '@sulu_media.media_manager'
Locale Fallbacks:
php bin/console debug:translation sulu_form
Form Submission Errors:
FormHandlerResult for errors:
$result = $formHandler->handle($formData, $formId);
if (!$result->isSuccess()) {
throw new \RuntimeException($result->getMessage());
}
config/packages/dev/sulu_form.yaml:
sulu_form:
debug: true
Database Issues:
php bin/console doctrine:migrations:status
php bin/console cache:clear
Sendinblue Integration:
sulu_form:
sendinblue:
pagination:
limit: 100
sulu_form.sendinblue.contact_created event:
$eventDispatcher->addListener(
'sulu_form.sendinblue.contact_created',
function ($event) {
// Log or debug the event data
}
);
Custom Form Types:
Sulu\Form\Type\AbstractType:
namespace App\Form\Type;
use Sulu\Form\Type\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CustomFieldType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('custom_field', TextType::class);
}
public function getBlockPrefix(): string
{
return 'app_custom_field';
}
}
resources/config/sulu_form.yaml:
sulu_form:
types:
app_custom_field: App\Form\Type\CustomFieldType
Event Listeners:
namespace App\EventListener;
use Sulu\Form\Event\FormSubmittedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class FormSubmittedListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
FormSubmittedEvent::NAME => 'onFormSubmitted',
];
}
public function onFormSubmitted(FormSubmittedEvent $event)
{
// Handle submission (e.g., log, notify)
}
}
Twig Extensions:
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class FormExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('format_form_data', [$this, 'formatData']),
];
}
public function formatData(array $data): string
{
return json_encode($data, JSON_PRETTY_PRINT);
}
}
config/packages/twig.yaml:
twig:
extensions:
- App\Twig\Form
How can I help you explore Laravel packages today?