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

mahefa/comment-bundle

mahefa/comment-bundle is a PHP package for adding comment functionality to your application. It provides core building blocks for storing, retrieving, and managing comments, making it easier to integrate discussion features into Laravel or PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a fork of the long-abandoned friendsofsymfony/comment-bundle — a Symfony bundle, not a Laravel package. Before you type composer require, understand what you're actually adopting: a Symfony DI/HttpKernel/Form/Doctrine stack with a 2022 release date, 0 stars, 0 dependents, and an upstream that was archived years ago. For a Laravel shop the realistic starting points are:

  1. Evaluate it as a reference implementation (MIT license — copy the patterns freely).
  2. Run it in a legacy/hybrid Symfony service you already operate, and call it over HTTP.
  3. Do not try to bolt it into a Laravel app; it will drag Symfony's kernel, event dispatcher, form component and DoctrineBundle in with it.

If you are in a Symfony codebase, the minimal path is:

composer require mahefa/comment-bundle

Then register it (Flex-era Symfony uses config/bundles.php, older uses AppKernel), import its routing, and — critically — subclass its mapped superclasses rather than using them directly:

// src/Entity/Comment.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\CommentBundle\Entity\Comment as BaseComment;

/**
 * @ORM\Entity
 * @ORM\Table(name="comment")
 */
class Comment extends BaseComment
{
}

Do the same for Thread, then point the bundle at your classes:

# config/packages/fos_comment.yml
fos_comment:
    db_driver: orm
    class:
        model:
            comment: App\Entity\Comment
            thread:  App\Entity\Thread

Where to look first, in this order:

  • Model/ — CommentInterface, ThreadInterface, CommentManagerInterface, ThreadManagerInterface. This is the contract surface you'll actually code against.
  • Entity/BaseComment.php and Entity/BaseThread.php — the persisted shape, including the tree columns (parent, children, level, treeLeft/treeRight).
  • Controller/ — ThreadController and CommentController; these define the HTTP contract (list thread, create comment, edit, delete, vote).
  • Resources/config/ — service ids (fos_comment.manager.comment, fos_comment.manager.thread), the ACL voters, and the routing definitions.
  • Form/ — CommentType, ThreadType; useful if you're replicating validation rules.

First use case — a comment thread on a blog post: create a Thread keyed by an identifier like post:42, list it via the thread route, and post replies through the comment-create route. Everything else (moderation, voting, spam) is layered on top of that.

Implementation Patterns

Thread-per-resource via string identifier. FOSCommentBundle does not use a polymorphic foreign key like Laravel's morphTo. Instead a Thread carries a unique string identifier (plus an optional permalink), and the manager resolves it:

$thread = $threadManager->findThreadById('post:42')
    ?? $threadManager->createThread('post:42');

Adopt this only if you like it; a Laravel dev will find $post->commentThread() more natural. The trap is that identifier has a unique index — namespace it (post:42, page:7) or you'll get collisions the first time you reuse raw IDs across entity types.

Manager-as-service. All persistence goes through CommentManagerInterface, never through the repository directly. This is the bundle's best idea and the one worth stealing: it gives you a single seam for wrapping transactions, firing events, and swapping storage drivers. In Laravel terms, bind a CommentManager in a service provider and keep controllers/model-free.

Extend, don't edit. Every customization path is inheritance or service replacement: subclass BaseComment/BaseThread, override the manager service id in your container, implement SpamDetectionInterface, or drop templates into templates/bundles/FOSCommentBundle/. Treat the vendor directory as read-only.

State machine, not booleans. CommentInterface exposes STATE_VALID, STATE_PENDING, STATE_SPAM, STATE_DELETED. Moderation is a transition between those, and the listing query filters on state. If you're porting to Laravel, copy this enum verbatim — it's better than the is_approved boolean most homegrown implementations reach for.

Event-driven side effects. The bundle emits fos_comment.comment.created, fos_comment.comment.persist, fos_comment.thread.created and friends. Notifications, webhooks and anti-spam enrichment belong in subscribers, not in the controller or the entity. In Laravel this maps cleanly to model observers or domain events dispatched from the manager.

ACL as voters, configured explicitly. Permissions (canCreateCommentOnThread, canEditComment, canDeleteComment, canVoteOnComment) are separate voters under fos_comment.acl.*. Configure them in fos_comment.yml; the defaults are permissive and are the single most common way people ship an open comment form to production.

Voting is pluggable. VoteInterface plus a score denormalized onto the comment. There is no batching — every upvote is an UPDATE on the comment row plus a tree-adjacent write. At scale you'll want to move the score aggregation out to a queue.

Integration tip for a hybrid stack. If you're running the bundle inside a Symfony service and consuming it from Laravel, expose the thread/comment controllers as JSON (they already return a Response you can shape) and let Laravel own users, auth and notifications. Pass a signed user identifier — the bundle's ACL layer will trust whatever you hand it.

If you're actually porting to Laravel, the equivalent stack is kalnoy/laravel-nestedset (or a plain parent_id + recursive CTE) on a comments table with commentable_type/commentable_id, plus a /comments resource controller. Take the state machine, the manager abstraction and the event names; leave the tree columns behind.

Gotchas and Tips

  • It's Symfony. This is the headline gotcha. There is no bundle concept in Laravel and no service container bridge. composer require inside a Laravel app will pull symfony/http-kernel, symfony/form, symfony/security-core, doctrine/doctrine-bundle and expect a Kernel. You will be maintaining two frameworks to get threaded comments.
  • The maintenance posture is the real risk. 0 stars, 0 dependents, last release 2022-08-10, and the upstream FOSCommentBundle has been unmaintained since the Symfony 3 era. Assume no security patches, no PHP 8.3+ fixes, and no Doctrine ORM 3 support.
  • Annotations, not attributes. The bundle's mappings and routes are Doctrine/Sensio annotations. Doctrine ORM 3 removed the annotation driver entirely. Pin doctrine/orm:^2.x or you'll be rewriting mappings before you write a single comment.
  • Tree columns go stale. treeLeft/treeRight/level/childCount are materialized and recomputed on insert. Concurrent replies to the same thread contend on the same rows — expect deadlocks under load. Serialize writes per thread (advisory lock on the root, or a queue with a single worker per thread), and add a rebuild command for when the counters drift.
  • Soft-deleted comments keep their tree slot. Moving a comment to STATE_DELETED leaves the tree intact, so childCount and level-based rendering drift from what users see. Decide early whether deletes are tombstones or real row removals.
  • The ACL defaults are open. Ship nothing until you've configured fos_comment.acl and written a test that an anonymous user cannot create a comment. This is the most common production incident with this family of bundles.
  • Akismet and other spam detectors make synchronous network calls on the request path and there's no built-in circuit breaker. If the detector throws, decide explicitly whether you fail open (spam gets through) or closed (comments break). Wrap it in your own SpamDetectionInterface decorator.
  • Routing has two surfaces — the HTML/JS routes and the API routes. Import them with an explicit prefix and check bin/console debug:router | grep fos_comment before assuming which one your front-end hit. CSRF is enforced on the create endpoints and will silently 400 an AJAX front-end that doesn't send a token.
  • Verify the Composer metadata before trusting it. Forks routinely ship broken replace, stale branch-alias, or a symfony/* constraint that resolves to an ancient major. Run composer why-not mahefa/comment-bundle and read the requirements before committing.
  • Debugging entry points: bin/console debug:container fos_comment, debug:event-dispatcher | grep comment, debug:router. Most "the comment didn't save" reports trace back to a mis-aliased model class parameter, not a logic bug.
  • Extension points worth knowing: replace fos_comment.manager.comment with your own CommentManagerInterface implementation; decorate SpamDetectionInterface; add a VoteInterface implementation; subscribe to the fos_comment.* events; override templates under templates/bundles/FOSCommentBundle/. None of these require touching vendor code.
  • MIT license is your escape hatch. If the goal is "threaded comments in Laravel," read Model/ and Entity/ for two hours, copy the state machine and the manager seam, and build a 200-line Laravel-native version. That will outlive this fork.
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.
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
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo