Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Contact Bundle Laravel Package

kphoen/contact-bundle

kphoen/contact-bundle is a lightweight Symfony bundle for adding a contact form to your application. It provides the form and basic message-handling workflow, making it easy to collect inquiries and integrate contact requests into an existing Symfony project with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a framing note that matters more than any setup step: this is a Symfony bundle, not a Laravel package. There is no service provider, no config/contact.php, no facade. If you're coming from Laravel, read every "register the bundle" step below as the Symfony equivalent of composer require + auto-discovery, and expect to do the wiring by hand.

The package is also archived (last release January 2016, 7 stars, zero dependents). Treat it as reference source code you may vendor, not as a dependency you can safely composer require into a modern app.

Minimal path, assuming a Symfony 2.8/3.x-era skeleton it was built for:

composer require kphoen/contact-bundle
// app/AppKernel.php
$bundles = [
    // ...
    new KPhoen\ContactBundle\KPhoenContactBundle(),
];
# app/config/config.yml
k_phoen_contact:
    recipient: [email protected]
    sender: [email protected]
# app/config/routing.yml
k_phoen_contact:
    resource: "@KPhoenContactBundle/Resources/config/routing.yml"
    prefix: /contact

Then create the table its message entity maps to (doctrine:schema:update --force, or a hand-written migration — see Gotchas) and hit /contact.

Where to look first, in order:

  1. README.md — it is the only documentation, and it is short enough that skimming it beats guessing.
  2. DependencyInjection/Configuration.php — the authoritative config tree. Don't trust blog snippets; the keys (recipient, sender, template name, whether messages are persisted) are defined here and nowhere else.
  3. Resources/config/routing.yml and Controller/ — to see whether a route is actually shipped or whether you're expected to write the controller.
  4. Form/Type/ContactType.php — the fields you get for free. This is the file you'll end up copying into your own codebase.
  5. Manager/ and Entity/ — the persistence and mail side, typically a ContactMessage entity plus a manager service that saves and sends.

First use case: a working "Contact us" page with name/email/subject/message, an email to a fixed recipient, and the message stored in a contact_message table. That's the whole product. Budget an afternoon to confirm it works, and an hour to decide you'd rather reimplement it — the bundle is small enough that reimplementing is often cheaper than integrating.

If you want the same outcome in Laravel, the honest translation is: a ContactMessage model + migration, a StoreContactRequest Form Request for validation, a ContactController@store, and a ContactSubmitted Mailable. That is roughly the entire bundle, expressed idiomatically. The rest of this document describes what the bundle gives you and where it will hurt.

Implementation Patterns

Pattern 1: Use it as shipped (fastest, least flexible)

Register, configure, import routes, done. This works when you want the default form, the default template, and a single hardcoded recipient. You get no spam protection, no rate limiting, and no admin UI — the bundle persists messages but does not provide a listing screen.

Pattern 2: Write your own controller, reuse the manager

This is what most real integrations end up doing. Keep the bundle registered for its services and entity, but own the routing:

// src/AppBundle/Controller/ContactController.php
public function contactAction(Request $request)
{
    $form = $this->createForm(ContactType::class);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $this->get('kphoen_contact.manager')->handle($form->getData());

        return $this->redirectToRoute('contact_thanks');
    }

    return $this->render('contact/contact.html.twig', ['form' => $form->createView()]);
}

Confirm the service id before relying on it:

bin/console debug:container | grep -i contact

If the manager's public API doesn't fit (it likely expects its own ContactMessage model rather than an array), stop here and move to Pattern 3.

Pattern 3: Lift the classes into your app

Copy Form/Type/ContactType.php, the message entity, and the manager's send/persist logic into src/. Delete the bundle. You keep the parts you want (field definitions, a working template) and gain the ability to:

  • swap SwiftMailer for Symfony\Component\Mailer or Laravel's Mail facade;
  • add a company, phone, or budget field without fighting a vendor form;
  • attach the message to whatever admin or notification flow you already have.

For a Laravel developer this is the natural move: the code is a few hundred lines, and the integration cost of an archived bundle usually exceeds the porting cost.

Pattern 4: Override the form via a form type extension

If you must keep the vendor form, add fields non-invasively:

// src/AppBundle/Form/Extension/ContactTypeExtension.php
class ContactTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('company', TextType::class, ['required' => false]);
    }

    public function getExtendedType()
    {
        return ContactType::class;
    }
}

Register with the form.type_extension tag. This survives bundle updates better than overriding the service definition, but note that extra fields won't be persisted or emailed unless the underlying model supports them — so in practice you're back to Pattern 3.

Pattern 5: Template overrides

Override only the Twig view, keeping bundle logic:

# Symfony 2.x
app/Resources/KPhoenContactBundle/views/Contact/contact.html.twig

# Symfony 3.4+/4.x
templates/bundles/KPhoenContactBundle/Contact/contact.html.twig

Check the actual path by running bin/console debug:twig | grep -i contact — archived bundles are inconsistent about directory casing (Contact vs contact), and casing bugs are the single most common "why is my override ignored" failure here.

Pattern 6: Wire submission into your existing pipeline

Rather than letting the bundle send mail inline, decorate the manager and dispatch your own event or push onto a queue:

class QueuedContactManager implements ContactManagerInterface
{
    public function __construct(
        private ContactManagerInterface $inner,
        private MessageBusInterface $bus
    ) {}

    public function handle($message)
    {
        $this->inner->persist($message);
        $this->bus->dispatch(new SendContactNotification($message));
    }
}

Alias the bundle's service id to your decorator in services.yml. This is the cleanest extension point the bundle offers, because it doesn't require touching its form or entity.

Integration tips

  • Keep the recipient in config, not in code, so staging mail doesn't reach real inboxes.
  • Configure SwiftMailer's spool (memory in dev, a queue in prod) so a slow or failing SMTP server doesn't turn your contact form into a 30-second page load.
  • If you already have a messages or enquiries table, don't let the bundle create a second one — remap the entity or drop persistence entirely and just send mail.
  • For Laravel parity: the bundle's manager is the equivalent of a queued Mailable plus an Eloquent create; its form type is a FormRequest + Blade form. Keep that mapping in mind when deciding what to keep.

Gotchas and Tips

It is archived, and the stack it targets is dead. 2016 means Symfony 2.x/3.0, PHP 5.5–7.0, and SwiftMailer. SwiftMailer was abandoned in favour of symfony/mailer; SwiftMailerBundle is incompatible with Symfony 5+. Doctrine's EntityManager API, form type signatures (getExtendedType), and getBlockPrefix naming all changed since. Installing this into a Symfony 6/7 app will not work; installing it into Laravel is not a thing. The realistic options are "vendor the source" or "rewrite the 300 lines."

The bundle ships a Doctrine entity — this is the sharpest edge. Entities defined inside a bundle (@KPhoenContactBundle/Entity/ContactMessage) cannot be extended the way application entities can. If you need to add a status, ip, or assigned_to column, you either edit vendor code or map the bundle entity as a mapped superclass and subclass it — which requires the bundle to have declared it as MappedSuperclass in the first place. Verify with the class annotations before planning around it. Also, doctrine:schema:update will create the table for you, but the bundle predates the modern migration workflow; write the migration by hand.

No spam protection whatsoever. There is no CAPTCHA, no honeypot, no rate limiting, no Akismet hook. A public form on this bundle is a spambot target within days. Minimum viable mitigation: honeypot field plus a timestamp check in a form event listener, plus per-IP rate limiting via your web server or Symfony's RateLimiter (which didn't exist in 2016). Do not deploy without this.

Route names and prefixes are not namespaced defensively. Importing the bundle's routing with a prefix is usually fine, but hardcoded route names in its templates (contact, contact_send) can collide with your app's routes. Grep Resources/ for path( and redirectToRoute before importing, and prefer Pattern 2 (your own route, prefixed explicitly) if you have an existing /contact.

Mail failures surface as a 500 on the request that submitted the form. The default behaviour sends synchronously. Set swiftmailer.spool.type: memory in dev, and in production use a real spool or replace the sending with a message bus dispatch. This is the most common production incident with bundles of this vintage.

Config key is k_phoen_contact, derived from the extension alias, not the bundle class name. Getting this wrong yields a silently ignored config block (Symfony 2/3 did not warn consistently about unknown root keys). Confirm by running bin/console config:dump-reference KPhoenContactBundle — if that errors, check getAlias() in DependencyInjection/KPhoenContactExtension.php.

Debugging checklist when the form "does nothing":

  1. bin/console debug:router | grep contact — is the route even registered?
  2. bin/console debug:container | grep -i contact — is the manager service public/available?
  3. bin/console debug:twig | grep -i contact — is your template override in the right casing/path?
  4. Mailer profiler panel (dev) — was a message actually sent, or silently dropped by the spool?
  5. Check var/logs//var/log/ — form validation failures are silent in the UI and only visible there.

PII in the database. It stores every submission, including names, emails, and message bodies, with no retention policy and no admin UI to delete them. If you keep persistence, add a purge command. If you don't need persistence, remove the entity mapping and keep only the email — that also removes the schema-update problem entirely.

Extension points that actually exist (given the code size, they're limited): service decoration of the manager, form.type_extension on the contact form type, Twig bundle overrides, and config-driven recipient/sender/template. There are no events documented and probably no dispatcher in the manager — check before designing around an event hook that isn't there.

Opportunity note. With zero dependents, a 2016 release, and an "opportunity" score near the top of the scale, this is a package nobody is maintaining and everybody would have to rewrite. If you're evaluating it seriously, the right output of that evaluation is a short internal snippet — a modern Symfony form + notifier, or a Laravel Mailable + model + FormRequest — not a dependency.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels