Participants represent users within a conversation. They bridge the gap between your application’s user models and WireChat conversations, managing roles, permissions, and conversation-specific user data.
use Wirechat\Wirechat\Enums\ParticipantRole;enum ParticipantRole: string{ case OWNER = 'owner'; case ADMIN = 'admin'; case PARTICIPANT = 'participant';}
Participants use a polymorphic relationship to link to any user model:
// The user who is participating$user = $participant->participantable;// Can work with any model$participant->participantable_type; // "App\\Models\\User"$participant->participantable_id; // 123
// Check if ownerif ($participant->isOwner()) { echo "Participant is the conversation owner";}// Check if admin (includes owners)if ($participant->isAdmin()) { echo "Participant has admin permissions";}
From the source code:
public function isAdmin(): bool{ return $this->role === ParticipantRole::OWNER || $this->role === ParticipantRole::ADMIN;}public function isOwner(): bool{ return $this->role === ParticipantRole::OWNER;}
$participant->exitConversation();// Check if exitedif ($participant->hasExited()) { echo "Participant has left the conversation";}
Owners cannot exit conversations. Private conversations cannot be exited (users should delete them instead).
The exit logic from the source:
public function exitConversation(): bool{ // Make sure conversation is not private abort_if( $this->conversation->isPrivate(), 403, 'Participant cannot exit a private conversation' ); // Make sure owner if group cannot be removed from chat abort_if( $this->isOwner(), 403, 'Owner cannot exit conversation' ); // Update Role to Participant $this->role = ParticipantRole::PARTICIPANT; $this->save(); if (!$this->hasExited()) { $this->exited_at = now(); return $this->save(); } return false;}
Admins can remove participants from conversations:
use Wirechat\Wirechat\Enums\Actions;// Remove a participant$participant->removeByAdmin($adminUser);// Check if removed by adminif ($participant->isRemovedByAdmin()) { echo "Participant was removed by an administrator";}
The removal creates an action record:
public function removeByAdmin(Model|Authenticatable $admin): void{ $adminParticipant = $this->conversation->participant($admin); if (!$adminParticipant) { return; } Action::create([ 'actionable_id' => $this->getKey(), 'actionable_type' => $this->getMorphClass(), 'actor_id' => $adminParticipant->getKey(), 'actor_type' => $adminParticipant->getMorphClass(), 'type' => Actions::REMOVED_BY_ADMIN, ]); // Downgrade role to normal participant $this->role = ParticipantRole::PARTICIPANT; $this->save();}
// Mark as read$conversation->markAsRead($user);// The participant's timestamp is updatedecho $participant->conversation_read_at; // "2024-01-15 10:30:00"
$conversation->deleteFor($user);// Check if deletedif ($participant->hasDeletedConversation(checkDeletionExpired: true)) { echo "Participant has deleted this conversation";}
Check if a participant has deleted a conversation:
// Simple checkif ($participant->hasDeletedConversation()) { echo "Conversation is marked as deleted";}// Check if deletion is still valid (not expired by new messages)if ($participant->hasDeletedConversation(checkDeletionExpired: true)) { echo "Conversation is deleted and no new messages have arrived";}
From the source code:
public function hasDeletedConversation(bool $checkDeletionExpired = false): bool{ if ($this->conversation_deleted_at === null) { return false; } $this->loadMissing('conversation'); $conversation = $this->conversation; // Expired conversation means hasDeletedConversation should return FALSE if ($checkDeletionExpired) { // Check if the deletion timestamp is older than the last update return $conversation->updated_at > $this->conversation_deleted_at ? false : true; } return true;}