Commit | Line | Data |
---|---|---|
9544b6b4 | 1 | <?php |
fea86294 | 2 | |
9544b6b4 | 3 | namespace wcf\data\conversation; |
fea86294 | 4 | |
6579145d | 5 | use wcf\data\conversation\label\ConversationLabel; |
6579145d | 6 | use wcf\data\conversation\label\ConversationLabelList; |
95ed3132 | 7 | use wcf\system\cache\runtime\UserProfileRuntimeCache; |
02b42a61 | 8 | use wcf\system\database\util\PreparedStatementConditionBuilder; |
9544b6b4 MW |
9 | use wcf\system\WCF; |
10 | ||
11 | /** | |
12 | * Represents a list of conversations. | |
fea86294 TD |
13 | * |
14 | * @author Marcel Werk | |
15 | * @copyright 2001-2019 WoltLab GmbH | |
16 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
17 | * @package WoltLabSuite\Core\Data\Conversation | |
18 | * | |
19 | * @method ViewableConversation current() | |
20 | * @method ViewableConversation[] getObjects() | |
21 | * @method ViewableConversation|null search($objectID) | |
22 | * @property ViewableConversation[] $objects | |
9544b6b4 | 23 | */ |
fea86294 TD |
24 | class UserConversationList extends ConversationList |
25 | { | |
26 | /** | |
27 | * list of available filters | |
28 | * @var string[] | |
29 | */ | |
30 | public static $availableFilters = ['hidden', 'draft', 'outbox']; | |
31 | ||
32 | /** | |
33 | * active filter | |
34 | * @var string | |
35 | */ | |
36 | public $filter = ''; | |
37 | ||
38 | /** | |
39 | * label list object | |
40 | * @var ConversationLabelList | |
41 | */ | |
42 | public $labelList; | |
43 | ||
44 | /** | |
45 | * @inheritDoc | |
46 | */ | |
47 | public $decoratorClassName = ViewableConversation::class; | |
48 | ||
49 | /** | |
50 | * Creates a new UserConversationList | |
51 | * | |
c85e9df8 | 52 | * @param int $userID |
fea86294 | 53 | * @param string $filter |
c85e9df8 | 54 | * @param int $labelID |
fea86294 TD |
55 | */ |
56 | public function __construct($userID, $filter = '', $labelID = 0) | |
57 | { | |
58 | parent::__construct(); | |
59 | ||
60 | $this->filter = $filter; | |
61 | ||
62 | // apply filter | |
63 | if ($this->filter === 'draft') { | |
64 | $this->getConditionBuilder()->add('conversation.userID = ?', [$userID]); | |
65 | $this->getConditionBuilder()->add('conversation.isDraft = 1'); | |
66 | } else { | |
67 | $this->getConditionBuilder()->add('conversation_to_user.participantID = ?', [$userID]); | |
68 | $this->getConditionBuilder() | |
69 | ->add('conversation_to_user.hideConversation = ?', [$this->filter == 'hidden' ? 1 : 0]); | |
6124508f | 70 | $this->sqlConditionJoins = "LEFT JOIN wcf" . WCF_N . "_conversation conversation ON conversation.conversationID = conversation_to_user.conversationID"; |
fea86294 TD |
71 | if ($this->filter == 'outbox') { |
72 | $this->getConditionBuilder()->add('conversation.userID = ?', [$userID]); | |
73 | } | |
74 | } | |
75 | ||
76 | // filter by label id | |
77 | if ($labelID) { | |
78 | $this->getConditionBuilder()->add("conversation.conversationID IN ( | |
8fbd8b01 MS |
79 | SELECT conversationID |
80 | FROM wcf" . WCF_N . "_conversation_label_to_object | |
81 | WHERE labelID = ? | |
82 | )", [$labelID]); | |
fea86294 TD |
83 | } |
84 | ||
85 | // own posts | |
86 | $this->sqlSelects = "DISTINCT conversation_message.userID AS ownPosts"; | |
6124508f | 87 | $this->sqlJoins = "LEFT JOIN wcf" . WCF_N . "_conversation_message conversation_message ON conversation_message.conversationID = conversation.conversationID AND conversation_message.userID = " . $userID; |
fea86294 TD |
88 | |
89 | // user info | |
90 | if (!empty($this->sqlSelects)) { | |
91 | $this->sqlSelects .= ','; | |
92 | } | |
93 | $this->sqlSelects .= "conversation_to_user.*"; | |
6124508f | 94 | $this->sqlJoins .= "LEFT JOIN wcf" . WCF_N . "_conversation_to_user conversation_to_user ON conversation_to_user.participantID = " . $userID . " AND conversation_to_user.conversationID = conversation.conversationID"; |
fea86294 TD |
95 | |
96 | if ($this->filter !== 'draft') { | |
97 | $this->sqlSelects .= ", conversation.*, CASE WHEN conversation_to_user.leftAt <> 0 THEN conversation_to_user.leftAt ELSE conversation.lastPostTime END AS lastPostTime"; | |
98 | // this avoids appending `conversation.*` to the SELECT list | |
99 | $this->useQualifiedShorthand = false; | |
100 | } | |
101 | } | |
102 | ||
103 | /** | |
104 | * Sets the label list of the user the conversations belong to. | |
105 | * | |
106 | * @param ConversationLabelList $labelList | |
107 | */ | |
108 | public function setLabelList(ConversationLabelList $labelList) | |
109 | { | |
110 | $this->labelList = $labelList; | |
111 | } | |
112 | ||
113 | /** | |
114 | * @inheritDoc | |
115 | */ | |
116 | public function countObjects() | |
117 | { | |
118 | if ($this->filter == 'draft') { | |
119 | return parent::countObjects(); | |
120 | } | |
121 | ||
8fbd8b01 MS |
122 | $sql = "SELECT COUNT(*) AS count |
123 | FROM wcf" . WCF_N . "_conversation_to_user conversation_to_user | |
124 | " . $this->sqlConditionJoins . " | |
ad5cae90 | 125 | " . $this->getConditionBuilder(); |
fea86294 TD |
126 | $statement = WCF::getDB()->prepareStatement($sql); |
127 | $statement->execute($this->getConditionBuilder()->getParameters()); | |
128 | $row = $statement->fetchArray(); | |
129 | ||
130 | return $row['count']; | |
131 | } | |
132 | ||
133 | /** | |
134 | * @inheritDoc | |
135 | */ | |
136 | public function readObjectIDs() | |
137 | { | |
138 | if ($this->filter === 'draft') { | |
139 | parent::readObjectIDs(); | |
140 | ||
141 | return; | |
142 | } | |
143 | ||
8fbd8b01 MS |
144 | $sql = "SELECT conversation_to_user.conversationID AS objectID |
145 | FROM wcf" . WCF_N . "_conversation_to_user conversation_to_user | |
146 | " . $this->sqlConditionJoins . " | |
ad5cae90 | 147 | " . $this->getConditionBuilder() . " |
8fbd8b01 | 148 | " . (!empty($this->sqlOrderBy) ? "ORDER BY " . $this->sqlOrderBy : ''); |
fea86294 TD |
149 | $statement = WCF::getDB()->prepareStatement($sql, $this->sqlLimit, $this->sqlOffset); |
150 | $statement->execute($this->getConditionBuilder()->getParameters()); | |
151 | $this->objectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); | |
152 | } | |
153 | ||
154 | /** | |
155 | * @inheritDoc | |
156 | */ | |
157 | public function readObjects() | |
158 | { | |
159 | if ($this->objectIDs === null) { | |
160 | $this->readObjectIDs(); | |
161 | } | |
162 | ||
163 | parent::readObjects(); | |
164 | ||
165 | if (!empty($this->objects)) { | |
166 | $messageIDs = []; | |
167 | foreach ($this->objects as $conversation) { | |
168 | if ($conversation->lastMessageID) { | |
169 | $messageIDs[] = $conversation->lastMessageID; | |
170 | } | |
171 | } | |
172 | if (!empty($messageIDs)) { | |
173 | $conditions = new PreparedStatementConditionBuilder(); | |
174 | $conditions->add("messageID IN (?)", [$messageIDs]); | |
175 | $sql = "SELECT messageID, userID, username, time | |
8fbd8b01 MS |
176 | FROM wcf" . WCF_N . "_conversation_message |
177 | " . $conditions; | |
fea86294 TD |
178 | $statement = WCF::getDB()->prepareStatement($sql); |
179 | $statement->execute($conditions->getParameters()); | |
180 | $messageData = []; | |
181 | while ($row = $statement->fetchArray()) { | |
182 | $messageData[$row['messageID']] = $row; | |
183 | } | |
184 | ||
185 | foreach ($this->objects as $conversation) { | |
186 | if ($conversation->lastMessageID) { | |
187 | $data = (isset($messageData[$conversation->lastMessageID])) ? $messageData[$conversation->lastMessageID] : null; | |
188 | if ($data !== null) { | |
189 | $conversation->setLastMessage($data['userID'], $data['username'], $data['time']); | |
190 | } else { | |
191 | $conversation->setLastMessage(null, '', 0); | |
192 | } | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | $labels = $this->loadLabelAssignments(); | |
198 | ||
199 | $userIDs = []; | |
200 | foreach ($this->objects as $conversationID => $conversation) { | |
201 | if (isset($labels[$conversationID])) { | |
202 | foreach ($labels[$conversationID] as $label) { | |
203 | $conversation->assignLabel($label); | |
204 | } | |
205 | } | |
206 | ||
207 | if ($conversation->userID) { | |
208 | $userIDs[] = $conversation->userID; | |
209 | } | |
210 | if ($conversation->lastPosterID) { | |
211 | $userIDs[] = $conversation->lastPosterID; | |
212 | } | |
213 | } | |
214 | ||
215 | if (!empty($userIDs)) { | |
216 | UserProfileRuntimeCache::getInstance()->cacheObjectIDs($userIDs); | |
217 | } | |
218 | } | |
219 | } | |
220 | ||
221 | /** | |
222 | * Returns a list of conversation labels. | |
223 | * | |
224 | * @return ConversationLabel[] | |
225 | */ | |
226 | protected function getLabels() | |
227 | { | |
228 | if ($this->labelList === null) { | |
229 | $this->labelList = ConversationLabel::getLabelsByUser(); | |
230 | } | |
231 | ||
232 | return $this->labelList->getObjects(); | |
233 | } | |
234 | ||
235 | /** | |
236 | * Returns label assignments per conversation. | |
237 | * | |
238 | * @return ConversationLabel[][] | |
239 | */ | |
240 | protected function loadLabelAssignments() | |
241 | { | |
242 | $labels = $this->getLabels(); | |
243 | if (empty($labels)) { | |
244 | return []; | |
245 | } | |
246 | ||
247 | $conditions = new PreparedStatementConditionBuilder(); | |
248 | $conditions->add("conversationID IN (?)", [\array_keys($this->objects)]); | |
249 | $conditions->add("labelID IN (?)", [\array_keys($labels)]); | |
250 | ||
8fbd8b01 MS |
251 | $sql = "SELECT labelID, conversationID |
252 | FROM wcf" . WCF_N . "_conversation_label_to_object | |
253 | " . $conditions; | |
fea86294 TD |
254 | $statement = WCF::getDB()->prepareStatement($sql); |
255 | $statement->execute($conditions->getParameters()); | |
256 | $data = []; | |
257 | while ($row = $statement->fetchArray()) { | |
258 | if (!isset($data[$row['conversationID']])) { | |
259 | $data[$row['conversationID']] = []; | |
260 | } | |
261 | ||
262 | $data[$row['conversationID']][$row['labelID']] = $labels[$row['labelID']]; | |
263 | } | |
264 | ||
265 | return $data; | |
266 | } | |
61f754e0 | 267 | } |