Passed
Pull Request — development (#3834)
by Spuds
08:39
created

Labels::_updateRules()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
nc 6
nop 1
dl 0
loc 20
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file deals with label actions related to personal messages.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * @version 2.0 Beta 1
11
 *
12
 */
13
14
namespace ElkArte\PersonalMessage;
15
16
use ElkArte\AbstractController;
17
use ElkArte\Cache\Cache;
18
use ElkArte\Helper\Util;
19
20
/**
21
 * Class Labels
22
 * It allows managing personal message labels
23
 *
24
 * @package ElkArte\PersonalMessage
25
 */
26
class Labels extends AbstractController
27
{
28
	/**
29
	 * Default action for the class
30
	 */
31
	public function action_index()
32
	{
33
		$this->action_manlabels();
34
	}
35
36
	/**
37
	 * This function handles adding, deleting, and editing labels on messages.
38
	 */
39
	public function action_manlabels(): void
40
	{
41
		global $context;
42
43
		require_once(SUBSDIR . '/PersonalMessage.subs.php');
44
45
		$this->_initLabelsContext();
46
47
		// Add all existing labels to the array to save, slashing them as necessary...
48
		$the_labels = $this->_getExistingLabels($context['labels']);
49
50
		// Submitting changes?
51
		if ($this->_req->hasPost('add') || $this->_req->hasPost('delete') || $this->_req->hasPost('save'))
52
		{
53
			$this->_handleLabelSubmissions($the_labels);
54
		}
55
	}
56
57
	/**
58
	 * Set up the context for the manage labels page.
59
	 */
60
	private function _initLabelsContext(): void
61
	{
62
		global $txt, $context;
63
64
		// Build the link tree elements...
65
		$context['breadcrumbs'][] = [
66
			'url' => getUrl('action', ['action' => 'pm', 'sa' => 'manlabels']),
67
			'name' => $txt['pm_manage_labels']
68
		];
69
70
		// Some things for the template
71
		$context['page_title'] = $txt['pm_manage_labels'];
72
		$context['sub_template'] = 'labels';
73
	}
74
75
	/**
76
	 * Get the existing labels from the context, excluding the inbox (-1).
77
	 *
78
	 * @param array $labels
79
	 * @return array
80
	 */
81
	private function _getExistingLabels(array $labels): array
82
	{
83
		$the_labels = [];
84
		foreach ($labels as $label)
85
		{
86
			if ($label['id'] !== -1)
87
			{
88
				$the_labels[$label['id']] = $label['name'];
89
			}
90
		}
91
92
		return $the_labels;
93
	}
94
95
	/**
96
	 * Handle the submission of label changes (add, delete, save).
97
	 *
98
	 * @param array $the_labels
99
	 */
100
	private function _handleLabelSubmissions(array $the_labels): void
101
	{
102
		checkSession();
103
104
		// This will be for updating messages.
105
		$message_changes = [];
106
		$new_labels = [];
107
108
		// Will most likely need this.
109
		loadRules();
110
111
		// Adding a new label?
112
		if ($this->_req->hasPost('add'))
113
		{
114
			$this->_addNewLabel($the_labels);
115
		}
116
		// Deleting an existing label?
117
		elseif ($this->_req->hasPost('delete') && $this->_req->hasPost('delete_label'))
118
		{
119
			$message_changes = $this->_deleteLabels($the_labels, $new_labels);
120
		}
121
		// The hardest one to deal with... changes.
122
		elseif ($this->_req->hasPost('save'))
123
		{
124
			$message_changes = $this->_saveLabels($the_labels, $new_labels);
125
		}
126
127
		// Save the label status.
128
		require_once(SUBSDIR . '/Members.subs.php');
129
		updateMemberData($this->user->id, ['message_labels' => implode(',', $the_labels)]);
130
131
		// Update all the messages currently with any label changes in them!
132
		$this->_updateMessagesAndRules($message_changes, $new_labels);
133
134
		// Make sure we're not caching this!
135
		Cache::instance()->remove('labelCounts:' . $this->user->id);
136
137
		// To make the changes appear right away, redirect.
138
		redirectexit('action=pm;sa=manlabels');
139
	}
140
141
	/**
142
	 * Add a new label to the list.
143
	 *
144
	 * @param array $the_labels
145
	 */
146
	private function _addNewLabel(array &$the_labels): void
147
	{
148
		$label = $this->_req->getPost('label', 'trim|strval', '');
149
		$label = strtr(Util::htmlspecialchars($label), [',' => '&#044;']);
150
151
		if (Util::strlen($label) > 30)
152
		{
153
			$label = Util::substr($label, 0, 30);
154
		}
155
156
		if ($label !== '')
157
		{
158
			$the_labels[] = $label;
159
		}
160
	}
161
162
	/**
163
	 * Delete labels from the list.
164
	 *
165
	 * @param array $the_labels
166
	 * @param array $new_labels
167
	 * @return array message changes
168
	 */
169
	private function _deleteLabels(array &$the_labels, array &$new_labels): array
170
	{
171
		$delete_label = $this->_req->getPost('delete_label', null, []);
172
		$message_changes = [];
173
		$i = 0;
174
175
		foreach (array_keys($the_labels) as $id)
176
		{
177
			if (isset($delete_label[$id]))
178
			{
179
				unset($the_labels[$id]);
180
				$message_changes[$id] = true;
181
			}
182
			else
183
			{
184
				$new_labels[$id] = $i++;
185
			}
186
		}
187
188
		return $message_changes;
189
	}
190
191
	/**
192
	 * Save changes to existing labels.
193
	 *
194
	 * @param array $the_labels
195
	 * @param array $new_labels
196
	 * @return array message changes
197
	 */
198
	private function _saveLabels(array &$the_labels, array &$new_labels): array
199
	{
200
		$label_name = $this->_req->getPost('label_name', null, []);
201
		$message_changes = [];
202
		$i = 0;
203
204
		foreach (array_keys($the_labels) as $id)
205
		{
206
			if ($id === -1)
207
			{
208
				continue;
209
			}
210
211
			if (isset($label_name[$id]))
212
			{
213
				// Prepare the label name
214
				$prepared = trim(strtr(Util::htmlspecialchars($label_name[$id]), [',' => '&#044;']));
215
216
				// Has to fit in the database as well
217
				if (Util::strlen($prepared) > 30)
218
				{
219
					$prepared = Util::substr($prepared, 0, 30);
220
				}
221
222
				if ($prepared !== '')
223
				{
224
					$the_labels[(int) $id] = $prepared;
225
					$new_labels[$id] = $i++;
226
				}
227
				else
228
				{
229
					unset($the_labels[(int) $id]);
230
					$message_changes[(int) $id] = true;
231
				}
232
			}
233
			else
234
			{
235
				$new_labels[$id] = $i++;
236
			}
237
		}
238
239
		return $message_changes;
240
	}
241
242
	/**
243
	 * Update messages and rules when labels are changed or deleted.
244
	 *
245
	 * @param array $message_changes
246
	 * @param array $new_labels
247
	 */
248
	private function _updateMessagesAndRules(array $message_changes, array $new_labels): void
249
	{
250
		global $context;
251
252
		if (empty($message_changes))
253
		{
254
			return;
255
		}
256
257
		$searchArray = array_keys($message_changes);
258
259
		if (!empty($new_labels))
260
		{
261
			for ($i = max($searchArray) + 1, $n = max(array_keys($new_labels)); $i <= $n; $i++)
262
			{
263
				$searchArray[] = $i;
264
			}
265
		}
266
267
		updateLabelsToPM($searchArray, $new_labels, $this->user->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
268
269
		// Now do the same the rules - check through each rule.
270
		$rule_changes = [];
271
		foreach ($context['rules'] as $k => $rule)
272
		{
273
			// Each action...
274
			foreach ($rule['actions'] as $k2 => $action)
275
			{
276
				if ($action['t'] !== 'lab' || !in_array($action['v'], $searchArray, true))
277
				{
278
					continue;
279
				}
280
281
				$rule_changes[] = $rule['id'];
282
283
				// If we're here, we have a label which is either changed or gone...
284
				if (isset($new_labels[$action['v']]))
285
				{
286
					$context['rules'][$k]['actions'][$k2]['v'] = $new_labels[$action['v']];
287
				}
288
				else
289
				{
290
					unset($context['rules'][$k]['actions'][$k2]);
291
				}
292
			}
293
		}
294
295
		// If we have rules to change, do so now.
296
		if (!empty($rule_changes))
297
		{
298
			$this->_updateRules($rule_changes);
299
		}
300
	}
301
302
	/**
303
	 * Update or delete PM rules.
304
	 *
305
	 * @param array $rule_changes
306
	 */
307
	private function _updateRules(array $rule_changes): void
308
	{
309
		global $context;
310
311
		$rule_changes = array_unique($rule_changes);
312
313
		// Update/delete as appropriate.
314
		foreach ($rule_changes as $k => $id)
315
		{
316
			if (!empty($context['rules'][$id]['actions']))
317
			{
318
				updatePMRuleAction($id, $this->user->id, $context['rules'][$id]['actions']);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
319
				unset($rule_changes[$k]);
320
			}
321
		}
322
323
		// Anything left here means it's lost all actions...
324
		if (!empty($rule_changes))
325
		{
326
			deletePMRules($this->user->id, $rule_changes);
327
		}
328
	}
329
}
330