toinou/summernote-bundle
A Symfony bundle for integrating the Summernote WYSIWYG editor into your applications, providing a convenient way to add rich-text HTML editing and bundle configuration to Symfony projects.
Treat this as a thin, unmaintained asset/form glue bundle rather than a full editor platform. The README on the repo is the only reliable source of truth for class names and config keys — read it before anything else, because the package has no dependents and no downstream examples to crib from.
composer require toinou/summernote-bundle
// app/AppKernel.php
$bundles = [
// ...
new Toinou\SummernoteBundle\SummernoteBundle(),
];
ls vendor/toinou/summernote-bundle
grep -r "namespace" vendor/toinou/summernote-bundle --include=*.php | head
cat vendor/toinou/summernote-bundle/README.md
Find the two integration points. Almost every Symfony editor bundle exposes exactly one of these, often both:
SummernoteType) that renders a <textarea> plus the JS init;textarea widget.First use case. Take an existing text/textarea field (a CMS Body or a Post::content), swap the widget for the bundle's type, and confirm the editor loads. That single change is the whole value proposition of the bundle — everything else (uploads, sanitization, custom toolbars) is work you own.
If the bundle exposes nothing usable beyond a CDN <script> tag, stop and vendor Summernote directly via Encore; you will save time.
Form-type substitution. The intended workflow is a drop-in widget swap, keeping your entity and validator untouched:
$builder->add('content', SummernoteType::class, [
'required' => false,
'attr' => ['rows' => 12],
]);
Keep the data contract boring. Summernote submits HTML. Store it in a TEXT/LONGTEXT column, never in a VARCHAR(255), and do not add a strip_tags constraint — it will silently mangle legitimate markup. Instead put sanitization in a listener or a setter so the DB always holds clean HTML:
public function setContent(?string $html): self
{
$this->content = $this->purifier->purify((string) $html); // e.g. ezyang/htmlpurifier
return $this;
}
Rendering side. {{ post.content|raw }} is required, which makes server-side purification non-optional. Do it on write, not on read, so cached templates and API consumers all get the same safe output.
Asset wiring. Symfony 3-era bundles usually assume Assetic and jQuery already loaded. If you are on Webpack Encore, ignore the bundle's asset helper entirely and load Summernote yourself:
require('summernote/dist/summernote-bundle.css');
require('summernote');
$('.summernote').summernote({ height: 300, toolbar: [['style', ['bold', 'italic']], ['insert', ['link', 'picture']]] });
Uploads. If you enable insertImage with a custom onImageUpload, point it at your own controller with a CSRF token and a mime/size whitelist. Never trust the bundle's default handler path if one exists — it predates modern upload hardening.
Config. Any bundle config lives under toinou_summernote: (verify the key with app/console config:dump-reference summernote). Keep only global defaults there — toolbar variants belong in the template/JS, where editors differ per screen.
AppKernel, Resources/views, and possibly Assetic idioms. It will not install cleanly on Symfony 5/6 without a fork.DependencyInjection/Configuration.php and Resources/config/services.yml first — they tell you the real public surface faster than the README.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), or you get the classic summernote is not a function.summernote-bs4 vs default builds differ in popover styling; a BS3 bundle skin on a BS4 page produces invisible dropdowns. Match the build to your theme.if (!$el.next('.note-editor').length) or destroy on teardown.<textarea> state in some versions; assert the hidden field value in tests rather than the visible editor DOM.app/console debug:container --tag=form.type | grep -i summernote to confirm the form type is registered, and app/console debug:twig to find the form theme path. If the editor renders unstyled, the CSS never loaded — check the network tab before touching PHP.app/Resources/views/Form/) and JS options passed via attr. Anything more invasive means forking.How can I help you explore Laravel packages today?