meniam/ckeditor-bundle
A Symfony bundle for integrating CKEditor into your application. It packages the editor assets and provides bundle-level configuration so you can add rich text editing to forms and templates with minimal setup.
The first step is confirming whether you have a Symfony 2 app at all. In a Laravel codebase, composer require meniam/ckeditor-bundle will fetch files onto disk and nothing more. There is no service provider, and the composer.json has no laravel entry under extra, so dispatch of PackageManifest discovers nothing to boot. If you try to new \Meniam\CKEditorBundle\CKEditorBundle() anywhere, it fails on Symfony\Component\HttpKernel\Bundle\Bundle — a class Laravel does not provide. There is no first use case to demonstrate, because the package's entire API surface is Symfony-shaped: a bundle class, a DependencyInjection\Extension, a form type registered against symfony/form, and Twig form-theme blocks under Resources/views/Form/.
If you genuinely have a Symfony 2 app already on this bundle, where to look first:
app/AppKernel.php — register new Meniam\CKEditorBundle\CKEditorBundle() in the bundles array. This is the boot point.app/config/config.yml — the bundle exposes a config tree under meniam_ck_editor: (asset path, toolbar, height, uiColor, filebrowser* paths). This is where per-environment editor settings live.DependencyInjection/Configuration.php — the authoritative list of every knob the bundle accepts. Not the README; the config tree is ground truth.Form/Type/CKEditorType.php — the form type. This is what you actually touch day-to-day; it renders a <textarea> and attaches CKEditor on DOMContentLoaded via the configured asset.Resources/views/Form/* — the Twig theme blocks. If you need to override markup, this is where you copy from.The first useful integration on Symfony 2 is registering a rich-text field in an existing form:
$builder->add('body', CKEditorType::class, [
'config' => ['toolbar' => 'Basic', 'height' => 300],
]);
Then ensure the bundle's form resources are registered with Twig in config.yml under twig.form.resources, or the field renders as a bare <textarea>.
For a Laravel codebase, the honest starting step is an npm install of CKEditor 5 (or a Tiptap component) and a Blade partial, not a Composer require. That is the actual day-to-day work this package cannot do for you.
Symfony 2, form-centric (the pattern this package was designed for). The dominant workflow is form-type-first: never emit <script> tags in templates, let CKEditorType own the editor lifecycle. Editors are per-field and configured through the form builder, which keeps editor config close to the field it applies to and makes it overrideable per form. This is the only pattern the bundle supports cleanly.
Symfony 2, template-driven (avoid). Some teams bypass the form type and drop the bundle's assets manually into a Twig template to attach CKEditor to an arbitrary element. This works — the bundle ships assets — but you lose the form-type contract, the config resolution, and the upgrade path. If you find yourself doing this, you have already outgrown the bundle.
Shared configuration via bundle config. For multi-form consistency (one toolbar for "article body," one for "short excerpt"), centralize the toolbar set in config.yml and reference the profile by name from each form type's config array. Duplicating toolbar config across forms is the most common drift source in Symfony 2 CKEditor integrations.
Laravel pattern that actually ships. A Blade component wrapping the <textarea> plus a @push('scripts') initialization:
{{-- resources/views/components/richtext.blade.php --}}
<textarea name="{{ $name }}" id="{{ $id }}" data-toolbar="{{ $toolbar ?? 'default' }}">
{{ old($name, $value) }}
</textarea>
@push('scripts')
<script type="module">
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Essentials } from '@ckeditor/ckeditor5-essentials';
// build + init against #{{ $id }}
</script>
@endpush
Three things this pattern buys you that the bundle cannot: it composes with old(), it survives form validation redisplay, and it works under Vite without Assetic path guessing.
Integration tips that apply to either stack.
EventListener on the entity save or a form PRE_SUBMIT transformer. In Laravel, a form request or model mutator running HTMLPurifier (mews/purifier). Treat this as a separate, mandatory piece of work — no editor package provides it.|raw) or {!! !!} in Blade, never through the escaped path. This is where stored XSS lives if sanitization is skipped upstream.filebrowserUploadRoute config and any Laravel equivalent just hand a URL to the editor. Auth, validation, MIME sniffing, storage disk, and quota are your controller's job in both stacks.<textarea> fallback. Progressive rollout, no-JS support, and a clean rollback if the editor misbehaves in a specific browser.Composer resolution will likely fail on a modern Laravel. The bundle pins symfony/framework-bundle and related components at ~2.x/3.x era constraints. Laravel 9–11 resolves those at 6.x/7.x. composer require will produce a conflict; --ignore-platform-reqs or aliasing forces an EOL dependency graph into production. Do not force it. A dependency conflict here is the package telling you the truth.
Package discovery silently succeeds while doing nothing. Laravel prints a "discovered" line if a package has a service provider under extra.laravel. This bundle does not, so there is no discovery line — but it will not error at install time either. The failure only surfaces when you try to use it, which makes it deceptively easy to leave in composer.json as dead weight.
Assetic paths have no runtime under Vite or Mix. The bundle's asset resolution assumes Assetic (assetic.assets entries, {% stylesheets %} tags). Under a modern asset pipeline those paths do not exist. If you port the bundle's Twig templates into Blade and copy the asset URL literals, you get 404s in production. Rebuild the asset reference against your manifest or CDN.
CKEditor 4 is end-of-life. The last release of this bundle (January 2019) targets CKEditor 4, which reached EOL in mid-2023. There is no upgrade path through the bundle to CKEditor 5. If you need to swap to CKEditor 5, you are redoing the integration from scratch anyway — which argues for doing that directly the first time.
The config tree is the documentation. The README and description.md say "configurable editor settings" but do not enumerate them. If you are stuck on a Symfony 2 install, read DependencyInjection/Configuration.php; every valid key is declared there with its default. Guessing at a key from the README is wasted time.
Twig form theme registration is the #1 "why is my editor a plain textarea" bug. On Symfony 2, CKEditorType renders only if the bundle's form theme is registered under twig.form.resources — either app-wide in config.yml or per-template via {% form_theme form 'MeniamCKEditorBundle:Form:ckeditor.html.twig' %}. There is no warning if it is missing; you just get a <textarea> with no editor attached.
There is no community to escalate to. One star, zero dependents, single maintainer, no release since 2019. Stack Overflow and package docs will not help; the config tree and the form type source are your only references. Budget accordingly — reverse-engineering Symfony 2 idioms is slower than writing a Blade partial from scratch.
Server-side sanitization is non-negotiable and belongs outside the editor choice. Even if you eventually pick CKEditor 5, Tiptap, TinyMCE, or Trix, the stored-XSS risk lives in what you persist and re-render. Own it in one place — a form request, mutator, or event listener — with tests that assert scripts and event-handler attributes are stripped. That work is identical regardless of which editor you land on, so do not let the editor decision block it.
The one legitimate use of this repository as a Laravel developer is as a reference. Reading Form/Type/CKEditorType.php and its Twig theme block tells you what a "good" rich-text form type looks like in a framework that has a form component. Then write the 30–50 line Blade equivalent, wrap it in a component, and move on.
How can I help you explore Laravel packages today?