1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Part of the files dealing with preparing the content for display posts |
||
5 | * via callbacks (Display, PM, Search). |
||
6 | * |
||
7 | * @package ElkArte Forum |
||
8 | * @copyright ElkArte Forum contributors |
||
9 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
10 | * |
||
11 | * @version 2.0 dev |
||
12 | * |
||
13 | */ |
||
14 | |||
15 | namespace ElkArte\MessagesCallback; |
||
16 | |||
17 | use ElkArte\Helper\ValuesContainer; |
||
18 | use ElkArte\MembersList; |
||
19 | use ElkArte\MessagesCallback\BodyParser\BodyParserInterface; |
||
20 | use ElkArte\EventManager; |
||
21 | |||
22 | /** |
||
23 | * Class Renderer |
||
24 | * |
||
25 | * The common skeleton to display content via callback. |
||
26 | * Classes extending this abstract should declare two constants: |
||
27 | * - BEFORE_PREPARE_HOOK |
||
28 | * - CONTEXT_HOOK |
||
29 | * that will be strings used as hook names. |
||
30 | * |
||
31 | * @package ElkArte\MessagesCallback |
||
32 | */ |
||
33 | abstract class Renderer |
||
34 | { |
||
35 | /** @var Object The database object */ |
||
36 | protected $_db; |
||
37 | |||
38 | /** @var ValuesContainer Some options */ |
||
39 | protected $_options; |
||
40 | |||
41 | /** @var int Position tracker, to know where we are into the request */ |
||
42 | protected $_counter = 0; |
||
43 | |||
44 | /** @var bool Should we show the signature of this message? */ |
||
45 | protected $_signature_shown; |
||
46 | |||
47 | /** @var array The current message being prepared */ |
||
48 | protected $_this_message; |
||
49 | |||
50 | /** @var ValuesContainer Index mapping, to normalize certain indexes across requests */ |
||
51 | protected $_idx_mapper = []; |
||
52 | |||
53 | /** |
||
54 | * Renderer constructor, starts everything. |
||
55 | * |
||
56 | * @param Object $_dbRequest |
||
57 | * @param Object $user |
||
58 | * @param BodyParserInterface $_bodyParser |
||
59 | * @param ValuesContainer $opt |
||
60 | */ |
||
61 | public function __construct(protected $_dbRequest, protected $user, protected $_bodyParser, $opt = null) |
||
62 | { |
||
63 | $this->_db = database(); |
||
64 | $this->_idx_mapper = new ValuesContainer([ |
||
65 | 'id_msg' => 'id_msg', |
||
66 | 'id_member' => 'id_member', |
||
67 | 'name' => 'poster_name', |
||
68 | 'time' => 'poster_time', |
||
69 | ]); |
||
70 | |||
71 | // opt: |
||
72 | // icon_sources |
||
73 | // show_signatures |
||
74 | $this->_options = $opt ?? new ValuesContainer(); |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * The main part: reads the DB resource and returns the complex array |
||
79 | * for a certain message. |
||
80 | * |
||
81 | * @param bool $reset |
||
82 | * |
||
83 | * @return bool|array |
||
84 | */ |
||
85 | public function getContext($reset = false) |
||
86 | { |
||
87 | global $txt, $context; |
||
88 | |||
89 | // If the query returned false, bail. |
||
90 | if (!is_object($this->_dbRequest) || $this->_dbRequest->hasResults() === false) |
||
91 | { |
||
92 | return false; |
||
93 | } |
||
94 | |||
95 | // Remember which message this is. (ie. reply #83) |
||
96 | if ($this->_counter === 0 || $reset) |
||
97 | { |
||
98 | $this->_counter = empty($context['start']) ? 0 : $context['start']; |
||
99 | } |
||
100 | |||
101 | // Start from the beginning, or get the next message |
||
102 | $this->_currentContext($reset); |
||
103 | |||
104 | if (empty($this->_this_message)) |
||
105 | { |
||
106 | 4 | return false; |
|
107 | } |
||
108 | 4 | ||
109 | 4 | // If you're a lazy bum, you probably didn't give a subject... |
|
110 | 4 | $this->_this_message['subject'] = $this->_this_message['subject'] !== '' ? $this->_this_message['subject'] : $txt['no_subject']; |
|
111 | 4 | ||
112 | 4 | $this->_setupPermissions(); |
|
113 | 4 | ||
114 | $id_member = $this->_this_message[$this->_idx_mapper->id_member]; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
115 | $member_context = MembersList::get($id_member); |
||
116 | $member_context->loadContext(); |
||
117 | |||
118 | // If it couldn't load, or the user was a guest.... someday may be done with a guest table. |
||
119 | if ($member_context->isEmpty()) |
||
120 | { |
||
121 | $this->_adjustGuestContext($member_context); |
||
122 | 4 | } |
|
123 | 4 | else |
|
124 | { |
||
125 | $this->_adjustMemberContext($member_context); |
||
126 | } |
||
127 | |||
128 | $this->_adjustAllMembers($member_context); |
||
129 | |||
130 | // Do the censor thang. |
||
131 | $this->_this_message['subject'] = censor($this->_this_message['subject']); |
||
132 | |||
133 | 2 | // Run BBC interpreter on the message. |
|
134 | $this->_this_message['body'] = $this->_bodyParser->prepare($this->_this_message['body'], $this->_this_message['smileys_enabled']); |
||
135 | 2 | ||
136 | 2 | call_integration_hook(static::BEFORE_PREPARE_HOOK, [&$this->_this_message]); |
|
0 ignored issues
–
show
|
|||
137 | |||
138 | // Compose the memory eat- I mean message array. |
||
139 | 2 | $output = $this->_buildOutputArray(); |
|
140 | |||
141 | call_integration_hook(static::CONTEXT_HOOK, [&$output, &$this->_this_message, $this->_counter]); |
||
0 ignored issues
–
show
|
|||
142 | |||
143 | $output['classes'] = implode(' ', $output['classes']); |
||
144 | |||
145 | 2 | $this->_counter++; |
|
146 | |||
147 | return $output; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | 2 | * This function receives a request handle and attempts to retrieve the next result. |
|
152 | * |
||
153 | * What it does: |
||
154 | * |
||
155 | * - It is used by the controller callbacks from the template, such as |
||
156 | * posts in topic display page, posts search results page, or personal messages. |
||
157 | * |
||
158 | 2 | * @param bool $reset |
|
159 | * |
||
160 | * @return bool |
||
161 | 2 | */ |
|
162 | protected function _currentContext($reset = false) |
||
163 | { |
||
164 | // Start from the beginning... |
||
165 | if ($reset) |
||
166 | { |
||
167 | 2 | $this->_dbRequest->data_seek(0); |
|
168 | } |
||
169 | 2 | ||
170 | // If the query has already returned false, get out of here |
||
171 | 2 | if ($this->_dbRequest->hasResults() === false) |
|
172 | 2 | { |
|
173 | 2 | return false; |
|
174 | } |
||
175 | |||
176 | 2 | // Attempt to get the next message. |
|
177 | $this->_this_message = $this->_dbRequest->fetch_assoc(); |
||
178 | 2 | if (!$this->_this_message) |
|
179 | { |
||
180 | $this->_dbRequest->free_result(); |
||
181 | |||
182 | return false; |
||
183 | } |
||
184 | 2 | ||
185 | return true; |
||
186 | } |
||
187 | 2 | ||
188 | /** |
||
189 | * Utility function, it shall be implemented by the extending class. |
||
190 | 2 | * Run just before \ElkArte\MembersList::get()->loadContext is executed. |
|
191 | */ |
||
192 | 2 | abstract protected function _setupPermissions(); |
|
193 | |||
194 | /** |
||
195 | 2 | * Utility function, it can be overridden to alter something just after the |
|
196 | * members' data has been loaded from the database. |
||
197 | 2 | * Run only if member exists failed. |
|
198 | * |
||
199 | 2 | * @param ValuesContainer $member_context |
|
200 | */ |
||
201 | 2 | protected function _adjustGuestContext($member_context) |
|
202 | { |
||
203 | 2 | global $txt; |
|
204 | |||
205 | // Notice this information isn't used anywhere else.... |
||
206 | $member_context['name'] = $this->_this_message[$this->_idx_mapper->name]; |
||
0 ignored issues
–
show
The property
name does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
207 | $member_context['id'] = 0; |
||
208 | $member_context['group'] = $txt['guest_title']; |
||
209 | $member_context['link'] = $this->_this_message[$this->_idx_mapper->name]; |
||
210 | $member_context['email'] = $this->_this_message['poster_email'] ?? ''; |
||
211 | $member_context['show_email'] = showEmailAddress(0); |
||
212 | $member_context['is_guest'] = true; |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Utility function, it can be overridden to alter something just after the |
||
217 | * members data have been set. |
||
218 | 2 | * Run only if member doesn't exist succeeded. |
|
219 | * |
||
220 | * @param ValuesContainer $member_context |
||
221 | 2 | */ |
|
222 | protected function _adjustMemberContext($member_context) |
||
223 | { |
||
224 | global $context, $modSettings; |
||
225 | |||
226 | $member_id = $this->_this_message[$this->_idx_mapper->id_member]; |
||
0 ignored issues
–
show
The property
id_member does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
227 | 2 | ||
228 | $member_context['can_view_profile'] = allowedTo('profile_view_any') || ($member_id == $this->user->id && allowedTo('profile_view_own')); |
||
229 | $member_context['is_topic_starter'] = $member_id == $context['topic_starter_id']; |
||
230 | $member_context['can_see_warning'] = !isset($context['disabled_fields']['warning_status']) && $member_context['warning_status'] && (!empty($context['user']['can_mod']) || ($this->user->is_guest === false && !empty($modSettings['warning_show']) && ($modSettings['warning_show'] > 1 || $member_id == $this->user->id))); |
||
231 | |||
232 | if ($this->_options->show_signatures === 1) |
||
0 ignored issues
–
show
The property
show_signatures does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
233 | 2 | { |
|
234 | 2 | if (empty($this->_signature_shown[$member_id])) |
|
235 | { |
||
236 | $this->_signature_shown[$member_id] = true; |
||
237 | } |
||
238 | else |
||
239 | { |
||
240 | $member_context['signature'] = ''; |
||
241 | 2 | } |
|
242 | } |
||
243 | elseif ($this->_options->show_signatures === 2) |
||
244 | { |
||
245 | $member_context['signature'] = ''; |
||
246 | } |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Utility function, it can be overridden to alter something just after either |
||
251 | * the members or the guests data have been loaded from the database. |
||
252 | * Run both if the member exists or not. |
||
253 | * |
||
254 | * @param ValuesContainer $member_context |
||
255 | * @return mixed |
||
256 | */ |
||
257 | 2 | abstract protected function _adjustAllMembers($member_context); |
|
258 | |||
259 | 2 | /** |
|
260 | * The most important bit that differentiate the various implementations. |
||
261 | * It is supposed to prepare the $output array with all the information |
||
262 | 2 | * needed by the template to properly render the message. |
|
263 | 2 | * |
|
264 | 2 | * The method of the class extending this abstract may run |
|
265 | 2 | * parent::_buildOutputArray() |
|
266 | 2 | * as first statement in order to have a starting point and |
|
267 | 2 | * some commonly used content for the array. |
|
268 | 2 | * |
|
269 | 2 | * @return array |
|
270 | */ |
||
271 | protected function _buildOutputArray() |
||
272 | { |
||
273 | return [ |
||
274 | 'id' => $this->_this_message[$this->_idx_mapper->id_msg], |
||
0 ignored issues
–
show
The property
id_msg does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
275 | 'member' => MembersList::get($this->_this_message[$this->_idx_mapper->id_member]), |
||
0 ignored issues
–
show
The property
id_member does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
276 | 'subject' => $this->_this_message['subject'], |
||
277 | 'html_time' => htmlTime($this->_this_message[$this->_idx_mapper->time]), |
||
0 ignored issues
–
show
The property
time does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
278 | 'time' => standardTime($this->_this_message[$this->_idx_mapper->time]), |
||
279 | 'timestamp' => forum_time(true, $this->_this_message[$this->_idx_mapper->time]), |
||
280 | 'counter' => $this->_counter, |
||
281 | 'body' => $this->_this_message['body'], |
||
282 | 'can_see_ip' => allowedTo('moderate_forum') || ($this->_this_message[$this->_idx_mapper->id_member] == $this->user->id && !empty($this->user->id)), |
||
283 | 'classes' => [] |
||
284 | ]; |
||
285 | } |
||
286 | } |
||
287 |