Installation
composer require edumedia/comment-bundle
Add the bundle to config/bundles.php:
return [
// ...
eduMedia\CommentBundle\EduMediaCommentBundle::class => ['all' => true],
];
Create a Comment Entity
Extend CommentInterface and use CommentTrait:
// src/Entity/Comment.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use eduMedia\CommentBundle\Entity\CommentInterface;
use eduMedia\CommentBundle\Entity\CommentTrait;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity]
class Comment implements CommentInterface
{
use CommentTrait;
#[ORM\ManyToOne(targetEntity: User::class)]
private ?UserInterface $author = null;
}
Make an Entity Commentable
Implement CommentableInterface and use CommentableTrait:
// src/Entity/Post.php
namespace App\Entity;
use eduMedia\CommentBundle\Entity\CommentableInterface;
use eduMedia\CommentBundle\Entity\CommentableTrait;
class Post implements CommentableInterface
{
use CommentableTrait;
}
Run Migrations
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Add Admin Routes
Include the bundle’s routes in config/routes.yaml:
edumedia_comment:
resource: '@eduMediaCommentBundle/Resources/config/routes.yaml'
prefix: '/admin/comments'
Fetch Comments in a Controller
// src/Controller/PostController.php
public function show(Post $post, CommentManagerInterface $commentManager)
{
$comments = $commentManager->getComments($post);
return $this->render('post/show.html.twig', ['comments' => $comments]);
}
Render Comments in Twig
{% for comment in comments %}
<div class="comment">
<p>{{ comment.content }}</p>
<small>By {{ comment.author.username }} on {{ comment.createdAt|date('M d, Y') }}</small>
</div>
{% endfor %}
Add a Comment Form
{{ form_start(form) }}
{{ form_widget(form.content) }}
{{ form_widget(form.author) }}
<button type="submit">Post Comment</button>
{{ form_end(form) }}
Fetching Comments
Use CommentManagerInterface to retrieve comments for a commentable entity:
$comments = $commentManager->getComments($post);
$comments = $commentManager->getComments($post, ['active' => true]);
Adding/Editing Comments
Inject CommentManagerInterface into your controller/service:
$comment = $commentManager->createComment($post, $author, $content);
$commentManager->saveComment($comment);
Deleting Comments
$commentManager->deleteComment($comment);
getCommentableId() and getCommentableType() in CommentableTrait if using polymorphic commentable entities:
public function getCommentableId(): string
{
return $this->id;
}
public function getCommentableType(): string
{
return 'post';
}
Extend CRUD for Comments Customize the EasyAdmin CRUD controller for comments:
// src/Controller/Admin/CommentCrudController.php
use eduMedia\CommentBundle\Entity\Comment;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
class CommentCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Comment::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityLabelInSingular('Comment')
->setEntityLabelInPlural('Comments')
->addFormTheme('@eduMediaComment/admin/comment_form.html.twig');
}
}
Embed Comments in Parent Entity CRUD
Use the CommentableTrait to auto-load comments in EasyAdmin:
# config/easyadmin.php
easy_admin:
entities:
Post:
list:
fields: ['title', 'comments']
show:
fields: ['title', 'comments']
Custom Validation
Add validation rules to your Comment entity:
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
class Comment implements CommentInterface
{
#[Assert\NotBlank]
#[Assert\Length(min: 3)]
private string $content;
}
Pre/Post Save Hooks
Extend the CommentManager or use Doctrine lifecycle callbacks:
#[ORM\PrePersist]
public function setAuthorOnCreate()
{
if (!$this->author && $this->getUser()) {
$this->author = $this->getUser();
}
}
Type for Comments Create a custom form type for comments:
// src/Form/CommentType.php
namespace App\Form;
use eduMedia\CommentBundle\Entity\Comment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CommentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('content', TextType::class, [
'attr' => ['class' => 'comment-content'],
]);
}
}
Dynamic Comment Forms
Use CommentableInterface to dynamically render forms:
{% if app.user %}
{{ form_start(form) }}
{{ form_widget(form) }}
<input type="hidden" name="commentable" value="{{ commentable.id }}">
{{ form_end(form) }}
{% endif %}
Expose Comments as Subresources
Annotate your Comment entity:
#[ApiResource(
collectionOperations: ['get'],
itemOperations: ['get', 'put', 'delete'],
normalizationContext: ['groups' => ['comment:read']],
denormalizationContext: ['groups' => ['comment:write']]
)]
class Comment implements CommentInterface
{
// ...
}
Link Comments to Parent Resource
Use ApiProperty to link comments to their parent:
#[ApiProperty(identifier: false)]
#[Assert\NotNull]
private ?Post $commentable = null;
GraphQL Subscription for Real-Time Comments Use Symfony’s GraphQL bundle to subscribe to comment events:
type Comment {
id: ID!
content: String!
author: User!
createdAt: DateTime!
}
type Subscription {
commentAdded: Comment @subscribe
}
WebSocket Events
Emit events in CommentManager:
$eventDispatcher->dispatch(new CommentAddedEvent($comment));
Polymorphic Commentable Entities
getCommentableType(), comments may not associate correctly with polymorphic entities (e.g., Post vs. User).getCommentableType() in your CommentableTrait:
public function getCommentableType(): string
{
return static::class;
}
Missing Migrations
Comment entity or CommentableTrait fields.php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
EasyAdmin Route Conflicts
/admin/comments) may conflict with existing routes.config/routes/edumedia_comment.yaml:
edumedia_comment:
resource: '@eduMediaCommentBundle/Resources/config/routes.yaml'
prefix: '/dashboard/comments' # Custom prefix
Circular References in Forms
Comment and `CommentHow can I help you explore Laravel packages today?