Installation:
composer require braune-digital/message-bundle
Enable the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):
BrauneDigital\MessageBundle\BrauneDigitalMessageBundle::class => ['all' => true],
Generate Extensions (Critical for customization):
php bin/console sonata:easy-extends:generate --dest=src BrauneDigitalMessageBundle
Enable the generated bundle in config/bundles.php:
Application\BrauneDigital\MessageBundle\ApplicationBrauneDigitalMessageBundle::class => ['all' => true],
Extend User Entity:
Add the required relations to your User entity (XML/YAML/Annotation). Example snippet:
<one-to-many target-entity="Application\BrauneDigital\MessageBundle\Entity\UserHasConversation" field="conversations" mapped-by="user">
<cascade><cascade-remove /></cascade>
<order-by>
<order-by-field name="joinedOn" direction="DESC"/>
</order-by>
</one-to-many>
First Use Case: Create a conversation between two users via a controller:
use BrauneDigital\MessageBundle\Entity\Conversation;
use BrauneDigital\MessageBundle\Entity\Message;
$conversation = new Conversation();
$conversation->addUser($senderUser);
$conversation->addUser($recipientUser);
$entityManager->persist($conversation);
$message = new Message();
$message->setConversation($conversation);
$message->setSender($senderUser);
$message->setContent("Hello!");
$entityManager->persist($message);
$entityManager->flush();
Conversation Management:
Conversation entity with addUser() for participants.UserHasConversation (e.g., $user->getConversations()).Message entity to add isRead flag and update via repository.Message Handling:
Conversation and set sender. Use MessageBundle's Message entity.conversation_id in queries. Example:
$messages = $entityManager->getRepository(Message::class)
->findBy(['conversation' => $conversation], ['createdAt' => 'DESC']);
Notifications:
message.sent) via Symfony's event dispatcher. Extend the bundle to listen:
# config/services.yaml
BrauneDigital\MessageBundle\EventListener\MessageListener:
tags:
- { name: kernel.event_listener, event: message.sent, method: onMessageSent }
API Integration:
use Symfony\Component\Serializer\Annotation\Groups;
class Message {
/** @Groups({"api"}) */
private $content;
}
Doctrine Lifecycle Callbacks:
Use @ORM\PrePersist/@ORM\PostUpdate in extended entities to auto-set timestamps (e.g., createdAt).
use Doctrine\ORM\Mapping as ORM;
/** @ORM\PrePersist */
public function setCreatedAtValue() {
$this->createdAt = new \DateTime();
}
Sonata Admin:
Register Conversation/Message in services.yaml for admin panel:
services:
app.admin.conversation:
class: Application\BrauneDigital\MessageBundle\Admin\ConversationAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Messages", label: "Conversations" }
Testing:
Use MessageBundle's entities in PHPUnit tests. Example:
public function testMessageCreation() {
$conversation = new Conversation();
$conversation->addUser($this->createMock(User::class));
$message = new Message();
$message->setConversation($conversation);
$this->assertEquals($conversation, $message->getConversation());
}
SonataEasyExtends Dependency:
sonata-project/easy-extends for customization. Without it, you cannot extend entities.composer require sonata-project/easy-extends
Entity Overrides:
Message) must be done via sonata:easy-extends:generate. Directly modifying original entities will break updates.--dest to specify a custom namespace (e.g., src/Application/BrauneDigital/MessageBundle/Entity).Circular References:
UserHasConversation/UserHasMessage entities create circular references. Configure Doctrine to handle them:
<many-to-one target-entity="User" inversed-by="conversations">
<join-column name="user_id" referenced-column-name="id" on-delete="CASCADE"/>
</many-to-one>
Outdated Symfony 2 Syntax:
AppKernel.php). For Symfony 4/5:
config/bundles.php instead of AppKernel.php app/console with php bin/console.Missing Default Routes:
routing.yaml:
braune_digital_message_conversation:
path: /conversations
controller: Application\BrauneDigital\MessageBundle\Controller\ConversationController::index
Entity Mapping Issues:
php bin/console cache:clear
php bin/console doctrine:schema:update --force
Event Dispatching:
public function onMessageSent(MessageEvent $event) {
error_log("Message sent: " . $event->getMessage()->getContent());
}
Performance:
$user->getConversations()->matching($qb->orderBy('joinedOn', 'DESC'))->setMaxResults(10);
Custom Message Types:
Message entity to add fields (e.g., isSystemMessage, attachment):
/** @ORM\Column(type="boolean") */
private $isSystemMessage = false;
/** @ORM\ManyToOne(targetEntity="Attachment") */
private $attachment;
Validation:
use Symfony\Component\Validator\Constraints as Assert;
/** @Assert\NotBlank */
private $content;
API Resources:
class ConversationSerializer extends AbstractNormalizer {
public function normalize($object, $format = null, array $context = []) {
return [
'id' => $object->getId(),
'messages' => $object->getMessages()->map(fn($m) => $m->getContent()),
];
}
}
WebSocket Integration:
// In MessageEventListener
public function onMessageSent(MessageEvent $event) {
$this->websocketClient->send(json_encode([
'type' => 'message',
'data' => $event->getMessage()->getContent(),
]));
}
How can I help you explore Laravel packages today?