locaine/lcn-wysihtml5-bundle
LCN WysiHTML5 Bundle integrates the wysihtml5 rich-text editor into Laravel/PHP applications, providing a lightweight WYSIWYG field for content forms. It packages editor assets and helpers to simplify setup, configuration, and use in views.
Architecture fit — wrong framework, not a weak fit. The package is a Symfony2 bundle, not a Laravel package. It ships a Symfony FormType extending Symfony\Component\Form\AbstractType, a DI container extension loaded through AppKernel::registerBundles(), Twig form themes, and Assetic-era asset publishing. Laravel's rendering path is Blade plus FormRequest validation; there is no Symfony Form component, no bundle registration, no Twig. Nothing in the code is reachable from a Laravel request without reimplementation. The portable asset is the design: a constrained client-side editor paired with mandatory server-side HTMLPurifier allow-list sanitization.
Integration feasibility — zero without a rewrite. Composer is the immediate hard stop. The bundle's constraints resolve to symfony/form ~2.3, symfony/framework-bundle ~2.3, and PHP ~5.3–5.6. Any current Laravel (10/11) requires symfony/* ^6/^7 and PHP 8.1+, so composer require produces an unresolvable graph; forcing it with --ignore-platform-reqs trades an install error for a runtime Class not found. The glue code is small (~200 lines), which is exactly the point: porting the pattern costs less than adapting the package.
Technical risk — high, and concentrated on the highest-severity surface. This lands directly in the rich-text input path, the primary vector for stored XSS. WYSIHTML5 is abandoned upstream, its browser and CSP assumptions predate current practice, and the bundle pins an ancient HTMLPurifier integration and config surface. HTMLPurifier itself remains maintained — that is the one salvageable component, and it is available directly without this bundle. 2 stars and 0 dependents confirm no community triage and no security response path.
Key questions for the team:
TPM read on the 0.11 score: the score is consistent, and it makes the decision cheap. The TPM value here is not evaluating the package; it is converting the finding into a reusable framework-fit and maintenance gate for dependency intake, and using the package as a worked reference for the sanitize-on-write boundary.
Stack fit — none at the framework level; strong at the pattern level. The bundle assumes Symfony's kernel, form theme rendering, and assets:install publishing. Laravel has maintained equivalents for every one of those concerns: mews/purifier (or ezyang/htmlpurifier directly) for sanitization, Vite for assets, Blade components for the editor. Running both conventions in one process is the failure mode to avoid, not a migration strategy.
Migration path — extract the pattern, discard the code. A one-day spike ports the design:
mews/purifier (Laravel-native config and facade) or ezyang/htmlpurifier; define a RichText purification profile matching the bundle's allowed-tags posture, with explicit allow-lists for tags, attributes, and URI schemes.<script>, onerror=, javascript: URIs, and style-based vectors are stripped, with the exact expected output committed as the content contract.Compatibility gaps to record in the ADR: PHP 8 strict types and typed properties (bundle code predates both), Twig vs Blade syntax, Symfony YAML service definitions vs Laravel service providers, Assetic vs Vite manifest, and the absence of any stable release tag.
Sequencing recommendation:
TPM control points: lock the sequencing before engineering starts so "make the bundle work" doesn't become a sprint; require the payload test to be merged with the component, not scheduled after; and record the rejection in the dependency-intake policy while the example is fresh.
Maintenance — unacceptable as a standing dependency. Zero maintainer velocity, no release cadence, no dependents. Every future PHP major upgrade becomes our problem against dead code, and the editor upstream has no path to a supported release. Contrast with ezyang/htmlpurifier (actively maintained, widely depended upon) and TipTap/Quill (large, funded maintainer bases). This is a clean entry in the abandoned-dependency policy: what counts as unmaintained, what the replacement path is, who owns the migration.
Support — none. No issue-tracker throughput, no CVE response process, no upgrade guide. Adoption would require naming an internal owner before day one, and the honest cost of owning a fork exceeds the port described above. That asymmetry is the argument to make to stakeholders, not editor features.
Scaling — one genuine nuance, and it belongs to the replacement, not this package. WYSIHTML5 is lighter on the wire than ProseMirror/TipTap, so if payload weight to low-end mobile clients were a hard budget, the legacy editor has a marginal edge; measure it before conceding it. Offset against sanitizer cost: HTMLPurifier is meaningfully expensive on large documents, so sanitize on write and cache, never on read. That is a configuration and caching decision independent of which bundle is in play, and it should be set as a requirement on the replacement component.
Failure modes to expect if forced down this path:
Class 'Symfony\Component\Form\AbstractType' not found at runtime after a forced install.assets:install publishing does not map to Vite's manifest.Ramp-up — low reading cost, high opportunity cost. The code is comprehensible in an hour. The real cost is the team learning Symfony 2 form and container conventions to evaluate it, then discarding them, plus the review time on the security surface. That time is better spent on the half-day spike against maintained libraries.
Recommendation: Do not adopt; classify as reference-only. Ship the capability with mews/purifier (or ezyang/htmlpurifier) plus a maintained editor, gated by the payload test. Ask: no budget — one engineering decision (editor selection), one policy artifact (framework-fit and maintenance gates in dependency review), and a named owner for the internal rich-text component. Re-evaluate only if the org standardizes on a legacy Symfony 2 application, which is not the stated Laravel context.
How can I help you explore Laravel packages today?