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

Form Bundle Laravel Package

folliked/form-bundle

A Laravel form bundle for defining, validating and rendering forms from a single configuration. Build reusable fields, rules and layouts, then output consistent forms across your PHP application with less boilerplate and easier customization.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle predates Symfony Flex and the last tagged release is from June 2020, so treat the first hour as an archaeology exercise rather than a normal composer require.

1. Install and pin

composer require folliked/form-bundle
# If it resolves against an old Symfony, pin explicitly:
composer require "folliked/form-bundle:^1.0" --with-dependencies

Check composer why-not folliked/form-bundle and the package's composer.json constraints before you fight the resolver. If it only allows Symfony 2/3, either run it in a legacy app or fork/vendor it.

2. Register the bundle

Symfony 4+ (config/bundles.php):

return [
    // ...
    Folliked\SHFormBundle\FollikedSHFormBundle::class => ['all' => true],
];

Legacy (app/AppKernel.php):

$bundles = [
    // ...
    new Folliked\SHFormBundle\FollikedSHFormBundle(),
];

Confirm the exact FQCN from vendor/folliked/form-bundle/ — with 0 stars and no docs, the README and the bundle class are your source of truth.

3. Configure keys and defaults

Add a config file (name varies by bundle; check for Configuration.php in DependencyInjection/). Typical shape:

# config/packages/sh_form.yaml
sh_form:
    recaptcha:
        public_key: '%env(RECAPTCHA_PUBLIC_KEY)%'
        private_key: '%env(RECAPTCHA_PRIVATE_KEY)%'
    captcha:
        width: 200
        height: 60

4. Wire the front-end assets once, in your base layout

These types are jQuery/jQuery-UI/TinyMCE-driven and do not ship a working asset pipeline for modern Symfony. Load them yourself, in order:

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js"></script>

First use case: a contact form with reCAPTCHA + TinyMCE

use Folliked\SHFormBundle\Form\Type\RecaptchaType;
use Folliked\SHFormBundle\Form\Type\TinymceType;

$builder
    ->add('name', TextType::class)
    ->add('message', TinymceType::class)
    ->add('recaptcha', RecaptchaType::class);

Render, submit, and confirm the validator actually fires. That single form exercises the config, the asset loading, and the server-side verification path — the three things that break first.

Implementation Patterns

Treat each type as a thin HTML/JS decorator, not a black box. The value-add here is rendering (captcha_gd image tags, TinyMCE init, jQuery UI widgets). Validation semantics for everything except captcha/reCAPTCHA are typically delegated to your own constraints.

Standard form usage

$builder->add('publishedAt', JqueryDateType::class, [
    'widget' => 'single_text',
    'attr'   => ['class' => 'js-datepicker'],
]);

$builder->add('priority', JquerySliderType::class, [
    'attr' => ['min' => 0, 'max' => 100, 'step' => 5],
]);

$builder->add('tags', JqueryAutocompleteType::class, [
    'route' => 'app_tag_autocomplete', // confirm option name in the type's configureOptions()
]);

Autocomplete needs an endpoint returning JSON. Keep it a lightweight controller, cap results, and filter server-side:

#[Route('/tags/autocomplete', name: 'app_tag_autocomplete')]
public function tags(Request $request): JsonResponse
{
    $q = trim((string) $request->query->get('term', ''));
    if (mb_strlen($q) < 2) {
        return $this->json([]);
    }

    return $this->json($this->tagRepo->search($q, 10));
}

File and image uploads — JqueryFileType/JqueryImageType handle the client-side picker/preview, but the move-and-store step is still yours:

$file = $form->get('attachment')->getData();
if ($file) {
    $name = bin2hex(random_bytes(8)).'.'.$file->guessExtension();
    $file->move($this->getParameter('uploads_dir'), $name);
    $entity->setAttachment($name);
}

Add File/Image constraints to the underlying field rather than trusting the widget. Store the filename, not the absolute path.

Captcha GD flow (session-backed)

// controller
#[Route('/captcha/refresh', name: 'app_captcha_refresh')]
public function captcha(): Response { /* delegate to the bundle's captcha controller/service */ }
{{ form_row(form.captcha) }}
<a href="#" id="refresh-captcha">New code</a>

The value is validated against the session, so the session must be started and the form must round-trip through the same session. Don't cache pages containing it.

reCAPTCHA is the one type with meaningful server-side verification. Keep keys in env vars, and verify in the form's validator config or via the bundle's constraint. If the bundle's verification path is broken against modern Google endpoints, do the verification yourself in the controller — it's ~10 lines with HttpClient.

Compose, don't modify. If you need consistent defaults across the app (e.g. every date field uses the same jQuery UI options), create your own type that extends the bundle's and set defaults in configureOptions():

class AppDateType extends JqueryDateType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        parent::configureOptions($resolver);
        $resolver->setDefault('attr', ['class' => 'js-datepicker', 'autocomplete' => 'off']);
    }
}

Testing. These are plain form types; test them with TypeTestCase and assert the produced form view. That's the fastest way to catch breakage after a Symfony upgrade:

protected function getExtensions(): array
{
    return [new PreloadedExtension([new RecaptchaType()], [])];
}

Gotchas and Tips

  • Abandoned since 2020, 0 stars, 0 dependents. Budget for it being a liability. Read every PHP file before shipping to production; the bundle is small enough to audit in under an hour. Fork it into your own namespace if you need patches — you won't get upstream fixes.
  • Symfony API drift is the #1 breakage. Old bundles still implement setDefaultOptions() (removed in Symfony 3) and use getName() on the type. Expect to patch or shim these. Run bin/console debug:form to see whether the types register at all.
  • Asset versions are the #2 breakage. jQuery UI 1.12 widgets and TinyMCE 4/5 init syntax differ from modern versions. If the bundle emits tinymce.init({...}) with TinyMCE 4 options, loading TinyMCE 6 will silently do nothing. Pin the CDN versions to what the bundle expects, or override the templates.
  • Template overrides are your main extension point. Find the Resources/views/Form/*.html.twig blocks and override them in templates/bundles/.... That's how you fix asset markup, ARIA attributes, and broken JS without forking.
  • Session/captcha pitfalls: captcha breaks behind full-page caching, in API contexts, and with stateless firewalls. For SPAs, this type is effectively unusable — move to reCAPTCHA v3 or hCaptcha.
  • Debugging JS widgets: the rendered hidden inputs are what actually submit. If validation fails with "This value is not valid" on a date/slider/autocomplete, dump $form->getData() and inspect the raw request payload — the widget isn't writing the expected format, usually a jQuery UI date format mismatch (dd/mm/yy vs Y-m-d).
  • Security: TinyMCE output is raw HTML — sanitize on render with HTMLPurifier or a strict Twig |raw policy. Captcha GD is trivially OCR-able; treat it as spam friction, not security. Never commit reCAPTCHA private keys.
  • Config quirks: bundle config trees from this era often require all keys to be present or fail with "Unrecognized option". Read DependencyInjection/Configuration.php and supply a complete block rather than partial overrides.
  • Migration path: if you're only using one or two types, don't adopt the bundle. symfony/ux-tinymce, symfony/ux-autocomplete, the built-in DateType with single_text, and a small custom captcha service cover the same ground with maintained dependencies. Reserve this bundle for legacy applications where it's already installed — for greenfield, the maintenance risk substantially outweighs the convenience.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core