Provides messenging features for your Symfony2 application.
The persistence is storage agnostic. Any backend may be implemented: Doctrine, Propel, etc. Presently, only the MongoDB implementation is complete.
MessageBundle supports threads, spam detection, soft deletion and messenging permissions.
MessageBundle requires FOSUserBundle by default, as NewThreadMessageFormType depends on the fos_user_username field type for entering a new message recipient. This dependency is optional if you implement a custom form type for new messages and specify your class in the new_thread_form.type config option.
Note: PR #32 introduced significant schema changes for the MongoDB model
layer. The ornicar:message:mongodb:migrate:metadata
console command may be
used to migrate your existing schema. Please refer to the command's help message
for additional information.
$ git submodule add git://github.com/ornicar/OrnicarMessageBundle.git vendor/bundles/Ornicar/MessageBundle
"require": { ... "ornicar/message-bundle": "dev-master" ... }
// app/autoload.php $loader->registerNamespaces(array( 'Ornicar' => __DIR__.'/../vendor/bundles', // your other namespaces );
// app/AppKernel.php public function registerBundles() { return array( // ... new Ornicar\MessageBundle\OrnicarMessageBundle(), // ... ); }
You have to include the MessageBundle in your Doctrine mapping configuration, along with the bundle containing your custom Thread and Message classes:
# app/config/config.yml doctrine_mongo_db: document_managers: default: mappings: OrnicarMessageBundle: ~ # your other bundles
The above example assumes a MongoDB configuration, but the mappings configuration block would be the same for ORM.
The message senders and recipients are called participants of the thread. MessageBundle will only refer to them using the ParticipantInterface. This allows you to use any user class. Just make it implement this interface.
For exemple, if your user class is Acme\UserBundle\Document\User
:
// src/Acme/UserBundle/Document/User.php use Ornicar\MessageBundle\Model\ParticipantInterface; /** * @MongoDB\Document */ class User implements ParticipantInterface { // your code here }
If you need a bundle providing a base user, see http://github.com/FriendsOfSymfony/FOSUserBundle
- For MongoDB
- For Doctrine_ORM
You will probably want to include the built-in routes.
In YAML:
# app/config/routing.yml ornicar_message: resource: "@OrnicarMessageBundle/Resources/config/routing.xml" prefix: /optional_routing_prefix
Or if you prefer XML:
# app/config/routing.xml <import resource="@OrnicarMessageBundle/Resources/config/routing.xml"/>
Have a look to the default controller to learn how to use the messenging services:
Controller\MessageController.php
You can also simply send a message from your code.
Get the threads in the inbox of the authenticated user:
$provider = $container->get('ornicar_message.provider'); $threads = $provider->getInboxThreads();
And the threads in the sentbox:
$threads = $provider->getSentThreads();
To get a single thread, check it belongs to the authenticated user and mark it as read:
$thread = $provider->getThread($threadId);
See Ornicar\\MessageBundle\\Model\\ThreadInterface
for the complete list of available methods:
// Print the thread subject echo $thread->getSubject(); // Get the tread participants $participants = $thread->getParticipants(); // Know if this participant has read this thread if ($thread->isReadByParticipant($participant)) // Know if this participant has deleted this thread if ($thread->isDeletedByParticipant($participant))
See Ornicar\\MessageBundle\\Model\\MessageInterface
for the complete list of available methods:
// Print the message body echo $message->getBody(); // Get the message sender participant $sender = $message->getSender(); // Get the message thread $thread = $message->getThread(); // Know if this participant has read this message if ($message->isReadByParticipant($participant))
Create a new message thread:
$composer = $container->get('ornicar_message.composer'); $message = $composer->newThread() ->setSender($jack) ->addRecipient($clyde) ->setSubject('Hi there') ->setBody('This is a test message') ->getMessage();
And to reply to this thread:
$message = $composer->reply($thread) ->setSender($clyde) ->setBody('This is the answer to the test message') ->getMessage();
Note that when replying, we don't need to provide the subject nor the recipient. Because they are the attributes of the thread, which already exists.
Nothing's easier than sending the message you've just composed:
$sender = $container->get('ornicar_message.sender'); $sender->send($message);
MessageBundle provides a few twig functions:
{# template.html.twig #} {# Know if a message is read by the authenticated participant #} {% if not ornicar_message_is_read(message) %} This message is new! {% endif %} {# Know if a thread is read by the authenticated participant. Yes, it's the same function. #} {% if not ornicar_message_is_read(thread) %} This thread is new! {% endif %} {# Get the number of new threads for the authenticated participant #} You have {{ ornicar_message_nb_unread() }} new messages
Using Akismet
Install AkismetBundle (http://github.com/ornicar/AkismetBundle).
Then, set the spam detector service accordingly:
# app/config/config.yml ornicar_message: spam_detector: ornicar_message.akismet_spam_detector
You can use any spam dectetor service, including one of your own, provided the
class implements Ornicar\MessageBundle\SpamDetection\SpamDetectorInterface
.
You can change the security logic by replacing the authorizer
service:
# app/config/config.yml ornicar_message: authorizer: acme_message.authorizer
Your class must implement Ornicar\MessageBundle\Security\AuthorizerInterface
:
interface AuthorizerInterface { /** * Tells if the current user is allowed * to see this thread * * @param ThreadInterface $thread * @return boolean */ function canSeeThread(ThreadInterface $thread); /** * Tells if the current participant is allowed * to delete this thread * * @param ThreadInterface $thread * @return boolean */ function canDeleteThread(ThreadInterface $thread); /** * Tells if the current participant is allowed * to send a message to this other participant * * $param ParticipantInterface $participant the one we want to send a message to * @return boolean */ function canMessageParticipant(ParticipantInterface $participant); }
You can tell whether the user can see or delete a thread, and if he can send a new message to another user.
See the default implementation in Ornicar\MessageBundle\Security\Authorizer
.
This bundles dispatches event when notable actions are performed.
See Ornicar\MessageBundle\Event\OrnicarMessageEvents
for a documented
list of the available events.
All configuration options are listed below:
# app/config/config.yml ornicar_message db_driver: mongodb thread_class: Acme\MessageBundle\Document\Thread message_class: Acme\MessageBundle\Document\Message message_manager: ornicar_message.message_manager # See ModelManager\MessageManagerInterface thread_manager: ornicar_message.thread_manager # See ModelManager\ThreadManagerInterface sender: ornicar_message.sender # See Sender\SenderInterface composer: ornicar_message.composer # See Composer\ComposerInterface provider: ornicar_message.provider # See Provider\ProviderInterface participant_provider: ornicar_message.participant_provider # See Security\ParticipantProviderInterface authorizer: ornicar_message.authorizer # See Security\AuthorizerInterface message_reader: ornicar_message.message_reader # See Reader\ReaderInterface thread_reader: ornicar_message.thread_reader # See Reader\ReaderInterface deleter: ornicar_message.deleter # See Deleter\DeleterInterface spam_detector: ornicar_message.noop_spam_detector # See SpamDetection\SpamDetectorInterface twig_extension: ornicar_message.twig_extension # See Twig\Extension\MessageExtension search: finder: ornicar_message.search_finder # See Finder\FinderInterface query_factory: ornicar_message.search_query_factory # See Finder\QueryFactoryInterface query_parameter: 'q' # Request query parameter containing the term new_thread_form: factory: ornicar_message.new_thread_form.factory # See FormFactory\NewThreadMessageFormFactory type: ornicar_message.new_thread_form.type # See FormType\NewThreadMessageFormType handler: ornicar_message.new_thread_form.handler # See FormHandler\NewThreadMessageFormHandler name: message reply_form: factory: ornicar_message.reply_form.factory # See FormFactory\ReplyMessageFormFactory type: ornicar_message.reply_form.type # See FormType\ReplyMessageFormType handler: ornicar_message.reply_form.handler # See FormHandler\ReplyMessageFormHandler name: message
I need your help for the ORM - and more - implementations.
To provide a new backend implementation, you must implement these interfaces:
Model/ThreadInterface.php
Model/MessageInterface.php
ModelManager/ThreadManagerInterface.php
ModelManager/MessageManagerInterface.php
MongoDB implementation examples:
Document/Thread.php
Document/Message.php
DocumentManager/ThreadManager.php
DocumentManager/MessageManager.php
Note that the MongoDB manager classes only contain MongoDB-specific logic. Backend-agnostic logic lives within the abstract managers.
You may also need to define mappings.
MongoDB mapping examples:
src/Ornicar/MessageBundle/Resources/config/doctrine/thread.mongodb.xml
src/Ornicar/MessageBundle/Resources/config/doctrine/message.mongodb.xml