I have user profiles that allow users to leave messages for each other. (Think Facebook/MySpace)...
Given a profile_messages
table with the following fields id
, user_id
, author_id
, parent_id
, and message
, how would I efficiently display them in a threaded layout?
Note: The comments will only be 1 level deep.
Currently, I'm fetching all of the relevant comments, then rebuilding the collection to have a $messages
with a sub-collection of replies
on each item.
$messages = new Collection();
$replySets = [];
foreach ($user->profileMessages as $message)
{
$parentId = $message->parent_id;
if ($parentId == 0)
{
$messages->put($message->id, $message);
}
else
{
$replySets[$parentId][] = $message;
}
}
foreach ($replySets as $parentId => $replies)
{
$parent = $messages->get($parentId);
if (isset($parent))
{
if ( ! isset($parent->replies))
{
$parent->replies = new Collection();
}
foreach ($replies as $reply)
{
$parent->replies->push($reply);
}
}
}
// Pass $messages to the view
This works great. However, I can't help but to think there is a better way of doing this... Is there a better way to do this, or perhaps a way to make use of the relationships to get a result set matching the $profileMessage->replies
structure?
From your description I assume you have root messages that have user_id
pointing to the user, a message was sent to. And replies to those root messages, that are relevant not to the user_id
but to the parent_id
.
So:
$user->load('messages.replies.author');
foreach ($user->messages as $message)
{
$message; // root message
$message->replies; // collection
$message->replies->first(); // single reply
$message->replies->first()->author;
}
with relations like below:
// user model
public function messages()
{
return $this->hasMany('Message')->where('parent_id', '=', 0);
// you could also create RootMessage model with global scope instead of this where
}
// message model
public function replies()
{
return $this->hasMany('Message', 'parent_id');
// again, here you can create separate Reply model if you like
}
public function author()
{
return $this->belongsTo('User', 'author_id');
}
public function user()
{
return $this->belongsTo('User');
}