Parley: Polymorphic Messaging for Laravel

Now in the rearward comes the duke and his: Fortune in favour makes him lag behind. Summon a parley; we will talk with him. - Henry IV, Part 1

With Parley you can easily send messages between different object types within a Laravel application. These "conversations" can be bi-directional, allowing for easy communication with your users about topics relevant to your application. Take a look at the github readme for installation instructions or you can go straight to the API. The documentation below is for Parley 2. Instructions for Parley 1 are also available.

GitHub Packagist

Sending Messages and Starting Conversations

Parley treats groups of related messages as "Threads". A thread can have one or many messages within it. Starting a new conversation thread consists of creating a new Parley Thread using the Parley::discuss() method and adding recipients of the message using the withParticipants() method.

Let's imagine that we have an application that manages reservations for an event space. In this scenario we might have models for Users, Organizations, Events and "Rooms" (where the events take place.)

Suppose we need to reach out to an organization about their room request application. We can send a message directly to that organization by doing this:

Parley::discuss([
    'subject' => "Question about Room Request 1251B6",
    'body'   => "The room you requested does not have a piano - will that be a problem for your vocal warmups?",
    'author' => $administrator,
])->withParticipant($organization);

We could alternatively send that message to each member of the organization by doing this:

Parley::discuss([
    'subject' => "Question about Room Request 1251B6",
    'body'   => "The room you requested does not have a piano - will that be a problem for your vocal warmups?",
    'author' => $administrator,
])->withParticipant($organization->users);

Or we could send to multiple organzations by doing this:

Parley::discuss([
    'subject' => "Lost and Found: Blue Nalgene ",
    'body'   => "We found a blue nalgene water bottle in room 221 yesterday, you were the only groups in the space - do you know who it belongs to?",
    'author' => $administrator,
])->withParticipants([$organizationA, $organizationB]);

withParticipants() and withParticipant() are both valid and achieve the same purpose.

Reference Objects

If a thread concerns a specific model entity, such as an order (or a Reservation in our case,) you can also associate that object with the thread as a "reference object".

Parley::discuss([
    'subject' => "Question about Room Request 1251B6",
    'body'   => "Your credit card has expired - please provide a new payment method.",
    'author' => $administrator,
    'regarding' => $reservation
])->withParticipant($organization);

Retrieving and Displaying Messsages

To show a user their messages, you need to retrieve not only the messages associated with their user account but also with their organization:

$threads = Parley::gatherFor([$user, $user->organization])->get();

You can also retrieve only their unread or read threads like so:

$unreadThreads = Parley::gatherFor([$user, $user->organization])->unread()->get();
$readThreads = Parley::gatherFor([$user, $user->organization])->read()->get();

Displaying their notifications in an inbox can be done like this:

@foreach($threads as $thread) 
    <tr>
        <td>{{ $thread->subject }} {{ ($thread->hasBeenReadByMember($user) ? '' : ' - New' )}} 
        <td>Thread ID: {{ $thread->id }}</td>
    </tr>   
@endforeach

To display the messages for a specific thread:

<?php $thread = Parley::getThread($threadId); ?>

<h2>{{ $thread->subject }}</h2>
@foreach($thread->messages as $message)
    <div class="message">
        {{ $message->body }} <br /> - {{ $message->author_alias }}
    </div>
@endforeach

Once a user has seen a message, you can mark the thread as read for that user:

$thread->markReadForMembers($user);

Replying to Messages

Sometimes you may want to allow your users to respond to your notifications:

$thread = Parley::getThread($threadId);
$thread->reply([
    'body' => 'You found my water bottle!  I have been looking everywhere!',
    'author' => $user
]);

Managing Threads

Threads can be flagged as read or unread for each individual member of a conversation:

// Mark a thread as Read for an individual member
$thread->markReadForMembers($user);

// Mark a thread as unread for an individual user
$thread->markUnreadForMembers($user);

Each time a new reply is added to a thread it will be flagged as unread for each member except the author of the reply.

Additionally, threads can be marked "Open" or "Closed". This can be helpful if you want to use threads as support tickets. By default, every thread is open.

// Mark a thread as closed
$thread->closedBy($user);

// Re-open a thread
$thread->reopen();

You can also run a check to see if a thread has been closed, and find out who closed it:

$closed = $thread->isClosed();

$closedBy = $thread->getCloser();

API

Parley Facade / Parley Manager

discuss(array $messageData, $object = null)
This method creates a new Parley Thread. The $messageData array must contain a "subject", "body" and an "author". You can optionally provide an "alias" that will overwrite the $author->alias provided via the ParleyableInterface. You can optionally pass the reference object as the second parameter to this mehtod, or within the messageData array under the "regarding" key. Returns a Parley\Models\Thread instance.

gatherFor($members)
Returns a collection of threads belonging to the specified members. "members" can either a single parleyable object or an array of parleyable objects.

getThread($id)
Return a specific Parley\Models\Thread instance with the given id.

Threads

withParticipants()
Used to add the initial members to a new thread. You can give it a single object, an array of objects or a collection of objects, as long as they all implement the ParleyableInterface. Returns the Thread object.

withParticipant()
Same as above.

addParticipant($member)
Add a single member to a thread. Returns the Thread object.

removeParticipant($member)
Remove a single member from a thread. Returns the Thread object.

isParticipant($member)
Determine if a given object is a member of this thread. Returns boolean.

getMembers(array $options = [])
Return a collection of the thread's member objects. Occasionally you may want to return a collection of all a thread's members except a few specific objects. In that case you can pass an array of members to exclude by doing getMembers(['except' => [$user, $user->organization]])

reply($messageData)
Add a new reply message to a thread. The messageData array must contain a "body" and an "author". Returns the Thread object.

newestMessage()
Return the newest Message object associated with this thread.

originalMessage()
Return the first Message object associated with this thread.

messages()
Return a collection of Message object associated with this thread.

setReferenceObject($object)
Associate an object with this thread as a "reference object." This object must have an "id" property. Returns boolean.

getReferenceObject()
Return the reference object associated with this thread. Returns null if no reference object exists.

clearReferenceObject()
Remove the current reference object. Returns boolean.

getThreadAuthor()
Returnt the other of the first message in the thread.

closedBy($member)
Mark the thread as closed, and note that it was closed by this $member.

isClosed()
Is this thread closed? Returns boolean.

getCloser()
Return the member object that closed the thread.

reopen()
Mark the thread as open.

hasBeenReadByMember($member)
Check to see if a given member has read this thread. Returns boolean.

markReadForMembers($members)
Mark this thread as read for a given member or array of members.

markReadForAllMembers()
Mark this thread as read for all current members.

markUnreadForMembers($members)
Mark this thread as unread for a given member or array of members.

markUnreadForAllMembers()
Mark this thread as unread for all current members.

$thread->subject
The subject line (aka Name) for this thread.

__$thread->created_at__
Carbon Object representing the Thread's creation date.

__$thread->updated_at__
Carbon Object representing the timestamp of the last thread update.

__$thread->closed_at__
Carbon Object representing the Thread's closing date.

__$thread->deleted_at__
Carbon Object representing the Thread's deletion date.

Messages

thread()
Returns the Eloquent BelongsTo relationship connecting this message to its thread.

getAuthor()
Return the author of this message.

setAuthor($author, $alias = null) Change the author for this message. You can also pass in a specific alias to overwrite the $author->alias method provided by the ParleyableInterface.

$message->body
The text content of the message__

__$message->author_alias__
The alias (aka display name) of the message's author.

comments powered by Disqus