chat
chat copied to clipboard
[Need help by everyone]: 📬How to create an Inbox with the newest update?
So before the big update, my inbox worked quite fine. However, now I'm struggling to create an inbox method :( I need everyone's help. My code gets quite ugly.
I show you the "old" code before patch 4.x.x. and explain what needs to be done.
/**
* Fetch all inbox for currently loggedin user with pagination.
*
* @param User $auth
* @param int $offset
* @param int $take
* @param string $order
* @return LengthAwarePaginator
*/
protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
{
$conversations = \Chat::conversations()
->setPaginationParams([
'sorting' => $order,
])
->for($auth)
->limit($take)
->page(($offset + $take) / $take)
->get();
//eager load users to the table
$withUsers = $conversations
->load(['users' => function ($query) {
$query->withTrashed();
}]);
//filters empty last_messages out
$collection = $withUsers->filter(function ($value) {
return !is_null($value->last_message);
})->values();
//swap out
return $conversations->setCollection($collection);
}
Explination
- First I'm loading all conversation a user has via pagination
- I'm eager loading all users, even deleted ones (they appear as "anonymous" so the user still has the option to read the messages of a deleted user)
- Sometimes they are conversations where all messages have been deleted or it's empty, so the
last_message
resultednull
. So I needed to filter those out. - The modified collection is set back, so I can work with the data.
Currently
Now with the new update, this is not that easy anymore. And I'm struggling to create an inbox method again.
This is my current code (not working):
protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
{
$conversations = ChatChat::conversations()
->setPaginationParams([
'sorting' => $order,
])
->setParticipant($auth)
->limit($take)
->page(($offset + $take) / $take)
->get();
// Since the new update >4.x.x, it gives me unfortunately the Participation Model back
$withUsers = $conversations
->load(['conversation.participants.messageable' => function ($query) {
$query->withTrashed();
}]);
//filters empty last_messages out
$collection = $withUsers->filter(function ($value) {
return !is_null($value->conversation->last_message);
})->values();
//swap out
return $conversations->setCollection($collection);
}
Problems I face:
- [x] - The pagination does not result in Conversation Collection but to the Participation Model (I'm using Laravel API Resources, so I can hack this away, ugly but it's ok).
- [x] - I fixed the eager load problem with loading several relationships like
'conversation.participants.messageable'
- [ ] - This gives me the biggest problem. I don't know how to filter out the "last_message". Because even if I delete messages, the messages are still returned for the user, even though it should be deleted. Addiontally, I face the problem that when I try to use
$this->getNotification(auth()->user())
it fails, because it cannot find the notification table. I guess because it's deleted?
Testing
I'm super close to migrating the code, however, this test still fails hard because I cannot filter out the last_message
/** @test */
public function no_inbox_is_loaded_when_messages_is_deleted_by_authenticed_user()
{
$this->deleteMessageWithId(1)
->assertStatus(202);
$this->deleteMessageWithId(2)
->assertStatus(202);
$this->fetchInbox()
->assertJsonCount(0, 'data')
->assertStatus(200);
}
Any tips for me? Thank you!
I will take a look over the weekend. Thanks for detailed explanation
It would be lovely 😊There must be a way to create a simple inbox.
Requirements are super easy (perspective from the authenticated user and only two people are chatting):
- Able to paginate
- See the last message
- See if it was read or not
- Fetch user's data
There are two catches though:
- There might be conversations where all messages have been deleted -> filter them out
- There might be conversations where the other user has deleted his account, but still load to all conversation even the trashed users
It would be lovely 😊There must be a way to create a simple inbox.
Requirements are super easy (perspective from the authenticated user and only two people are chatting):
- Able to paginate
- See the last message
- See if it was read or not
- Fetch user's data
There are two catches though:
- There might be conversations where all messages have been deleted -> filter them out
- There might be conversations where the other user has deleted his account, but still load to all conversation even the trashed users
@pmochine Hi, i do this on my project and i thing it can help you
protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
{
$conversations = ChatChat::conversations()
->setPaginationParams([
'sorting' => $order,
])
->setParticipant($auth)
->limit($take)
->page(($offset + $take) / $take)
->get();
return $conversations;
}
All You Need To Do:
Clone library and replace getConversationsList
function in Musonza\Chat\Models\Conversation
file
/**
* @param Model $participant
* @param $options
*
* @return mixed
**/
private function getConversationsList(Model $participant, $options)
{
/** @var Builder $paginator */
$paginator = $participant->participation()
->join($this->tablePrefix . 'conversations as c', $this->tablePrefix . 'participation.conversation_id', '=', 'c.id')
->with([
'conversation.last_message' => function ($query) use ($participant) {
$query->join($this->tablePrefix . 'message_notifications', $this->tablePrefix . 'message_notifications.message_id', '=', $this->tablePrefix . 'messages.id')
->select($this->tablePrefix . 'message_notifications.*', $this->tablePrefix . 'messages.*')
->where($this->tablePrefix . 'message_notifications.messageable_id', $participant->getKey())
->where($this->tablePrefix . 'message_notifications.messageable_type', get_class($participant))
->whereNull($this->tablePrefix . 'message_notifications.deleted_at');
},
'conversation.participants.messageable' => function ($query) {
$query->withTrashed();
},
])
->whereHas('conversation.last_message', function ($query) use ($participant) {
$query->join($this->tablePrefix . 'message_notifications', $this->tablePrefix . 'message_notifications.message_id', '=', $this->tablePrefix . 'messages.id')
->select($this->tablePrefix . 'message_notifications.*', $this->tablePrefix . 'messages.*')
->where($this->tablePrefix . 'message_notifications.messageable_id', $participant->getKey())
->where($this->tablePrefix . 'message_notifications.messageable_type', get_class($participant))
->whereNull($this->tablePrefix . 'message_notifications.deleted_at');
});
if (isset($options['filters']['private'])) {
$paginator = $paginator->where('c.private', (bool)$options['filters']['private']);
}
if (isset($options['filters']['direct_message'])) {
$paginator = $paginator->where('c.direct_message', (bool)$options['filters']['direct_message']);
}
return $paginator
->orderBy('c.updated_at', 'DESC')
->orderBy('c.id', 'DESC')
->distinct('c.id')
->paginate($options['perPage'], [$this->tablePrefix . 'participation.*', $this->tablePrefix . 'participation.id as participation_id', 'c.*'], $options['pageName'], $options['page']);
}
And in view loop, get another participation
$anotherUser = $row->conversation->participants->where('id', '!=', $row->participation_id)->first()->messageable;
$conversaions: