ConversationMessageModel::save PHP Method

save() public method

Save message from form submission.
Since: 2.0.0
public save ( array $FormPostValues, $Conversation = null, $Options = [] ) : integer
$FormPostValues array Values submitted via form.
return integer Unique ID of message created or updated.
    public function save($FormPostValues, $Conversation = null, $Options = array())
    {
        $Session = Gdn::session();
        // Define the primary key in this model's table.
        $this->defineSchema();
        // Add & apply any extra validation rules:
        $this->Validation->applyRule('Body', 'Required');
        $this->addInsertFields($FormPostValues);
        $this->EventArguments['FormPostValues'] = $FormPostValues;
        $this->fireEvent('BeforeSaveValidation');
        // Determine if spam check should be skipped.
        $SkipSpamCheck = !empty($Options['NewConversation']);
        // Validate the form posted values
        $MessageID = false;
        if ($this->validate($FormPostValues) && !$this->checkForSpam('ConversationMessage', $SkipSpamCheck)) {
            $Fields = $this->Validation->schemaValidationFields();
            // All fields on the form that relate to the schema
            touchValue('Format', $Fields, c('Garden.InputFormatter', 'Html'));
            $this->EventArguments['Fields'] = $Fields;
            $this->fireEvent('BeforeSave');
            $MessageID = $this->SQL->insert($this->Name, $Fields);
            $this->LastMessageID = $MessageID;
            $ConversationID = val('ConversationID', $Fields, 0);
            if (!$Conversation) {
                $Conversation = $this->SQL->getWhere('Conversation', array('ConversationID' => $ConversationID))->firstRow(DATASET_TYPE_ARRAY);
            }
            $Message = $this->getID($MessageID);
            $this->EventArguments['Conversation'] = $Conversation;
            $this->EventArguments['Message'] = $Message;
            $this->fireEvent('AfterSave');
            // Get the new message count for the conversation.
            $SQLR = $this->SQL->select('MessageID', 'count', 'CountMessages')->select('MessageID', 'max', 'LastMessageID')->from('ConversationMessage')->where('ConversationID', $ConversationID)->get()->firstRow(DATASET_TYPE_ARRAY);
            if (sizeof($SQLR)) {
                list($CountMessages, $LastMessageID) = array_values($SQLR);
            } else {
                return;
            }
            // Update the conversation's DateUpdated field.
            $DateUpdated = Gdn_Format::toDateTime();
            $this->SQL->update('Conversation c')->set('CountMessages', $CountMessages)->set('LastMessageID', $LastMessageID)->set('UpdateUserID', Gdn::session()->UserID)->set('DateUpdated', $DateUpdated)->where('ConversationID', $ConversationID)->put();
            // Update the last message of the users that were previously up-to-date on their read messages.
            $this->SQL->update('UserConversation uc')->set('uc.LastMessageID', $MessageID)->set('uc.DateConversationUpdated', $DateUpdated)->where('uc.ConversationID', $ConversationID)->where('uc.Deleted', '0')->where('uc.CountReadMessages', $CountMessages - 1)->where('uc.UserID <>', $Session->UserID)->put();
            // Update the date updated of the users that were not up-to-date.
            $this->SQL->update('UserConversation uc')->set('uc.DateConversationUpdated', $DateUpdated)->where('uc.ConversationID', $ConversationID)->where('uc.Deleted', '0')->where('uc.CountReadMessages <>', $CountMessages - 1)->where('uc.UserID <>', $Session->UserID)->put();
            // Update the sending user.
            $this->SQL->update('UserConversation uc')->set('uc.CountReadMessages', $CountMessages)->set('Deleted', 0)->set('uc.DateConversationUpdated', $DateUpdated)->where('ConversationID', $ConversationID)->where('UserID', $Session->UserID)->put();
            // Find users involved in this conversation
            $UserData = $this->SQL->select('UserID')->select('LastMessageID')->select('Deleted')->from('UserConversation')->where('ConversationID', $ConversationID)->get()->result(DATASET_TYPE_ARRAY);
            $UpdateCountUserIDs = array();
            $NotifyUserIDs = array();
            // Collapse for call to UpdateUserCache and ActivityModel.
            $InsertUserFound = false;
            foreach ($UserData as $UpdateUser) {
                $LastMessageID = val('LastMessageID', $UpdateUser);
                $UserID = val('UserID', $UpdateUser);
                $Deleted = val('Deleted', $UpdateUser);
                if ($UserID == val('InsertUserID', $Fields)) {
                    $InsertUserFound = true;
                    if ($Deleted) {
                        $this->SQL->put('UserConversation', array('Deleted' => 0, 'DateConversationUpdated' => $DateUpdated), array('ConversationID' => $ConversationID, 'UserID' => $UserID));
                    }
                }
                // Update unread for users that were up to date
                if ($LastMessageID == $MessageID) {
                    $UpdateCountUserIDs[] = $UserID;
                }
                // Send activities to users that have not deleted the conversation
                if (!$Deleted) {
                    $NotifyUserIDs[] = $UserID;
                }
            }
            if (!$InsertUserFound) {
                $UserConversation = array('UserID' => val('InsertUserID', $Fields), 'ConversationID' => $ConversationID, 'LastMessageID' => $LastMessageID, 'CountReadMessages' => $CountMessages, 'DateConversationUpdated' => $DateUpdated);
                $this->SQL->insert('UserConversation', $UserConversation);
            }
            if (sizeof($UpdateCountUserIDs)) {
                $ConversationModel = new ConversationModel();
                $ConversationModel->updateUserUnreadCount($UpdateCountUserIDs, true);
            }
            $body = val('Body', $Fields, '');
            $subject = val('Subject', $Conversation, '');
            $this->EventArguments['Body'] =& $body;
            $this->EventArguments['Subject'] =& $subject;
            $this->fireEvent('AfterAdd');
            $activityModel = new ActivityModel();
            foreach ($NotifyUserIDs as $notifyUserID) {
                if ($Session->UserID == $notifyUserID) {
                    continue;
                    // don't notify self.
                }
                // Notify the users of the new message.
                $activity = array('ActivityType' => 'ConversationMessage', 'ActivityUserID' => val('InsertUserID', $Fields), 'NotifyUserID' => $notifyUserID, 'HeadlineFormat' => t('HeadlineFormat.ConversationMessage', '{ActivityUserID,user} sent you a <a href="{Url,html}">message</a>'), 'RecordType' => 'Conversation', 'RecordID' => $ConversationID, 'Story' => $body, 'Format' => val('Format', $Fields, c('Garden.InputFormatter')), 'Route' => "/messages/{$ConversationID}#{$MessageID}");
                if (c('Conversations.Subjects.Visible') && $subject) {
                    $activity['HeadlineFormat'] = $subject;
                }
                $activityModel->queue($activity, 'ConversationMessage');
            }
            $activityModel->saveQueue();
        }
        return $MessageID;
    }

Usage Example

 /**
  * Save conversation from form submission.
  *
  * @since 2.0.0
  * @access public
  *
  * @param array $FormPostValues Values submitted via form.
  * @param ConversationMessageModel $MessageModel Message starting the conversation.
  * @return int Unique ID of conversation created or updated.
  */
 public function save($FormPostValues, $MessageModel)
 {
     // Define the primary key in this model's table.
     $this->defineSchema();
     $MessageModel->defineSchema();
     $this->EventArguments['FormPostValues'] = $FormPostValues;
     $this->fireEvent('BeforeSaveValidation');
     if (!val('RecipientUserID', $FormPostValues) && isset($FormPostValues['To'])) {
         $To = explode(',', $FormPostValues['To']);
         $To = array_map('trim', $To);
         $RecipientUserIDs = $this->SQL->select('UserID')->from('User')->whereIn('Name', $To)->get()->resultArray();
         $RecipientUserIDs = array_column($RecipientUserIDs, 'UserID');
         $FormPostValues['RecipientUserID'] = $RecipientUserIDs;
     }
     if (c('Garden.ForceInputFormatter')) {
         $FormPostValues['Format'] = c('Garden.InputFormatter');
     }
     // Add & apply any extra validation rules:
     $this->Validation->applyRule('Body', 'Required');
     $MessageModel->Validation->applyRule('Body', 'Required');
     // Make sure that there is at least one recipient
     $this->Validation->addRule('OneOrMoreArrayItemRequired', 'function:ValidateOneOrMoreArrayItemRequired');
     $this->Validation->applyRule('RecipientUserID', 'OneOrMoreArrayItemRequired');
     // Add insert/update fields
     $this->addInsertFields($FormPostValues);
     $this->addUpdateFields($FormPostValues);
     // Validate the form posted values
     $ConversationID = false;
     if ($this->validate($FormPostValues) && $MessageModel->validate($FormPostValues) && !$this->checkForSpam('Conversation')) {
         $Fields = $this->Validation->validationFields();
         // All fields on the form that relate to the schema
         // Define the recipients, and make sure that the sender is in the list
         $RecipientUserIDs = val('RecipientUserID', $Fields, 0);
         if (!in_array($FormPostValues['InsertUserID'], $RecipientUserIDs)) {
             $RecipientUserIDs[] = $FormPostValues['InsertUserID'];
         }
         // Also make sure there are no duplicates in the recipient list
         $RecipientUserIDs = array_unique($RecipientUserIDs);
         sort($RecipientUserIDs);
         $Fields = $this->Validation->schemaValidationFields();
         // All fields on the form that relate to the schema
         $ConversationID = $this->SQL->insert($this->Name, $Fields);
         $FormPostValues['ConversationID'] = $ConversationID;
         // Notify the message model that it's being called as a direct result
         // of a new conversation being created. As of now, this is being used
         // so that spam checks between new conversations and conversation
         // messages each have a separate counter. Without this, a new
         // conversation will cause itself AND the message model spam counter
         // to increment by 1.
         $MessageID = $MessageModel->save($FormPostValues, null, array('NewConversation' => true));
         $this->SQL->update('Conversation')->set('FirstMessageID', $MessageID)->where('ConversationID', $ConversationID)->put();
         // Now that the message & conversation have been inserted, insert all of the recipients
         foreach ($RecipientUserIDs as $UserID) {
             $CountReadMessages = $UserID == $FormPostValues['InsertUserID'] ? 1 : 0;
             $this->SQL->options('Ignore', true)->insert('UserConversation', array('UserID' => $UserID, 'ConversationID' => $ConversationID, 'LastMessageID' => $MessageID, 'CountReadMessages' => $CountReadMessages, 'DateConversationUpdated' => $FormPostValues['DateUpdated']));
         }
         // And update the CountUnreadConversations count on each user related to the discussion.
         $this->updateUserUnreadCount(array_diff($RecipientUserIDs, array($FormPostValues['InsertUserID'])));
         $this->updateParticipantCount($ConversationID);
         $this->EventArguments['Recipients'] = $RecipientUserIDs;
         $Conversation = $this->getID($ConversationID);
         $this->EventArguments['Conversation'] = $Conversation;
         $Message = $MessageModel->getID($MessageID, DATASET_TYPE_ARRAY);
         $this->EventArguments['Message'] = $Message;
         $this->fireEvent('AfterAdd');
         // Add notifications (this isn't done by the conversationmessagemodule
         // because the conversation has not yet been created at the time they are
         // inserted)
         $UnreadData = $this->SQL->select('uc.UserID')->from('UserConversation uc')->where('uc.ConversationID', $ConversationID)->where('uc.UserID <>', $FormPostValues['InsertUserID'])->get();
         $Activity = array('ActivityType' => 'ConversationMessage', 'ActivityUserID' => $FormPostValues['InsertUserID'], 'HeadlineFormat' => t('HeadlineFormat.ConversationMessage', '{ActivityUserID,User} sent you a <a href="{Url,html}">message</a>'), 'RecordType' => 'Conversation', 'RecordID' => $ConversationID, 'Story' => val('Body', $FormPostValues), 'Format' => val('Format', $FormPostValues, c('Garden.InputFormatter')), 'Route' => "/messages/{$ConversationID}#Message_{$MessageID}");
         $Subject = val('Subject', $Fields);
         if ($Subject) {
             $Activity['HeadlineFormat'] = $Subject;
         }
         $ActivityModel = new ActivityModel();
         foreach ($UnreadData->result() as $User) {
             $Activity['NotifyUserID'] = $User->UserID;
             $ActivityModel->queue($Activity, 'ConversationMessage');
         }
         $ActivityModel->saveQueue();
     } else {
         // Make sure that all of the validation results from both validations are present for view by the form
         foreach ($MessageModel->validationResults() as $FieldName => $Results) {
             foreach ($Results as $Result) {
                 $this->Validation->addValidationResult($FieldName, $Result);
             }
         }
     }
     return $ConversationID;
 }