Installation:
composer require friendsofsymfony/message-bundle
Add to config/bundles.php:
return [
// ...
FriendsOfSymfony\MessageBundle\FOSMessageBundle::class => ['all' => true],
];
Database Migration: Run migrations for Doctrine ORM (or ODM if using MongoDB):
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case: Send a message between users via a controller:
use FriendsOfSymfony\MessageBundle\Model\MessageInterface;
use FriendsOfSymfony\MessageBundle\Manager\MessageManagerInterface;
public function sendMessage(MessageManagerInterface $messageManager, $recipientId, Request $request)
{
$message = $messageManager->createMessage();
$message->setSender($this->getUser());
$message->setRecipientId($recipientId);
$message->setSubject($request->request->get('subject'));
$message->setBody($request->request->get('body'));
$messageManager->saveMessage($message);
return new Response('Message sent!');
}
Routing:
Enable routing by importing fos_message routes in config/routes.yaml:
fos_message:
resource: "@FOSMessageBundle/Resources/config/routing.yml"
prefix: /messages
Message Creation & Management:
MessageManagerInterface to create, read, update, and delete messages.ThreadManagerInterface:
$thread = $threadManager->findThreadById($threadId);
$message = $messageManager->createMessage();
$message->setThread($thread);
$message->setSender($this->getUser());
$message->setBody($request->get('content'));
$messageManager->saveMessage($message);
Permissions & Security:
# config/packages/security.yaml
access_control:
- { path: ^/messages, roles: ROLE_USER }
fos_message.permissions config (e.g., disable spam detection):
fos_message:
permissions:
spam_detection: false
Templates & Notifications:
templates/FOSMessageBundle/ to customize UI.// src/EventListener/NewMessageListener.php
public function onNewMessage(NewMessageEvent $event)
{
$message = $event->getMessage();
// Send email or trigger other logic
}
Register in services.yaml:
services:
App\EventListener\NewMessageListener:
tags:
- { name: kernel.event_listener, event: fos_message.new_message, method: onNewMessage }
Soft Deletion:
MessageManagerInterface::deleteMessage() for soft deletion (messages are marked as deleted but retained for auditing).$messages = $messageManager->getMessageRepository()->findBy(
['deletedAt' => null],
['createdAt' => 'DESC']
);
API Integration:
# config/routes/api.yaml
fos_message_api:
resource: "@FOSMessageBundle/Resources/config/routing/api.yml"
prefix: /api/messages
Doctrine Events:
Latch onto fos_message.message.pre_persist or fos_message.message.post_remove for pre/post-processing:
services:
App\EventListener\MessageEventListener:
tags:
- { name: kernel.event_listener, event: fos_message.message.pre_persist, method: onPrePersist }
Testing:
Use MessageManagerInterface in tests to mock message creation:
$messageManager = $this->createMock(MessageManagerInterface::class);
$messageManager->method('createMessage')->willReturn($message);
Custom Fields:
Extend the Message entity to add metadata (e.g., isUrgent):
// src/Entity/Message.php
class Message extends AbstractMessage
{
private $isUrgent = false;
// Getters/setters
}
Update the form type and templates accordingly.
Deprecation:
v1.3.0 (see legacy docs).Threading Quirks:
Permission Overrides:
fos_message:
permissions:
can_send_message: ['ROLE_USER', 'ROLE_ADMIN']
Spam Detection:
FOS\MessageBundle\Spam\SpamDetector service:
services:
fos_message.spam_detector:
class: App\Spam\CustomSpamDetector
arguments: ['@fos_message.manager']
ORM vs. ODM:
Message Not Saving:
$errors = $messageManager->getMessageValidator()->validate($message);
sender and recipientId are set (required fields).Threading Issues:
ThreadManagerInterface is injected correctly. Threads are auto-linked to messages via setThread() or setRecipient().Permission Denied:
fos_message.permissions:
php bin/console cache:clear
/profiler) for access control logs.Soft Deletion Not Working:
deletedAt is null for active messages. Use:
$message->setDeletedAt(new \DateTime()); // Hard delete
$message->setDeletedAt(null); // Restore
Custom Message Types:
AbstractMessage to add fields (e.g., FileMessage):
class FileMessage extends AbstractMessage
{
private $file;
// Add getters/setters and validation
}
MessageManager:
services:
App\Message\FileMessage:
tags: ['fos_message.message_type']
Event-Driven Extensions:
fos_message.thread.created to trigger side effects (e.g., analytics):
public function onThreadCreated(ThreadEvent $event)
{
$thread = $event->getThread();
// Custom logic
}
API Resources:
# config/api/resources.yaml
resources:
App\Entity\Message:
collectionOperations:
get: false
post: false
itemOperations:
get:
method: GET
path: /messages/{id}
Testing Helpers:
// tests/Utils/MessageTestHelper.php
class MessageTestHelper
{
public static function createTestMessage(MessageManagerInterface $manager, User $sender, User $recipient)
{
$message = $manager->createMessage();
$message->setSender($sender);
$message->setRecipientId($recipient->getId());
$message->setBody('Test message');
$manager->saveMessage($message);
return $message;
}
}
How can I help you explore Laravel packages today?