Completed
Push — master ( c97259...614dac )
by Nazar
04:31
created

Comments::count_internal()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 3
eloc 7
nc 3
nop 1
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
	h,
12
	cs\Cache,
13
	cs\Config,
14
	cs\Language,
15
	cs\Request,
16
	cs\User,
17
	cs\CRUD_helpers,
18
	cs\Singleton;
19
20
/**
21
 * @method static $this instance($check = false)
22
 */
23
class Comments {
24
	use
25
		CRUD_helpers,
26
		Singleton;
27
28
	/**
29
	 * @var Cache
30
	 */
31
	protected $cache;
32
	/**
33
	 * @var int    Avatar size in px, can be redefined
34
	 */
35
	public $avatar_size = 36;
36
37
	protected $data_model = [
38
		'id'     => 'int:1',
39
		'parent' => 'int:0',
40
		'module' => 'text',
41
		'item'   => 'int:1',
42
		'user'   => 'int:1',
43
		'date'   => 'int:1',
44
		'text'   => 'html',
45
		'lang'   => 'text'
46
	];
47
48
	protected $table = '[prefix]comments';
49
50
	protected function construct () {
51
		$this->cache = Cache::prefix('Comments');
0 ignored issues
show
Documentation Bug introduced by
It seems like \cs\Cache::prefix('Comments') of type object<cs\Cache\Prefix> is incompatible with the declared type object<cs\Cache> of property $cache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
52
	}
53
	/**
54
	 * Returns database index
55
	 *
56
	 * @return int
57
	 */
58
	protected function cdb () {
59
		return Config::instance()->module('Comments')->db('comments');
60
	}
61
	/**
62
	 * Get comment data
63
	 *
64
	 * @param int|int[] $id
65
	 *
66
	 * @return array|false
1 ignored issue
show
Documentation introduced by
Should the return type not be array|false|integer|string? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
67
	 */
68
	function get ($id) {
69
		return $this->read($id);
70
	}
71
	/**
72
	 * Add new comment
73
	 *
74
	 * @param int    $item   Item id
75
	 * @param string $module Module name
76
	 * @param string $text   Comment text
77
	 * @param int    $parent Parent comment id
78
	 *
79
	 * @return false|int
1 ignored issue
show
Documentation introduced by
Should the return type not be false|integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
80
	 */
81
	function add ($item, $module, $text, $parent = 0) {
82
		$L    = Language::instance();
83
		$User = User::instance();
84
		$text = xap($text, true);
85
		if (!$text) {
86
			return false;
87
		}
88
		if ($parent) {
89
			$parent_comment = $this->read($parent);
90
			if ($parent_comment['item'] != $item || $parent_comment['module'] != $module) {
91
				return false;
92
			}
93
		}
94
		$id = $this->create($parent, $module, $item, $User->id, time(), $text, $L->clang);
95
		if ($id) {
96
			$this->cache->del("$module/$item");
97
		}
98
		return $id;
99
	}
100
	/**
101
	 * Set comment text
102
	 *
103
	 * @param int    $id
104
	 * @param string $text
105
	 *
106
	 * @return bool
107
	 */
108
	function set ($id, $text) {
109
		$text = xap($text, true);
110
		if (!$text) {
111
			return false;
112
		}
113
		$comment = $this->get($id);
114
		if (!$comment) {
115
			return false;
116
		}
117
		$comment['text'] = $text;
118
		$result          = $this->update($comment);
119
		if ($result) {
120
			$this->cache->del("$comment[module]/$comment[item]");
121
		}
122
		return $result;
123
	}
124
	/**
125
	 * Delete comment
126
	 *
127
	 * @param int $id
128
	 *
129
	 * @return bool
130
	 */
131
	function del ($id) {
132
		$comment = $this->read($id);
133
		if (
134
			!$comment ||
135
			$this->search(
136
				[
137
					'parent'      => $id,
138
					'total_count' => true
139
				]
140
			)
141
		) {
142
			return false;
143
		}
144
		$result = $this->delete($id);
145
		if ($result) {
146
			$this->cache->del("$comment[module]/$comment[item]");
147
		}
148
		return $result;
149
	}
150
	/**
151
	 * Delete all comments of specified item
152
	 *
153
	 * @param int    $item   Item id
154
	 * @param string $module Module name
155
	 *
156
	 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be object|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
157
	 */
158
	function del_all ($item, $module) {
159
		$item   = (int)$item;
160
		$result = $this->db_prime()->q(
161
			"DELETE FROM `[prefix]comments`
162
			WHERE
163
				`module`	= '%s' AND
164
				`item`		= '%d'",
165
			$module,
166
			$item
167
		);
168
		if ($result) {
169
			$this->cache->del("$module/$item");
170
		}
171
		return $result;
172
	}
173
	/**
174
	 * Count of comments for specified item
175
	 *
176
	 * @param int    $item   Item id
177
	 * @param string $module Module name
178
	 *
179
	 * @return int
180
	 */
181
	function count ($item, $module) {
182
		$item = (int)$item;
183
		$L    = Language::instance();
184
		return $this->cache->get(
185
			"$module/$item/count/$L->clang",
186
			function () use ($item, $module, $L) {
187
				return $this->search(
188
					[
189
						'module'      => $module,
190
						'item'        => $item,
191
						'lang'        => $L->clang,
192
						'total_count' => true
193
					]
194
				);
195
			}
196
		);
197
	}
198
	/**
199
	 * Get comments tree in html format for specified item (look at ::block() method before usage)
200
	 *
201
	 * @param int    $item   Item id
202
	 * @param string $module Module name
203
	 *
204
	 * @return string
205
	 */
206
	function tree ($item, $module) {
207
		return $this->tree_html($this->tree_data($item, $module) ?: []);
208
	}
209
	/**
210
	 * Get comments structure of specified item
211
	 *
212
	 * @param int			$item
213
	 * @param string		$module
214
	 * @param int			$parent
215
	 *
216
	 * @return false|array
217
	 */
218
	function tree_data ($item, $module, $parent = 0) {
219
		$Cache	= $this->cache;
220
		$L		= Language::instance();
221
		if (($comments = $Cache->{"$module/$item/$L->clang"}) === false) {
222
			$item		= (int)$item;
223
			$parent		= (int)$parent;
224
			$comments	= $this->db()->qfa(
225
				"SELECT
226
					`id`,
227
					`parent`,
228
					`user`,
229
					`date`,
230
					`text`,
231
					`lang`
232
				FROM `[prefix]comments`
233
				WHERE
234
					`parent`	= '%d' AND
235
					`item`		= '%d' AND
236
					`module`	= '%s' AND
237
					`lang`		= '%s'",
238
				$parent,
239
				$item,
240
				$module,
241
				$L->clang
242
			) ?: [];
243
			foreach ($comments as &$comment) {
244
				$comment['comments'] = $this->tree_data($item, $module, $comment['id']);
245
			}
246
			unset($comment);
247
			/**
248
			 * Cache only root tree data
249
			 */
250
			if ($parent == 0) {
251
				$Cache->{"$module/$item/$L->clang"}	= $comments;
252
			}
253
		}
254
		return $comments;
255
	}
256
	/**
257
	 * Get comments tree in html format for given data structure (usually uses ::tree_data() method)
258
	 *
259
	 * @param array[]	$comments
260
	 *
261
	 * @return string
262
	 */
263
	function tree_html ($comments) {
264
		$L			= Language::instance();
265
		$User		= User::instance();
266
		if (!is_array($comments) || !$comments) {
267
			return '';
268
		}
269
		$content	= '';
270
		foreach ($comments as $comment) {
271
			$uniqid		= uniqid('comment_', true);
272
			$content	.= str_replace($uniqid, $comment['text'], h::{'article.cs-comments-comment'}(
273
				h::{'img.cs-comments-comment-avatar'}([
274
					'src'	=> $User->avatar($this->avatar_size, $comment['user']),
275
					'alt'	=> $User->username($comment['user']),
276
					'title'	=> $User->username($comment['user'])
277
				]).
278
				h::span($User->username($comment['user'])).
279
				h::{'time.cs-comments-comment-date'}(
280
					date('dmY', time()) == date('dmY', $comment['date']) ?
281
						date($L->_time, $comment['date']) : $L->to_locale(date($L->_datetime, $comment['date'])),
282
					[
283
						'datetime'		=> date('c', $comment['date'])
284
					]
285
				).
286
				h::{'a.cs-comments-comment-link'}(
287
					h::icon('anchor'),
288
					[
289
						'href'	=> "#comment_$comment[id]"
290
					]
291
				).
292
				(
293
					$comment['parent'] ? h::{'a.cs-comments-comment-parent'}(
294
						h::icon('level-up'),
295
						[
296
							'href'	=> "#comment_$comment[parent]"
297
						]
298
					) : ''
299
				).
300
				(
301
					$User->id == $comment['user'] || $User->admin() ? h::{'icon.cs-comments-comment-edit.cs-cursor-pointer'}('pencil') : ''
302
				).
303
				(
304
					!$comment['comments'] &&
305
					(
306
						$User->id == $comment['user'] || $User->admin()
307
					) ? h::{'icon.cs-comments-comment-delete.cs-cursor-pointer'}('trash-o') : ''
308
				).
309
				h::{'div.cs-comments-comment-text'}($uniqid).
310
				(
311
					$comment['comments'] ? $this->tree_html($comment['comments']) : ''
312
				),
313
				[
314
					'id'	=> "comment_$comment[id]"
315
				]
316
			));
317
		}
318
		return $content;
319
	}
320
	/**
321
	 * Get comments block with comments tree and comments sending form
322
	 *
323
	 * @param int    $item   Item id
324
	 * @param string $module Module name
325
	 *
326
	 * @return string
327
	 */
328
	function block ($item, $module) {
329
		$L	= Language::prefix('comments_');
330
		return h::{'section#comments.cs-comments-comments'}(
331
			$L->comments.':'.
332
			(
333
				$this->tree($item, $module) ?: h::{'article.cs-blogs-no-comments'}($L->no_comments_yet)
334
			)
335
		).
336
		h::{'p.cs-comments-add-comment'}("$L->add_comment:").
337
		(
338
			User::instance()->user() ? h::{'section.cs-comments-comment-write'}(
339
				h::{'cs-editor-simple textarea.cs-comments-comment-write-text[is=cs-textarea][autosize]'}(
340
					'',
341
					[
342
						'data-item'		=> $item,
343
						'data-parent'	=> 0,
344
						'data-id'		=> 0,
345
						'data-module'	=> $module
346
					]
347
				).
348
				h::br().
349
				h::{'button.cs-comments-comment-write-send[is=cs-button]'}(
350
					$L->send_comment
351
				).
352
				h::{'button.cs-comments-comment-write-edit[is=cs-button]'}(
353
					$L->save,
354
					[
355
						'style'	=>	'display: none'
356
					]
357
				).
358
				h::{'button.cs-comments-comment-write-cancel[is=cs-button]'}(
359
					$L->cancel,
360
					[
361
						'style'	=>	'display: none'
362
					]
363
				)
364
			) : h::p($L->register_for_comments_sending)
365
		);
366
	}
367
}
368