tousleshoraires/contact-bundle
tousleshoraires/contact-bundle is a PHP bundle for adding a contact form to your application. It handles form submission, validation, and contact-message storage, helping you collect and manage enquiries with minimal setup and configuration. Designed for quick integration into existing projects.
This is a Symfony bundle (tousleshoraires/contact-bundle), not a Laravel package — that distinction drives everything below. Version 3.0.1 is a patch release on the 3.x line; if you're on ^3.0 you'll pick it up on the next composer update, and it only touches Configuration.php (the dependency-injection config tree), so treat it as a low-risk config-surface change rather than a feature drop.
Minimal steps to evaluate it:
composer require tousleshoraires/contact-bundle:^3.0 in a Symfony app (or a throwaway Symfony skeleton if you're a Laravel dev sizing it up).config/bundles.php.src/DependencyInjection/Configuration.php first. It is the contract: it tells you every option (recipient address, sender, template overrides, entity class override, etc.) before you read a single controller.config/packages/tousleshoraires_contact.yaml block, run php bin/console config:dump-reference <alias> to confirm the tree, then hit the bundle's contact route.First use case to validate: wire the bundled form into a page, submit it, and confirm both persistence and the notification email arrive (use a local mail catcher / MAILER_DSN pointed at Mailpit or null://). That single flow exercises config, routing, Doctrine, the form type, and the mailer in one pass.
If you're actually working in a Laravel app, don't expect composer require to "just work" — see Implementation Patterns for the realistic integration routes.
Config-first setup. Almost all behaviour is toggled through the bundle's config block (the tree in Configuration.php) rather than by editing bundle source. Keep your overrides in config/packages/tousleshoraires_contact.yaml and commit them; that's the file you'll diff against future releases.
Mount, don't fork. Render the bundled form type in your own template or via a fragment/sub-request rather than copying the controller. This survives patch/minor upgrades and keeps your custom layout logic in your app.
Override by convention. Symfony resolves template overrides at templates/bundles/<BundleName>/... and lets you decorate services. Use those extension points before subclassing: template override → service decoration → compiler pass → subclass. Only fork the entity/form type when you genuinely need schema or field changes.
Event/listener hook for side effects. Route post-submit work (Slack ping, CRM push, spam scoring) through a listener/subscriber on whatever event the bundle dispatches after a message is created, instead of editing the controller. Keeps the "send to inbox" path intact.
Route hygiene. Put the bundle's contact route behind your own prefix and, if the form is API/JSON-facing, disable CSRF for that route only. Prefer attributing the route in your app over relying on the bundle's default path if you already have a /contact.
Testing. Functional-test the submitted form end-to-end: post to the route, assert the entity row landed, and assert the mailer via Symfony's test transport (assertEmailCount, assertEmailAddressContains). This catches config regressions faster than manual clicking.
Laravel-side integration options. Since this is a Symfony bundle:
POST /contact JSON endpoint, and call it from Laravel via Http::post(...). Clean boundaries, no framework leakage.DependencyInjection, Form, Doctrine) won't transfer.ServiceProvider, no config/contact.php, and no auto-discovery.Configuration.php. Config-tree edits are exactly where a "patch" release can still change runtime behaviour: renamed nodes, tightened validation, or changed defaults (e.g., a default recipient or template path) can silently alter what the form does. After upgrading, run cache:clear, then config:dump-reference and debug:config <alias> and diff defaults against what you had pinned. Pin ^3.0 and re-verify config after any 3.x bump, not just minors.bin/console cache:clear before debugging config.schema:update run blind.symfony/mailer transport. In dev, point MAILER_DSN at a catcher; failed sends usually surface as swallowed exceptions in the request cycle, so check var/log and use the test transport in CI./contact route or a global CSRF setting applied to an API call are the two most common "it 500s / 419s" causes. Check debug:router to confirm which route actually wins.debug:container and debug:router are your first stop when the bundle appears installed but nothing works — usually a missing bundle registration or a config alias typo.Decorator / decorates:) → event subscriber → compiler pass → subclass. Reaching for subclassing first is what makes future upgrades painful.Configuration.php nodes you actually use; that's the only part of a 3.x-to-3.x bump that realistically bites you.How can I help you explore Laravel packages today?