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

Comment Bundle Laravel Package

short-edition/comment-bundle

A lightweight Laravel bundle for adding threaded comments to your models, with nested replies, moderation-ready structure, and simple Blade helpers. Minimal setup, sensible defaults, and clean integration for small projects that need commenting without the overhead.

View on GitHub
Deep Wiki
Context7

Getting Started

The reality check you need on day one. short-edition/comment-bundle is a republished fork of friendsofsymfony/comment-bundle — a Symfony bundle, not a Laravel package. It ships no ServiceProvider, no publishable config/comment.php, no Blade views, and no Illuminate dependencies. It will not boot in a Laravel app, and composer require is expected to fail at the resolver level because the bundle's Symfony 2/3-era constraints collide with the Symfony 6/7 components Laravel 10/11 requires. As a Laravel developer, your leverage comes from reading it as a reference implementation of the threading domain model, not from installing it.

Where to look first (in this order, ~90 minutes total):

  1. composer.json — the require block tells you immediately whether it can coexist with your PHP version, and confirms the Symfony/Doctrine dependency chain.
  2. Entity/Comment.php and Entity/Thread.php — the actual domain model. This is the package's real value: how a comment relates to a thread, how a parent/child tree is represented, what fields exist for moderation state and voting.
  3. Manager/CommentManagerInterface.php and its Doctrine implementation — the abstraction seam the bundle is built around. This is the boundary you would replicate in Laravel as a contract + Eloquent implementation.
  4. DependencyInjection/Configuration.php — every tunable knob (nesting depth, sorting, pagination, moderation). This becomes your config/comments.php requirements doc.
  5. Resources/views/ (the Twig templates) — how threading is rendered recursively, how pagination is surfaced, and where moderation controls attach.

Your first concrete use case. Do not try to run the package. Instead, extract a Laravel-shaped spec: a Comment model with thread_id, parent_id, body, state, author_id; a Thread model with a polymorphic commentable morph; configurable max_depth; and moderation states as a PHP enum. Then implement threaded replies once with kalnoy/nestedset (or a closure table) and prove you can render a 3-level thread in Blade. That one-day spike gives you 80% of the bundle's value with 0% of its maintenance burden.

The composer spike (gated, 1–2 hours max). If a stakeholder mandates evaluation, attempt composer require short-edition/comment-bundle in a throwaway Laravel app. Record the resolver error verbatim and stop. Everything downstream is wasted effort if that gate fails — and it is expected to fail.

Implementation Patterns

Pattern 1 — Blueprint port (the default, recommended). Use the bundle as a design document and reimplement in Laravel idiom. The four things worth copying verbatim:

  • Tree storage choice. The bundle leans on Doctrine Tree (nested-set / materialized-path). Nested-set gives fast reads and painful writes; a closure table gives simpler, safer concurrent writes. For a Laravel social-ish app, prefer kalnoy/nestedset on top of Eloquent or a hand-rolled closure table — do not hand-roll nested-set bounds math.
  • Manager interface as a contract. Bind App\Contracts\CommentManager in a service provider and implement with Eloquent. This preserves the package's clean seam and makes swapping storage later cheap.
  • Config surface. Mirror Configuration.php into config/comments.php: max_depth, default_sort, per_page, allow_voting, moderation.enabled, moderation.default_state.
  • Moderation as explicit state. Model it as an enum cast (Pending, Approved, Rejected, Spam) rather than a boolean — the bundle's state handling is the part most worth inheriting conceptually. Filter at the query layer with a scope, never in the view.

Pattern 2 — Behavioral parity tests. If you ever migrate off a real FOSCommentBundle installation, write feature tests against the semantics before you build UI: create root comment, reply to depth N, reject reply at N+1, soft-delete a parent with children, paginate a thread at depth 3. These tests become the receipt that the port is faithful.

Pattern 3 — Event-driven side effects. The bundle dispatches Symfony events on comment creation/moderation/deletion. In Laravel, emit CommentCreated, CommentModerated, CommentDeleted and hang notifications, spam scoring, and audit logging off listeners. Keep notification dispatch queued (ShouldQueue) — comment traffic is spiky and you do not want SMTP in the request path.

Pattern 4 — Polymorphic attachment. The bundle attaches threads to "any entity." In Eloquent that is a morphMany(Comment::class, 'commentable') on the parent model, plus a morphTo on Comment. Add an index on (commentable_type, commentable_id) and a deleted_at-aware scope so threads don't leak soft-deleted parents.

Pattern 5 — Rendering. Rebuild the Twig recursion as a Blade recursive component (<x-comment :comment="$comment" :depth="$depth" />) that hard-stops at max_depth. Paginate at the thread level, not per node; use cursor pagination for deep threads.

Pattern 6 — Strangler port (only if you're on a legacy Symfony estate). If existing production FOSCommentBundle data must be preserved, sequence it: schema migration with legacy_id columns → domain port with parity tests → event hooks reimplemented → Blade UI → moderation/rate-limiting/GDPR erasure added → frozen-writes cutover with post-import tree integrity verification (node counts, max depth, path validity).

Framework-fit routing. Do not build an adapter layer that runs Symfony components inside Laravel. Either read-and-reimplement or, if you genuinely need the bundle, run Symfony as the host — that is a stack decision, not an integration task.

Gotchas and Tips

  • Resolver conflicts are the first hour, not the last. Laravel 10/11 require Symfony 6.x/7.x components; this bundle targets 2.x/3.x. composer require will likely fail immediately. Treat that as the decision gate, not an obstacle to route around.
  • No migration files in the Laravel idiom. Doctrine entities use annotations/attributes and lifecycle callbacks. You will hand-author Eloquent migrations anyway — so you are paying the port cost regardless of whether you keep the PHP classes.
  • Nested-set writes are the danger zone. Inserts and moves rewrite left/right bounds and require locking under concurrency. Comment traffic is spiky (viral threads, live events). Plan for transactional writes, read caching, and async notifications. Silent tree corruption is expensive to repair — add a scheduled integrity check.
  • Zero dependents means zero search corpus. No Stack Overflow answers, no GitHub issue history for this fork, no peers who hit your bug. Debugging is entirely first-principles. Budget for it or avoid it.
  • Security is entirely on you. No CVE response path, no CI signal, no PHP 8.x modernization guarantee. The bundle provides no rate limiting, spam scoring, report queue, or GDPR erasure hooks. If moderation and abuse are in scope — and for UGC they always are — that is a first-party build requirement either way.
  • Escaping differences. Twig autoescaping and Blade's {{ }} are not semantically identical in every edge case (raw filters, HTML in comments). Sanitize comment bodies at write time with an HTML purifier; never rely on the template layer alone.
  • Orphaned threads. Neither the bundle nor a naive Eloquent port cleans up comments when the parent entity is deleted. Add morphMany + explicit cascade or a queued purge job tied to parent model deletion, and a user_id-based purge for account erasure.
  • Pagination on deep threads is a trap. Per-node pagination produces fragmented, unreadable threads. Paginate top-level comments, then eager-load a bounded reply tree (with('replies.replies') capped by max_depth) — or accept N+1 and cache aggressively; the latter is often cheaper than over-engineering.
  • Config quirks to watch when reading the bundle: nesting depth limits, default sort order, and moderation defaults are commonly set three places (DI config, entity defaults, template conditionals). Consolidate into one config/comments.php when you port — divergence between those layers is the classic source of "why is this comment visible" bugs.
  • The extension points you actually want to steal: the manager interface (storage abstraction), the event names (side-effect seams), and the configuration tree (feature flags). The Doctrine entities, Twig templates, and Symfony Forms are all throwaway for a Laravel host.
  • Do not add it to composer.json. Not as a dependency, not as a dev dependency. Vendor it as read-only reference material if your team needs it on disk, with a code-owner annotation and a review date.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect