getStringOrNull(0), action: $result->getString(1), params: json_decode($result->getString(2)), created: $result->getInteger(3), address: $result->isNull(4) ? '::1' : $result->getString(4), // apparently this being NULL is possible? country: $result->getString(5), ); } public function hasUserId(): bool { return $this->userId !== null; } public function getUserId(): ?string { return $this->userId; } public function getAction(): string { return $this->action; } public function getParams(): array { return $this->params; } public function getCreatedTime(): int { return $this->created; } public function getCreatedAt(): DateTime { return DateTime::fromUnixTimeSeconds($this->created); } public function getRemoteAddressRaw(): string { return $this->address; } public function getRemoteAddress(): IPAddress { return IPAddress::parse($this->address); } public function getCountryCode(): string { return $this->country; } public function getFormatted(): string { if(array_key_exists($this->action, self::FORMATS)) try { return vsprintf(self::FORMATS[$this->action], $this->params); } catch(ValueError $ex) {} return sprintf('%s(%s)', $this->action, implode(', ', $this->params)); } public const FORMATS = [ 'PERSONAL_EMAIL_CHANGE' => 'Changed e-mail address to %s.', 'PERSONAL_PASSWORD_CHANGE' => 'Changed account password.', 'PERSONAL_SESSION_DESTROY' => 'Ended session #%d.', 'PERSONAL_SESSION_DESTROY_ALL' => 'Ended all personal sessions.', 'PERSONAL_DATA_DOWNLOAD' => 'Downloaded archive of account data.', 'PASSWORD_RESET' => 'Successfully used the password reset form to change password.', 'CHANGELOG_ENTRY_CREATE' => 'Created a new changelog entry #%d.', 'CHANGELOG_ENTRY_EDIT' => 'Edited changelog entry #%d.', 'CHANGELOG_TAG_ADD' => 'Added tag #%2$d to changelog entry #%1$d.', 'CHANGELOG_TAG_REMOVE' => 'Removed tag #%2$d from changelog entry #%1$d.', 'CHANGELOG_TAG_CREATE' => 'Created new changelog tag #%d.', 'CHANGELOG_TAG_EDIT' => 'Edited changelog tag #%d.', 'CHANGELOG_TAG_DELETE' => 'Deleted changelog tag #%d.', 'CHANGELOG_ACTION_CREATE' => 'Created new changelog action #%d.', 'CHANGELOG_ACTION_EDIT' => 'Edited changelog action #%d.', 'COMMENT_ENTRY_DELETE' => 'Deleted comment #%d.', 'COMMENT_ENTRY_DELETE_MOD' => 'Deleted comment #%d by user #%d %s.', 'COMMENT_ENTRY_RESTORE' => 'Restored comment #%d by user #%d %s.', 'NEWS_POST_CREATE' => 'Created news post #%d.', 'NEWS_POST_EDIT' => 'Edited news post #%d.', 'NEWS_POST_DELETE' => 'Deleted news post #%d.', 'NEWS_CATEGORY_CREATE' => 'Created news category #%d.', 'NEWS_CATEGORY_EDIT' => 'Edited news category #%d.', 'NEWS_CATEGORY_DELETE' => 'Deleted news category #%d.', 'FORUM_POST_EDIT' => 'Edited forum post #%d.', 'FORUM_POST_DELETE' => 'Deleted forum post #%d.', 'FORUM_POST_RESTORE' => 'Restored forum post #%d.', 'FORUM_POST_NUKE' => 'Nuked forum post #%d.', 'FORUM_TOPIC_DELETE' => 'Deleted forum topic #%d.', 'FORUM_TOPIC_RESTORE' => 'Restored forum topic #%d.', 'FORUM_TOPIC_NUKE' => 'Nuked forum topic #%d.', 'FORUM_TOPIC_BUMP' => 'Manually bumped forum topic #%d.', 'FORUM_TOPIC_LOCK' => 'Locked forum topic #%d.', 'FORUM_TOPIC_UNLOCK' => 'Unlocked forum topic #%d.', 'FORUM_TOPIC_REDIR_CREATE' => 'Created redirect for topic #%d.', 'FORUM_TOPIC_REDIR_REMOVE' => 'Removed redirect for topic #%d.', 'CONFIG_CREATE' => 'Created config value with name "%s".', 'CONFIG_UPDATE' => 'Updated config value with name "%s".', 'CONFIG_DELETE' => 'Deleted config value with name "%s".', 'EMOTICON_CREATE' => 'Created emoticon #%s.', 'EMOTICON_EDIT' => 'Edited emoticon #%s.', 'EMOTICON_DELETE' => 'Deleted emoticon #%s.', 'EMOTICON_ORDER' => 'Changed order of emoticon #%s.', 'EMOTICON_ALIAS' => 'Added alias "%2$s" to emoticon #%1$s.', 'MOD_NOTE_CREATE' => 'Added moderator note #%d to user #%d.', 'MOD_NOTE_UPDATE' => 'Edited moderator note #%d on user #%d.', 'MOD_NOTE_DELETE' => 'Removed moderator note #%d from user #%d.', 'BAN_CREATE' => 'Added ban #%d to user #%d.', 'BAN_DELETE' => 'Removed ban #%d from user #%d.', 'WARN_CREATE' => 'Added warning #%d to user #%d.', 'WARN_DELETE' => 'Removed warning #%d from user #%d.', 'ROLE_CREATE' => 'Created role #%d.', 'ROLE_UPDATE' => 'Updated role #%d.', 'USER_IMPERSONATE' => 'Impersonated user #%d %s.', ]; }