Passed
Push — master ( c1368b...bc6a5e )
by Joas
13:04 queued 17s
created

Comment::getMentions()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 12
nc 4
nop 0
dl 0
loc 16
rs 9.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OC\Comments;
27
28
use OCP\Comments\IComment;
29
use OCP\Comments\IllegalIDChangeException;
30
use OCP\Comments\MessageTooLongException;
31
32
class Comment implements IComment {
33
34
	protected $data = [
35
		'id'              => '',
36
		'parentId'        => '0',
37
		'topmostParentId' => '0',
38
		'childrenCount'   => '0',
39
		'message'         => '',
40
		'verb'            => '',
41
		'actorType'       => '',
42
		'actorId'         => '',
43
		'objectType'      => '',
44
		'objectId'        => '',
45
		'referenceId'     => null,
46
		'creationDT'      => null,
47
		'latestChildDT'   => null,
48
	];
49
50
	/**
51
	 * Comment constructor.
52
	 *
53
	 * @param array $data	optional, array with keys according to column names from
54
	 * 						the comments database scheme
55
	 */
56
	public function __construct(array $data = null) {
57
		if(is_array($data)) {
58
			$this->fromArray($data);
59
		}
60
	}
61
62
	/**
63
	 * returns the ID of the comment
64
	 *
65
	 * It may return an empty string, if the comment was not stored.
66
	 * It is expected that the concrete Comment implementation gives an ID
67
	 * by itself (e.g. after saving).
68
	 *
69
	 * @return string
70
	 * @since 9.0.0
71
	 */
72
	public function getId() {
73
		return $this->data['id'];
74
	}
75
76
	/**
77
	 * sets the ID of the comment and returns itself
78
	 *
79
	 * It is only allowed to set the ID only, if the current id is an empty
80
	 * string (which means it is not stored in a database, storage or whatever
81
	 * the concrete implementation does), or vice versa. Changing a given ID is
82
	 * not permitted and must result in an IllegalIDChangeException.
83
	 *
84
	 * @param string $id
85
	 * @return IComment
86
	 * @throws IllegalIDChangeException
87
	 * @since 9.0.0
88
	 */
89
	public function setId($id) {
90
		if(!is_string($id)) {
0 ignored issues
show
introduced by
The condition is_string($id) is always true.
Loading history...
91
			throw new \InvalidArgumentException('String expected.');
92
		}
93
94
		$id = trim($id);
95
		if($this->data['id'] === '' || ($this->data['id'] !== '' && $id === '')) {
96
			$this->data['id'] = $id;
97
			return $this;
98
		}
99
100
		throw new IllegalIDChangeException('Not allowed to assign a new ID to an already saved comment.');
101
	}
102
103
	/**
104
	 * returns the parent ID of the comment
105
	 *
106
	 * @return string
107
	 * @since 9.0.0
108
	 */
109
	public function getParentId() {
110
		return $this->data['parentId'];
111
	}
112
113
	/**
114
	 * sets the parent ID and returns itself
115
	 *
116
	 * @param string $parentId
117
	 * @return IComment
118
	 * @since 9.0.0
119
	 */
120
	public function setParentId($parentId) {
121
		if(!is_string($parentId)) {
0 ignored issues
show
introduced by
The condition is_string($parentId) is always true.
Loading history...
122
			throw new \InvalidArgumentException('String expected.');
123
		}
124
		$this->data['parentId'] = trim($parentId);
125
		return $this;
126
	}
127
128
	/**
129
	 * returns the topmost parent ID of the comment
130
	 *
131
	 * @return string
132
	 * @since 9.0.0
133
	 */
134
	public function getTopmostParentId() {
135
		return $this->data['topmostParentId'];
136
	}
137
138
139
	/**
140
	 * sets the topmost parent ID and returns itself
141
	 *
142
	 * @param string $id
143
	 * @return IComment
144
	 * @since 9.0.0
145
	 */
146
	public function setTopmostParentId($id) {
147
		if(!is_string($id)) {
0 ignored issues
show
introduced by
The condition is_string($id) is always true.
Loading history...
148
			throw new \InvalidArgumentException('String expected.');
149
		}
150
		$this->data['topmostParentId'] = trim($id);
151
		return $this;
152
	}
153
154
	/**
155
	 * returns the number of children
156
	 *
157
	 * @return int
158
	 * @since 9.0.0
159
	 */
160
	public function getChildrenCount() {
161
		return $this->data['childrenCount'];
162
	}
163
164
	/**
165
	 * sets the number of children
166
	 *
167
	 * @param int $count
168
	 * @return IComment
169
	 * @since 9.0.0
170
	 */
171
	public function setChildrenCount($count) {
172
		if(!is_int($count)) {
0 ignored issues
show
introduced by
The condition is_int($count) is always true.
Loading history...
173
			throw new \InvalidArgumentException('Integer expected.');
174
		}
175
		$this->data['childrenCount'] = $count;
176
		return $this;
177
	}
178
179
	/**
180
	 * returns the message of the comment
181
	 *
182
	 * @return string
183
	 * @since 9.0.0
184
	 */
185
	public function getMessage() {
186
		return $this->data['message'];
187
	}
188
189
	/**
190
	 * sets the message of the comment and returns itself
191
	 *
192
	 * @param string $message
193
	 * @param int $maxLength
194
	 * @return IComment
195
	 * @throws MessageTooLongException
196
	 * @since 9.0.0
197
	 */
198
	public function setMessage($message, $maxLength = self::MAX_MESSAGE_LENGTH) {
199
		if(!is_string($message)) {
0 ignored issues
show
introduced by
The condition is_string($message) is always true.
Loading history...
200
			throw new \InvalidArgumentException('String expected.');
201
		}
202
		$message = trim($message);
203
		if ($maxLength && mb_strlen($message, 'UTF-8') > $maxLength) {
204
			throw new MessageTooLongException('Comment message must not exceed ' . $maxLength. ' characters');
205
		}
206
		$this->data['message'] = $message;
207
		return $this;
208
	}
209
210
	/**
211
	 * returns an array containing mentions that are included in the comment
212
	 *
213
	 * @return array each mention provides a 'type' and an 'id', see example below
214
	 * @since 11.0.0
215
	 *
216
	 * The return array looks like:
217
	 * [
218
	 *   [
219
	 *     'type' => 'user',
220
	 *     'id' => 'citizen4'
221
	 *   ],
222
	 *   [
223
	 *     'type' => 'group',
224
	 *     'id' => 'media'
225
	 *   ],
226
	 *   …
227
	 * ]
228
	 *
229
	 */
230
	public function getMentions() {
231
		$ok = preg_match_all("/\B(?<![^a-z0-9_\-@\.\'\s])@(\"guest\/[a-f0-9]+\"|\"[a-z0-9_\-@\.\' ]+\"|[a-z0-9_\-@\.\']+)/i", $this->getMessage(), $mentions);
232
		if(!$ok || !isset($mentions[0]) || !is_array($mentions[0])) {
233
			return [];
234
		}
235
		$uids = array_unique($mentions[0]);
236
		$result = [];
237
		foreach ($uids as $uid) {
238
			$cleanUid = trim(substr($uid, 1), '"');
239
			if (strpos($cleanUid, 'guest/') === 0) {
240
				$result[] = ['type' => 'guest', 'id' => $cleanUid];
241
			} else {
242
				$result[] = ['type' => 'user', 'id' => $cleanUid];
243
			}
244
		}
245
		return $result;
246
	}
247
248
	/**
249
	 * returns the verb of the comment
250
	 *
251
	 * @return string
252
	 * @since 9.0.0
253
	 */
254
	public function getVerb() {
255
		return $this->data['verb'];
256
	}
257
258
	/**
259
	 * sets the verb of the comment, e.g. 'comment' or 'like'
260
	 *
261
	 * @param string $verb
262
	 * @return IComment
263
	 * @since 9.0.0
264
	 */
265
	public function setVerb($verb) {
266
		if(!is_string($verb) || !trim($verb)) {
0 ignored issues
show
introduced by
The condition is_string($verb) is always true.
Loading history...
267
			throw new \InvalidArgumentException('Non-empty String expected.');
268
		}
269
		$this->data['verb'] = trim($verb);
270
		return $this;
271
	}
272
273
	/**
274
	 * returns the actor type
275
	 *
276
	 * @return string
277
	 * @since 9.0.0
278
	 */
279
	public function getActorType() {
280
		return $this->data['actorType'];
281
	}
282
283
	/**
284
	 * returns the actor ID
285
	 *
286
	 * @return string
287
	 * @since 9.0.0
288
	 */
289
	public function getActorId() {
290
		return $this->data['actorId'];
291
	}
292
293
	/**
294
	 * sets (overwrites) the actor type and id
295
	 *
296
	 * @param string $actorType e.g. 'users'
297
	 * @param string $actorId e.g. 'zombie234'
298
	 * @return IComment
299
	 * @since 9.0.0
300
	 */
301
	public function setActor($actorType, $actorId) {
302
		if(
303
		       !is_string($actorType) || !trim($actorType)
0 ignored issues
show
introduced by
The condition is_string($actorType) is always true.
Loading history...
304
		    || !is_string($actorId)   || $actorId === ''
305
		) {
306
			throw new \InvalidArgumentException('String expected.');
307
		}
308
		$this->data['actorType'] = trim($actorType);
309
		$this->data['actorId']   = $actorId;
310
		return $this;
311
	}
312
313
	/**
314
	 * returns the creation date of the comment.
315
	 *
316
	 * If not explicitly set, it shall default to the time of initialization.
317
	 *
318
	 * @return \DateTime
319
	 * @since 9.0.0
320
	 */
321
	public function getCreationDateTime() {
322
		return $this->data['creationDT'];
323
	}
324
325
	/**
326
	 * sets the creation date of the comment and returns itself
327
	 *
328
	 * @param \DateTime $timestamp
329
	 * @return IComment
330
	 * @since 9.0.0
331
	 */
332
	public function setCreationDateTime(\DateTime $timestamp) {
333
		$this->data['creationDT'] = $timestamp;
334
		return $this;
335
	}
336
337
	/**
338
	 * returns the DateTime of the most recent child, if set, otherwise null
339
	 *
340
	 * @return \DateTime|null
341
	 * @since 9.0.0
342
	 */
343
	public function getLatestChildDateTime() {
344
		return $this->data['latestChildDT'];
345
	}
346
347
	/**
348
	 * sets the date of the most recent child
349
	 *
350
	 * @param \DateTime $dateTime
351
	 * @return IComment
352
	 * @since 9.0.0
353
	 */
354
	public function setLatestChildDateTime(\DateTime $dateTime = null) {
355
		$this->data['latestChildDT'] = $dateTime;
356
		return $this;
357
	}
358
359
	/**
360
	 * returns the object type the comment is attached to
361
	 *
362
	 * @return string
363
	 * @since 9.0.0
364
	 */
365
	public function getObjectType() {
366
		return $this->data['objectType'];
367
	}
368
369
	/**
370
	 * returns the object id the comment is attached to
371
	 *
372
	 * @return string
373
	 * @since 9.0.0
374
	 */
375
	public function getObjectId() {
376
		return $this->data['objectId'];
377
	}
378
379
	/**
380
	 * sets (overwrites) the object of the comment
381
	 *
382
	 * @param string $objectType e.g. 'files'
383
	 * @param string $objectId e.g. '16435'
384
	 * @return IComment
385
	 * @since 9.0.0
386
	 */
387
	public function setObject($objectType, $objectId) {
388
		if(
389
		       !is_string($objectType) || !trim($objectType)
0 ignored issues
show
introduced by
The condition is_string($objectType) is always true.
Loading history...
390
		    || !is_string($objectId)   || trim($objectId) === ''
391
		) {
392
			throw new \InvalidArgumentException('String expected.');
393
		}
394
		$this->data['objectType'] = trim($objectType);
395
		$this->data['objectId']   = trim($objectId);
396
		return $this;
397
	}
398
399
	/**
400
	 * returns the reference id of the comment
401
	 *
402
	 * @return string|null
403
	 * @since 19.0.0
404
	 */
405
	public function getReferenceId(): ?string {
406
		return $this->data['referenceId'];
407
	}
408
409
	/**
410
	 * sets (overwrites) the reference id of the comment
411
	 *
412
	 * @param string $referenceId e.g. sha256 hash sum
413
	 * @return IComment
414
	 * @since 19.0.0
415
	 */
416
	public function setReferenceId(?string $referenceId): IComment {
417
		if ($referenceId === null) {
418
			$this->data['referenceId'] = $referenceId;
419
		} else {
420
			$referenceId = trim($referenceId);
421
			if ($referenceId === '') {
422
				throw new \InvalidArgumentException('Non empty string expected.');
423
			}
424
			$this->data['referenceId'] = $referenceId;
425
		}
426
		return $this;
427
	}
428
429
	/**
430
	 * sets the comment data based on an array with keys as taken from the
431
	 * database.
432
	 *
433
	 * @param array $data
434
	 * @return IComment
435
	 */
436
	protected function fromArray($data) {
437
		foreach(array_keys($data) as $key) {
438
			// translate DB keys to internal setter names
439
			$setter = 'set' . implode('', array_map('ucfirst', explode('_', $key)));
440
			$setter = str_replace('Timestamp', 'DateTime', $setter);
441
442
			if(method_exists($this, $setter)) {
443
				$this->$setter($data[$key]);
444
			}
445
		}
446
447
		foreach(['actor', 'object'] as $role) {
448
			if(isset($data[$role . '_type']) && isset($data[$role . '_id'])) {
449
				$setter = 'set' . ucfirst($role);
450
				$this->$setter($data[$role . '_type'], $data[$role . '_id']);
451
			}
452
		}
453
454
		return $this;
455
	}
456
}
457