GIF89a;
Direktori : /home/serb/www/livechat/php/model/ |
Current File : /home/serb/www/livechat/php/model/MessageModel.php |
<?php class MessageModel extends Model { // Constants const TALK_ID_ALL = -1; const TALK_ID_CANCELLED = -2; const USER_INFO_ALL = 'all'; const NEW_TALK_TIME_DELAY = 900; // how long does it take to group message in a separate talk: 15 minutes (in seconds) const LAST_MESSAGES_TIME_DELAY = 3600; // maximum age of previous messages displayed in the current talk: 1 hour (in seconds) // Defaults public $is_new = 'y'; // Constructor public function initialize() { parent::initialize(); $this->talk_id = self::TALK_ID_ALL; $this->to_id = self::TALK_ID_ALL; $this->to_user_info = self::USER_INFO_ALL; } // Getters & setters public function getTableName() { return 'mirrormx_customer_chat_message'; } public function getColumns() { return array('from_id', 'to_id', 'body', 'datetime', 'talk_id', 'is_new', 'from_user_info', 'to_user_info'); } // Methods public static function repo() { return new MessageModel; } public function preSave() { $result = parent::preSave(); if(!isset($this->id)) // New message { $fromUser = new UserModel((array) $result['from_user_info']); $toUser = new UserModel((array) $result['to_user_info']); $isGuest = !$fromUser->hasRole('OPERATOR'); $guestInTalk = false; $lastMessages = $this->getUserLastMessages($this->from_id, $this->to_id, $isGuest); $lastMessage = null; // Group message into a talk if(empty($lastMessages)) // Generate a new talk { $this->talk_id = $this->generateTalkId(); } else { $lastMessage = end($lastMessages); if($isGuest) { // Continue the current talk $this->talk_id = $lastMessage->talk_id; } else { if(!$toUser->hasRole('OPERATOR')) // Target user is a guest { // Check if guest is already talking with an operator foreach($lastMessages as $msg) { if($msg->to_id == $this->to_id) { $guestInTalk = true; if($msg->from_id == $this->from_id) { $lastMessage = $msg; $this->talk_id = $msg->talk_id; } } else if($msg->to_id == self::TALK_ID_ALL) { $lastMessage = $msg; $this->talk_id = $msg->talk_id; } } } if($this->talk_id == self::TALK_ID_ALL) $this->talk_id = $this->generateTalkId(); } } // Assign talk to an operator if($this->to_id != self::TALK_ID_CANCELLED && !($fromUser->hasRole('OPERATOR') && $toUser->hasRole('OPERATOR'))) { // Assign message to talk's operator, if any if($this->to_id == self::TALK_ID_ALL && $lastMessage->to_id != self::TALK_ID_ALL) // it's sent as a "broadcast" message, but has a talk already { if($lastMessage->from_id == $this->from_id) { $this->to_id = $lastMessage->to_id; $this->to_user_info = $lastMessage->to_user_info; } else if($lastMessage->to_id === $this->from_id) { $this->to_id = $lastMessage->from_id; $this->to_user_info = $lastMessage->from_user_info; } } else if(!$isGuest) // Operator writes to a guest { if($lastMessage) { if($lastMessage->to_id == self::TALK_ID_ALL || $lastMessage->talk_id == $this->talk_id) // operator "takes" the talk { $operator = $fromUser; $guest = $toUser; // Assign operator to messages in the talk and mark the messages as read self::$db->execute( 'UPDATE ' . $this->getTableName() . ' SET to_id = ?, is_new = ? WHERE from_id = ? AND (to_id = ? OR to_id = ?) AND talk_id = ?', array($operator->id, 'n', $guest->id, self::TALK_ID_ALL, $operator->id, $this->talk_id) ); } else if($guestInTalk) // Operator message is cancelled { $this->to_id = self::TALK_ID_CANCELLED; $this->id = self::CANCEL_SAVE_ID; } } } } // Encode from/to users data $result = $this->getData(); if($result['from_user_info'] !== self::USER_INFO_ALL) $result['from_user_info'] = json_encode($result['from_user_info']); if($result['to_user_info'] !== self::USER_INFO_ALL) $result['to_user_info'] = json_encode($result['to_user_info']); } // Store current time for new messages if(!isset($this->id)) $result['datetime'] = date('Y-m-d H:i:s'); return $result; } public function postRead($data) { $data = parent::postRead($data); $data['from_user_info'] = json_decode($data['from_user_info'], true); $data['to_user_info'] = json_decode($data['to_user_info'], true); return $data; } public function queryHistory($query) { if(empty($query)) $query = array(); $q = array(); if(isset($query['datetime'])) $q['datetime'] = $query['datetime']; $dbResults = $this->findBy($q, 'AND', array('datetime' => 'DESC')); // Group the results into "talk" groups $groups = array(); foreach($dbResults as $message) { if(!isset($groups[$message->talk_id])) $groups[$message->talk_id] = array(); $groups[$message->talk_id][] = $message; } // Filter by from_user_info and to_user_info fields $filteredResults = array(); if(isset($query['name']) || isset($query['mail'])) { foreach($groups as $group) { $addEntry = false; // Add the group to search results if any entry matches the filter foreach($group as $message) { $fromUser = $message->from_user_info; $toUser = $message->to_user_info; if(isset($query['name'])) { if(stripos($fromUser['name'], $query['name']) !== false || stripos($toUser['name'], $query['name']) !== false) { $addEntry = true; } } if(isset($query['mail'])) { if(stripos($fromUser['mail'], $query['mail']) !== false || stripos($toUser['mail'], $query['mail']) !== false) { $addEntry = true; } } if($addEntry) break; } if($addEntry) $filteredResults[] = $group; } } else { $filteredResults = array_values($groups); } $results = $filteredResults; return $results; } public function clearHistory() { // Remove all model entries return self::$db->execute('DELETE FROM ' . MessageModel::repo()->getTableName()); } public function generateTalkId() { // Find the last talk ID $result = self::$db->queryOne('SELECT MAX(talk_id) AS talk_id FROM ' . MessageModel::repo()->getTableName()); return $result['talk_id'] + 1; } public function getUserLastMessages($userId, $toId, $isGuest = false) { // Get last messages $lastMessages = $this->findBy(array( 'datetime' => array('>=', date('Y-m-d H:i:s', time() - self::NEW_TALK_TIME_DELAY)) )); $messages = array(); if(!empty($lastMessages)) { // Filter messages related to this user foreach($lastMessages as $message) { if($isGuest) // Guest to operator { if($message->from_id == $userId || $message->to_id == $userId) { $messages[] = $message; } } else // Operator to operator / operator to guest { if( $message->from_id == $userId || $message->to_id == $userId || $message->to_id == $toId || ($message->from_id == $toId && $message->to_id == self::TALK_ID_ALL) ) { $messages[] = $message; } } } } return $messages; } public function archiveMessagesToGuest($guestId) { // Mark last messages to the guest as read self::$db->query('UPDATE ' . $this->getTableName() . ' SET is_new = "n" WHERE to_id = ? AND is_new = "y"', array($guestId)); } public function archiveMessagesBy($userId, $messageIdFirst, $messageIdLast) { // Mark given messages to the guest as read self::$db->query('UPDATE ' . $this->getTableName() . ' SET is_new = "n" WHERE to_id = ? AND is_new = "y" AND id BETWEEN ? AND ?', array($userId, $messageIdFirst, $messageIdLast)); } public function archiveOutdatedMessages() { // Mark messages from offline guests as read self::$db->query( 'UPDATE ' . $this->getTableName() . ' m INNER JOIN ' . UserModel::repo()->getTableName() . ' u ON m.from_id = u.id ' . 'SET m.is_new = "n" WHERE u.last_activity < "' . date('Y-m-d H:i:s', time() - UserModel::GUEST_SESSION_TIME) . '"' ); } } ?>