Apply PSR-12 code style (#145)
[GitHub/WoltLab/com.woltlab.wcf.conversation.git] / files / lib / system / conversation / ConversationHandler.class.php
1 <?php
2
3 namespace wcf\system\conversation;
4
5 use wcf\system\database\util\PreparedStatementConditionBuilder;
6 use wcf\system\exception\NamedUserException;
7 use wcf\system\exception\PermissionDeniedException;
8 use wcf\system\flood\FloodControl;
9 use wcf\system\SingletonFactory;
10 use wcf\system\user\storage\UserStorageHandler;
11 use wcf\system\WCF;
12
13 /**
14 * Handles the number of conversations and unread conversations of the active user.
15 *
16 * @author Marcel Werk
17 * @copyright 2001-2019 WoltLab GmbH
18 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
19 * @package WoltLabSuite\Core\System\Conversation
20 */
21 class ConversationHandler extends SingletonFactory
22 {
23 /**
24 * number of unread conversations
25 * @var integer[]
26 */
27 protected $unreadConversationCount = [];
28
29 /**
30 * number of conversations
31 * @var integer[]
32 */
33 protected $conversationCount = [];
34
35 /**
36 * Returns the number of unread conversations for given user.
37 *
38 * @param integer $userID
39 * @param boolean $skipCache
40 * @return integer
41 */
42 public function getUnreadConversationCount($userID = null, $skipCache = false)
43 {
44 if ($userID === null) {
45 $userID = WCF::getUser()->userID;
46 }
47
48 if (!isset($this->unreadConversationCount[$userID]) || $skipCache) {
49 $this->unreadConversationCount[$userID] = 0;
50
51 // load storage data
52 UserStorageHandler::getInstance()->loadStorage([$userID]);
53
54 // get ids
55 $data = UserStorageHandler::getInstance()->getStorage([$userID], 'unreadConversationCount');
56
57 // cache does not exist or is outdated
58 if ($data[$userID] === null || $skipCache) {
59 $conditionBuilder = new PreparedStatementConditionBuilder();
60 $conditionBuilder->add('conversation.conversationID = conversation_to_user.conversationID');
61 $conditionBuilder->add('conversation_to_user.participantID = ?', [$userID]);
62 $conditionBuilder->add('conversation_to_user.hideConversation = 0');
63 $conditionBuilder->add('conversation_to_user.lastVisitTime < conversation.lastPostTime');
64 $conditionBuilder->add('conversation_to_user.leftAt = 0');
65
66 $sql = "SELECT COUNT(*) AS count
67 FROM wcf" . WCF_N . "_conversation_to_user conversation_to_user,
68 wcf" . WCF_N . "_conversation conversation
69 " . $conditionBuilder;
70 $statement = WCF::getDB()->prepareStatement($sql);
71 $statement->execute($conditionBuilder->getParameters());
72 $row = $statement->fetchArray();
73 $this->unreadConversationCount[$userID] = $row['count'];
74
75 // update storage data
76 UserStorageHandler::getInstance()->update(
77 $userID,
78 'unreadConversationCount',
79 \serialize($this->unreadConversationCount[$userID])
80 );
81 } else {
82 $this->unreadConversationCount[$userID] = \unserialize($data[$userID]);
83 }
84 }
85
86 return $this->unreadConversationCount[$userID];
87 }
88
89 /**
90 * Returns the number of conversations for given user.
91 *
92 * @param integer $userID
93 * @return integer
94 */
95 public function getConversationCount($userID = null)
96 {
97 if ($userID === null) {
98 $userID = WCF::getUser()->userID;
99 }
100
101 if (!isset($this->conversationCount[$userID])) {
102 $this->conversationCount[$userID] = 0;
103
104 // load storage data
105 UserStorageHandler::getInstance()->loadStorage([$userID]);
106
107 // get ids
108 $data = UserStorageHandler::getInstance()->getStorage([$userID], 'conversationCount');
109
110 // cache does not exist or is outdated
111 if ($data[$userID] === null) {
112 $conditionBuilder1 = new PreparedStatementConditionBuilder();
113 $conditionBuilder1->add('conversation_to_user.participantID = ?', [$userID]);
114 $conditionBuilder1->add('conversation_to_user.hideConversation IN (0,1)');
115 $conditionBuilder2 = new PreparedStatementConditionBuilder();
116 $conditionBuilder2->add('conversation.userID = ?', [$userID]);
117 $conditionBuilder2->add('conversation.isDraft = 1');
118
119 $sql = "SELECT (SELECT COUNT(*)
120 FROM wcf" . WCF_N . "_conversation_to_user conversation_to_user
121 " . $conditionBuilder1->__toString() . ")
122 +
123 (SELECT COUNT(*)
124 FROM wcf" . WCF_N . "_conversation conversation
125 " . $conditionBuilder2->__toString() . ") AS count";
126 $statement = WCF::getDB()->prepareStatement($sql);
127 $statement->execute(\array_merge(
128 $conditionBuilder1->getParameters(),
129 $conditionBuilder2->getParameters()
130 ));
131 $row = $statement->fetchArray();
132 $this->conversationCount[$userID] = $row['count'];
133
134 // update storage data
135 UserStorageHandler::getInstance()->update(
136 $userID,
137 'conversationCount',
138 \serialize($this->conversationCount[$userID])
139 );
140 } else {
141 $this->conversationCount[$userID] = \unserialize($data[$userID]);
142 }
143 }
144
145 return $this->conversationCount[$userID];
146 }
147
148 /**
149 * Enforces the flood control.
150 */
151 public function enforceFloodControl()
152 {
153 $limit = WCF::getSession()->getPermission('user.conversation.maxStartedConversationsPer24Hours');
154 if ($limit == -1) {
155 return;
156 } elseif ($limit == 0) {
157 // `0` is not a valid value, but the interface logic does not permit and exclusion
158 // while also allowing the special value `-1`. Therefore, `0` behaves like the
159 // 'canStartConversation' permission added in WoltLab Suite 5.2.
160 throw new PermissionDeniedException();
161 }
162
163 $count = FloodControl::getInstance()->countContent('com.woltlab.wcf.conversation', new \DateInterval('P1D'));
164 if ($count['count'] >= $limit) {
165 throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.conversation.error.floodControl', [
166 'limit' => $count['count'],
167 'notBefore' => $count['earliestTime'] + 86400,
168 ]));
169 }
170 }
171 }