/** * Log an operation into the log table. * * @param string $Operation The operation being performed. This is usually one of: * - Delete: The record has been deleted. * - Edit: The record has been edited. * - Spam: The record has been marked spam. * - Moderate: The record requires moderation. * - Pending: The record needs pre-moderation. * @param string $RecordType The type of record being logged. This usually correspond to the tablename of the record. * @param array $Data The record data. * - If you are logging just one row then pass the row as an array. * - You can pass an additional _New element to tell the logger what the new data is. * @param array $Options Additional options to affect the insert. * @return int|false The log ID or **false** if there was a problem. */ public static function insert($Operation, $RecordType, $Data, $Options = []) { if ($Operation === false) { return false; } if (!is_array($Data)) { $Data = [$Data]; } // Check to see if we are storing two versions of the data. if (($InsertUserID = self::logValue($Data, 'Log_InsertUserID')) === null) { $InsertUserID = Gdn::session()->UserID; } if (($InsertIPAddress = self::logValue($Data, 'Log_InsertIPAddress')) == null) { $InsertIPAddress = Gdn::request()->ipAddress(); } // Do some known translations for the parent record ID. if (($ParentRecordID = self::logValue($Data, 'ParentRecordID')) === null) { switch ($RecordType) { case 'Activity': $ParentRecordID = self::logValue($Data, 'CommentActivityID', 'CommentActivityID'); break; case 'Comment': $ParentRecordID = self::logValue($Data, 'DiscussionID', 'DiscussionID'); break; } } // Get the row information from the data or determine it based on the type. $LogRow = ['Operation' => $Operation, 'RecordType' => $RecordType, 'RecordID' => self::logValue($Data, 'RecordID', $RecordType . 'ID'), 'RecordUserID' => self::logValue($Data, 'RecordUserID', 'UpdateUserID', 'InsertUserID'), 'RecordIPAddress' => self::logValue($Data, 'RecordIPAddress', 'LastIPAddress', 'InsertIPAddress'), 'RecordDate' => self::logValue($Data, 'RecordDate', 'DateUpdated', 'DateInserted'), 'InsertUserID' => $InsertUserID, 'InsertIPAddress' => $InsertIPAddress, 'DateInserted' => Gdn_Format::toDateTime(), 'ParentRecordID' => $ParentRecordID, 'CategoryID' => self::logValue($Data, 'CategoryID'), 'OtherUserIDs' => implode(',', val('OtherUserIDs', $Options, [])), 'Data' => dbencode($Data)]; if ($LogRow['RecordDate'] == null) { $LogRow['RecordDate'] = Gdn_Format::toDateTime(); } $GroupBy = val('GroupBy', $Options); // Make sure we aren't grouping by null values. if (is_array($GroupBy)) { foreach ($GroupBy as $Name) { if (val($Name, $LogRow) === null) { $GroupBy = false; break; } } } if ($GroupBy) { $GroupBy[] = 'Operation'; $GroupBy[] = 'RecordType'; // Check to see if there is a record already logged here. $Where = array_combine($GroupBy, arrayTranslate($LogRow, $GroupBy)); $LogRow2 = Gdn::sql()->getWhere('Log', $Where)->firstRow(DATASET_TYPE_ARRAY); if ($LogRow2) { $LogID = $LogRow2['LogID']; $Set = []; $Data = array_merge(dbdecode($LogRow2['Data']), $Data); $OtherUserIDs = explode(',', $LogRow2['OtherUserIDs']); if (!is_array($OtherUserIDs)) { $OtherUserIDs = []; } if (!$LogRow2['InsertUserID']) { $Set['InsertUserID'] = $InsertUserID; } elseif ($InsertUserID != $LogRow2['InsertUserID'] && !in_array($InsertUserID, $OtherUserIDs)) { $OtherUserIDs[] = $InsertUserID; } if (array_key_exists('OtherUserIDs', $Options)) { $OtherUserIDs = array_merge($OtherUserIDs, $Options['OtherUserIDs']); $OtherUserIDs = array_unique($OtherUserIDs); $OtherUserIDs = array_diff($OtherUserIDs, [$InsertUserID]); $Count = count($OtherUserIDs) + 1; } else { $Count = (int) $LogRow2['CountGroup'] + 1; } $Set['OtherUserIDs'] = implode(',', $OtherUserIDs); $Set['CountGroup'] = $Count; $Set['Data'] = dbencode($Data); $Set['DateUpdated'] = Gdn_Format::toDateTime(); if (self::$transactionID > 0) { $Set['TransactionLogID'] = self::$transactionID; } elseif (self::$transactionID === true) { if ($LogRow2['TransactionLogID']) { self::$transactionID = $LogRow2['TransactionLogID']; } else { self::$transactionID = $LogID; $Set['TransactionLogID'] = $LogID; } } Gdn::sql()->put('Log', $Set, ['LogID' => $LogID]); } else { $L = self::instance(); $L->EventArguments['Log'] =& $LogRow; $L->fireEvent('BeforeInsert'); if (self::$transactionID > 0) { $LogRow['TransactionLogID'] = self::$transactionID; } $LogID = Gdn::sql()->insert('Log', $LogRow); if (self::$transactionID === true) { // A new transaction was started and needs to assigned. self::$transactionID = $LogID; Gdn::sql()->put('Log', ['TransactionLogID' => $LogID], ['LogID' => $LogID]); } $L->EventArguments['LogID'] = $LogID; $L->fireEvent('AfterInsert'); } } else { if (self::$transactionID > 0) { $LogRow['TransactionLogID'] = self::$transactionID; } // Insert the log entry. $L = self::instance(); $L->EventArguments['Log'] =& $LogRow; $L->fireEvent('BeforeInsert'); $LogID = Gdn::sql()->insert('Log', $LogRow); if (self::$transactionID === true) { // A new transaction was started and needs to assigned. self::$transactionID = $LogID; Gdn::sql()->put('Log', ['TransactionLogID' => $LogID], ['LogID' => $LogID]); } $L->EventArguments['LogID'] = $LogID; $L->fireEvent('AfterInsert'); } return $LogID; }