Completed
Push — master ( 47bd7a...595ca5 )
by Nazar
04:16
created

Comments::tree_data()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 38
rs 8.439
cc 5
eloc 18
nc 5
nop 3
1
<?php
2
/**
3
 * @package   Comments
4
 * @category  modules
5
 * @author    Nazar Mokrynskyi <[email protected]>
6
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
7
 * @license   MIT License, see license.txt
8
 */
9
namespace cs\modules\Comments;
10
use
11
	cs\DB\Accessor,
12
	h,
13
	cs\Cache\Prefix as Cache_prefix,
14
	cs\Config,
15
	cs\Language,
16
	cs\Language\Prefix as Language_prefix,
17
	cs\Request,
18
	cs\User,
19
	cs\Singleton;
20
21
/**
22
 * @method static $this instance($check = false)
23
 */
24
class Comments {
25
	use
26
		Accessor,
27
		Singleton;
28
29
	/**
30
	 * @var Cache_prefix
31
	 */
32
	protected	$cache;
33
	/**
34
	 * @var int	Avatar size in px, can be redefined
35
	 */
36
	public		$avatar_size	= 36;
37
38
	protected function construct () {
39
		$this->cache	= new Cache_prefix('Comments');
40
	}
41
	/**
42
	 * Returns database index
43
	 *
44
	 * @return int
45
	 */
46
	protected function cdb () {
47
		return Config::instance()->module('Comments')->db('comments');
48
	}
49
	/**
50
	 * Get comment data
51
	 *
52
	 * @param int			$id Comment id
53
	 *
54
	 * @return array|false		Array of comment data on success or <b>false</b> on failure
55
	 */
56
	function get ($id) {
57
		$id	= (int)$id;
58
		return $this->db()->qf(
59
			"SELECT
60
				`id`,
61
				`parent`,
62
				`module`,
63
				`item`,
64
				`user`,
65
				`date`,
66
				`text`,
67
				`lang`
68
			FROM `[prefix]comments`
69
			WHERE
70
				`id`	= '%d'
71
			LIMIT 1",
72
			$id
73
		);
74
	}
75
	/**
76
	 * Add new comment
77
	 *
78
	 * @param int			$item	Item id
79
	 * @param string		$module	Module name
80
	 * @param string		$text	Comment text
81
	 * @param int			$parent	Parent comment id
82
	 *
83
	 * @return false|int
84
	 */
85
	function add ($item, $module, $text, $parent = 0) {
86
		$L		= Language::instance();
87
		$User	= User::instance();
88
		$text	= xap($text, true);
89
		if (!$text) {
90
			return false;
91
		}
92
		$item	= (int)$item;
93
		$parent	= (int)$parent;
94
		if (
95
			$parent != 0 &&
96
			$this->db_prime()->qfs(
97
				"SELECT `item`
98
				FROM `[prefix]comments`
99
				WHERE
100
					`id`		= '%d' AND
101
					`module`	= '%s'
102
				LIMIT 1",
103
				$parent,
104
				$module
105
			) != $item
106
		) {
107
			return false;
108
		}
109
		if ($this->db_prime()->q(
110
			"INSERT INTO `[prefix]comments`
111
				(
112
					`parent`,
113
					`module`,
114
					`item`,
115
					`user`,
116
					`date`,
117
					`text`,
118
					`lang`
119
				)
120
			VALUES
121
				(
122
					'%s',
123
					'%s',
124
					'%s',
125
					'%s',
126
					'%s',
127
					'%s',
128
					'%s'
129
				)",
130
			$parent,
131
			$module,
132
			$item,
133
			$User->id,
134
			time(),
135
			$text,
136
			$L->clang
137
		)) {
138
			$this->cache->del("$module/$item");
139
			return $this->db_prime()->id();
140
		}
141
		return false;
142
	}
143
	/**
144
	 * Set comment text
145
	 *
146
	 * @param int		$id		Comment id
147
	 * @param string	$text	New comment text
148
	 *
149
	 * @return bool
150
	 */
151
	function set ($id, $text) {
152
		$text	= xap($text, true);
153
		if (!$text) {
154
			return false;
155
		}
156
		$id				= (int)$id;
157
		$comment		= $this->get($id);
158
		if (!$comment) {
159
			return false;
160
		}
161
		if ($this->db_prime()->q(
162
			"UPDATE `[prefix]comments`
163
			SET `text` = '%s'
164
			WHERE
165
				`id`	= '%d'
166
			LIMIT 1",
167
			$text,
168
			$id
169
		)) {
170
			$this->cache->del("$comment[module]/$comment[item]");
171
			return true;
172
		}
173
		return false;
174
	}
175
	/**
176
	 * Delete comment
177
	 *
178
	 * @param int	$id	Comment id
179
	 *
180
	 * @return bool
181
	 */
182
	function del ($id) {
183
		$id				= (int)$id;
184
		$comment		= $this->db_prime()->qf(
185
			"SELECT `p`.*, COUNT(`c`.`id`) AS `count`
186
			FROM `[prefix]comments` AS `p`
187
			LEFT JOIN `[prefix]comments` AS `c`
188
			ON `p`.`id` = `c`.`parent`
189
			WHERE
190
				`p`.`id`	= '%d'
191
			LIMIT 1",
192
			$id
193
		);
194
		if (!$comment || $comment['count']) {
195
			return false;
196
		}
197
		if ($this->db_prime()->q(
198
			"DELETE FROM `[prefix]comments`
199
			WHERE
200
				`id`	= '%s'
201
			LIMIT 1",
202
			$id
203
		)) {
204
			$this->cache->del("$comment[module]/$comment[item]");
205
			return true;
206
		}
207
		return false;
208
	}
209
	/**
210
	 * Delete all comments of specified item
211
	 *
212
	 * @param int    $item   Item id
213
	 * @param string $module Module name
214
	 *
215
	 * @return bool
216
	 */
217
	function del_all ($item, $module) {
218
		$item			= (int)$item;
219
		if ($this->db_prime()->q(
220
			"DELETE FROM `[prefix]comments`
221
			WHERE
222
				`module`	= '%s' AND
223
				`item`		= '%d'",
224
			$module,
225
			$item
226
		)) {
227
			$this->cache->del("$module/$item");
228
			return true;
229
		}
230
		return false;
231
	}
232
	/**
233
	 * Count of comments for specified item
234
	 *
235
	 * @param int    $item   Item id
236
	 * @param string $module Module name
237
	 *
238
	 * @return int
239
	 */
240
	function count ($item, $module) {
241
		$item = (int)$item;
242
		$L    = Language::instance();
243
		return $this->cache->get("$module/$item/count/$L->clang", function () use ($item, $module)  {
244
			return $this->count_internal($this->tree_data($item, $module)) ?: 0;
245
		});
246
	}
247
	protected function count_internal ($data) {
248
		if (!is_array($data)) {
249
			return 0;
250
		}
251
		$count	= 0;
252
		foreach ($data as &$d) {
253
			$count	+= $this->count_internal($d['comments']) + 1;
254
		}
255
		return $count;
256
	}
257
	/**
258
	 * Get comments tree in html format for specified item (look at ::block() method before usage)
259
	 *
260
	 * @param int    $item   Item id
261
	 * @param string $module Module name
262
	 *
263
	 * @return string
264
	 */
265
	function tree ($item, $module) {
266
		return $this->tree_html($this->tree_data($item, $module) ?: []);
267
	}
268
	/**
269
	 * Get comments structure of specified item
270
	 *
271
	 * @param int			$item
272
	 * @param string		$module
273
	 * @param int			$parent
274
	 *
275
	 * @return false|array
276
	 */
277
	function tree_data ($item, $module, $parent = 0) {
278
		$Cache	= $this->cache;
279
		$L		= Language::instance();
280
		if (($comments = $Cache->{"$module/$item/$L->clang"}) === false) {
281
			$item		= (int)$item;
282
			$parent		= (int)$parent;
283
			$comments	= $this->db()->qfa(
284
				"SELECT
285
					`id`,
286
					`parent`,
287
					`user`,
288
					`date`,
289
					`text`,
290
					`lang`
291
				FROM `[prefix]comments`
292
				WHERE
293
					`parent`	= '%d' AND
294
					`item`		= '%d' AND
295
					`module`	= '%s' AND
296
					`lang`		= '%s'",
297
				$parent,
298
				$item,
299
				$module,
300
				$L->clang
301
			) ?: [];
302
			foreach ($comments as &$comment) {
303
				$comment['comments'] = $this->tree_data($item, $module, $comment['id']);
304
			}
305
			unset($comment);
306
			/**
307
			 * Cache only root tree data
308
			 */
309
			if ($parent == 0) {
310
				$Cache->{"$module/$item/$L->clang"}	= $comments;
311
			}
312
		}
313
		return $comments;
314
	}
315
	/**
316
	 * Get comments tree in html format for given data structure (usually uses ::tree_data() method)
317
	 *
318
	 * @param array[]	$comments
319
	 *
320
	 * @return string
321
	 */
322
	function tree_html ($comments) {
323
		$L			= Language::instance();
324
		$User		= User::instance();
325
		if (!is_array($comments) || !$comments) {
326
			return '';
327
		}
328
		$content	= '';
329
		foreach ($comments as $comment) {
330
			$uniqid		= uniqid('comment_', true);
331
			$content	.= str_replace($uniqid, $comment['text'], h::{'article.cs-comments-comment'}(
332
				h::{'img.cs-comments-comment-avatar'}([
333
					'src'	=> $User->avatar($this->avatar_size, $comment['user']),
334
					'alt'	=> $User->username($comment['user']),
335
					'title'	=> $User->username($comment['user'])
336
				]).
337
				h::span($User->username($comment['user'])).
338
				h::{'time.cs-comments-comment-date'}(
339
					date('dmY', time()) == date('dmY', $comment['date']) ?
340
						date($L->_time, $comment['date']) : $L->to_locale(date($L->_datetime, $comment['date'])),
341
					[
342
						'datetime'		=> date('c', $comment['date'])
343
					]
344
				).
345
				h::{'a.cs-comments-comment-link'}(
346
					h::icon('anchor'),
347
					[
348
						'href'	=> "#comment_$comment[id]"
349
					]
350
				).
351
				(
352
					$comment['parent'] ? h::{'a.cs-comments-comment-parent'}(
353
						h::icon('level-up'),
354
						[
355
							'href'	=> "#comment_$comment[parent]"
356
						]
357
					) : ''
358
				).
359
				(
360
					$User->id == $comment['user'] || $User->admin() ? h::{'icon.cs-comments-comment-edit.cs-cursor-pointer'}('pencil') : ''
361
				).
362
				(
363
					!$comment['comments'] &&
364
					(
365
						$User->id == $comment['user'] || $User->admin()
366
					) ? h::{'icon.cs-comments-comment-delete.cs-cursor-pointer'}('trash-o') : ''
367
				).
368
				h::{'div.cs-comments-comment-text'}($uniqid).
369
				(
370
					$comment['comments'] ? $this->tree_html($comment['comments']) : ''
371
				),
372
				[
373
					'id'	=> "comment_$comment[id]"
374
				]
375
			));
376
		}
377
		return $content;
378
	}
379
	/**
380
	 * Get comments block with comments tree and comments sending form
381
	 *
382
	 * @param int    $item   Item id
383
	 * @param string $module Module name
384
	 *
385
	 * @return string
386
	 */
387
	function block ($item, $module) {
388
		$L	= new Language_prefix('comments_');
389
		return h::{'section#comments.cs-comments-comments'}(
390
			$L->comments.':'.
391
			(
392
				$this->tree($item, $module) ?: h::{'article.cs-blogs-no-comments'}($L->no_comments_yet)
393
			)
394
		).
395
		h::{'p.cs-comments-add-comment'}("$L->add_comment:").
396
		(
397
			User::instance()->user() ? h::{'section.cs-comments-comment-write'}(
398
				h::{'cs-editor-simple textarea.cs-comments-comment-write-text[is=cs-textarea][autosize]'}(
399
					'',
400
					[
401
						'data-item'		=> $item,
402
						'data-parent'	=> 0,
403
						'data-id'		=> 0,
404
						'data-module'	=> $module
405
					]
406
				).
407
				h::br().
408
				h::{'button.cs-comments-comment-write-send[is=cs-button]'}(
409
					$L->send_comment
410
				).
411
				h::{'button.cs-comments-comment-write-edit[is=cs-button]'}(
412
					$L->save,
413
					[
414
						'style'	=>	'display: none'
415
					]
416
				).
417
				h::{'button.cs-comments-comment-write-cancel[is=cs-button]'}(
418
					$L->cancel,
419
					[
420
						'style'	=>	'display: none'
421
					]
422
				)
423
			) : h::p($L->register_for_comments_sending)
424
		);
425
	}
426
}
427