c975l/contactform-bundle

Bundle to manage simple contact form

Maintainers

Package info

github.com/975L/ContactFormBundle

Type:symfony-bundle

pkg:composer/c975l/contactform-bundle

Statistics

Installs: 852

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0


README

Symfony bundle that provides a fully-featured contact form with built-in spam protection, reCaptcha v3, rate limiting, event-driven customization, and multilingual support.

GitHub Packagist Version PHP Version

Features

  • Contact form at /contact (or /{_locale}/contact for multilingual apps)
  • Pre-fills name and email when a user is logged in
  • Sends emails via Symfony Mailer (TemplatedEmail)
  • Dispatches events to customize form behavior and email content
  • Anti-spam: dynamic honeypot with randomized field names and labels per session
  • Anti-spam: minimum submission delay check to reject bot submissions
  • Anti-spam: reCaptcha v3 via karser/KarserRecaptcha3Bundle
  • Rate limiting: optional limits by IP and by email address
  • GDPR consent checkbox (configurable)
  • Optional "receive a copy" checkbox for the sender
  • Subject pre-fill via URL parameter (?s=My+Subject)
  • Configuration managed via c975L/ConfigBundle

Requirements

Installation

Download

composer require c975l/contactform-bundle

Enable routes

Add the following to config/routes.yaml:

c975_l_contact_form:
    resource: "@c975LContactFormBundle/"
    type: attribute
    prefix: /
    # For multilingual websites:
    # prefix: /{_locale}
    # defaults: { _locale: '%locale%' }
    # requirements:
    #     _locale: en|fr|es

Load configuration values

php bin/console c975l:config:load-all

Then use the ConfigBundle dashboard to set the values for each key.

Configure reCaptcha v3

Create your keys on Google reCaptcha and set them in your .env.local:

RECAPTCHA3_KEY=your_site_key
RECAPTCHA3_SECRET=your_secret_key

Or store them via the ConfigBundle dashboard (recaptcha3-site-key and recaptcha3-secret-key).

Override the layout template

Create templates/bundles/c975LContactFormBundle/layout.html.twig and extend your own layout:

{% extends 'layout.html.twig' %}

{% set title = 'Contact' %}

{% block content %}
    {% block contactform_content %}
    {% endblock %}
{% endblock %}

The email templates are loaded from SiteBundle. Override them in templates/c975LSiteBundle/emails/.

Usage

The route name is contactform_display. Link to it from Twig:

{{ path('contactform_display') }}

Pre-filling the subject

Pass the s query parameter to pre-fill the subject field (rendered as read-only):

https://example.com/contact?s=My+Subject

Rate limiting (optional)

If the following Symfony RateLimiter services are defined, they are automatically applied before any email is sent:

  • limiter.contact_form_by_ip
  • limiter.contact_form_by_email

Example (config/packages/rate_limiter.yaml):

framework:
    rate_limiter:
        contact_form_by_ip:
            policy: sliding_window
            limit: 5
            interval: '10 minutes'
        contact_form_by_email:
            policy: sliding_window
            limit: 3
            interval: '10 minutes'

Honeypot and CSP

If you have disabled unsafe-inline for style-src in your Content Security Policy, add this rule to keep the honeypot hidden:

.sr-only {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

Events

Two events allow customization without modifying the bundle:

Constant Event name Fired when
ContactFormEvent::CREATE_FORM c975l_contactform.create.form The form is being built
ContactFormEvent::SEND_FORM c975l_contactform.send.form The form has been submitted and validated

Example: customize email on submission

namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use c975L\ContactFormBundle\Event\ContactFormEvent;

class ContactFormSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            ContactFormEvent::SEND_FORM => 'onSendForm',
        ];
    }

    public function onSendForm(ContactFormEvent $event): void
    {
        $subject = $event->getFormData()->getSubject();

        if (str_contains((string) $subject, 'some-keyword')) {
            $event->setEmailData([
                'subject'   => 'Custom email subject',
                'bodyEmail' => 'emails/custom_contact.html.twig',
                'bodyData'  => [],
            ]);

            // Or abort sending with an error code:
            // $event->setError('error.user_not_found');
        }
    }
}

Override the redirect URL after submission

public function onCreateForm(ContactFormEvent $event): void
{
    $event->getRequest()->getSession()->set('redirectUrl', 'https://example.com/thank-you');
}

If this bundle saves you development time, consider sponsoring via the Sponsor button at the top of the repository. Thank you!