Completed
Push — master ( fa84a1...c2d4ab )
by Nazar
05:12
created

Posts::get()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 2
nop 1
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package   Blogs
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\Blogs;
10
use
11
	cs\Cache,
12
	cs\Config,
13
	cs\Event,
14
	cs\Language,
15
	cs\User,
16
	cs\CRUD_helpers,
17
	cs\Singleton,
18
	cs\modules\Json_ld\Json_ld;
19
20
/**
21
 * @method static $this instance($check = false)
22
 */
23
class Posts {
24
	use
25
		CRUD_helpers,
26
		Singleton;
27
	protected $data_model                  = [
28
		'id'       => 'int:0',
29
		'user'     => 'int:0',
30
		'date'     => 'int:0',
31
		'title'    => 'ml:text',
32
		'path'     => 'ml:text',
33
		'content'  => 'ml:html',
34
		'draft'    => 'int:0..1',
35
		'sections' => [
36
			'data_model' => [
37
				'id'      => 'int:0',
38
				'section' => 'int:0'
39
			]
40
		],
41
		'tags'     => [
42
			'data_model'     => [
43
				'id'  => 'int:0',
44
				'tag' => 'int:0'
45
			],
46
			'language_field' => 'lang'
47
		]
48
	];
49
	protected $table                       = '[prefix]blogs_posts';
50
	protected $data_model_ml_group         = 'Blogs/posts';
51
	protected $data_model_files_tag_prefix = 'Blogs/posts';
52
	/**
53
	 * @var Cache\Prefix
54
	 */
55
	protected $cache;
56
57
	protected function construct () {
58
		$this->cache = Cache::prefix('Blogs');
59
		if (Config::instance()->module('Blogs')->allow_iframes_without_content) {
60
			$this->data_model['content'] = 'ml:html_iframe';
61
		}
62
	}
63
	/**
64
	 * Returns database index
65
	 *
66
	 * @return int
67
	 */
68
	protected function cdb () {
69
		return Config::instance()->module('Blogs')->db('posts');
70
	}
71
	/**
72
	 * Get data of specified post
73
	 *
74
	 * @param int|int[] $id
75
	 *
76
	 * @return array|false
77
	 */
78
	public function get ($id) {
79
		if (is_array($id)) {
80
			return array_map([$this, 'get'], $id);
81
		}
82
		$L    = Language::instance();
83
		$id   = (int)$id;
84
		$data = $this->cache->get(
85
			"posts/$id/$L->clang",
86
			function () use ($id) {
87
				$data = $this->read($id);
88
				if ($data) {
89
					$data['short_content'] = truncate(explode('<!-- pagebreak -->', $data['content'])[0]);
90
					$data['tags']          = $this->read_tags_processing($data['tags']);
91
				}
92
				return $data;
93
			}
94
		);
95
		return $data;
96
	}
97
	/**
98
	 * @param int $page
99
	 * @param int $count
100
	 *
101
	 * @return int[]
102
	 */
103
	public function get_all ($page, $count) {
104
		return $this->search([], $page, $count, 'id');
105
	}
106
	/**
107
	 * Transform tags ids back into array of strings
108
	 *
109
	 * @param int[] $tags
110
	 *
111
	 * @return string[]
112
	 */
113
	protected function read_tags_processing ($tags) {
114
		return array_column(Tags::instance()->get($tags) ?: [], 'text');
115
	}
116
	/**
117
	 * Get data of specified post
118
	 *
119
	 * @param int|int[] $id
120
	 *
121
	 * @return array|false
122
	 */
123
	public function get_as_json_ld ($id) {
124
		$post = $this->get($id);
125
		if (!$post) {
126
			return false;
127
		}
128
		return $this->post_to_jsonld($post);
129
	}
130
	/**
131
	 * @param array|array[] $post
132
	 *
133
	 * @return array
134
	 */
135
	public function post_to_jsonld ($post) {
136
		$base_structure = [
137
			'@context' =>
138
				[
139
					'content'        => 'articleBody',
140
					'title'          => 'headline',
141
					'tags'           => 'keywords',
142
					'datetime'       => null,
143
					'sections_paths' => null,
144
					'tags_paths'     => null
145
				] + Json_ld::context_stub(isset($post[0]) ? $post[0] : $post)
146
		];
147
		if (isset($post[0])) {
148
			return
149
				$base_structure +
150
				[
151
					'@graph' => array_map(
152
						[$this, 'post_to_jsonld_single_post'],
153
						$post
154
					)
155
				];
156
		}
157
		return
158
			$base_structure +
159
			$this->post_to_jsonld_single_post($post);
160
	}
161
	protected function post_to_jsonld_single_post ($post) {
162
		if (preg_match_all('/<img[^>]src=["\'](.*)["\']/Uims', $post['content'], $images)) {
163
			$images = $images[1];
164
		}
165
		$Sections = Sections::instance();
166
		$sections = [];
167
		if ($post['sections'] != [0]) {
168
			$sections = array_column(
169
				$Sections->get($post['sections']),
170
				'title'
171
			);
172
		}
173
		$L            = Language::prefix('blogs_');
174
		$base_url     = Config::instance()->base_url();
175
		$module_path  = path($L->Blogs);
176
		$section_path = "$base_url/$module_path/".path($L->section);
177
		$tag_path     = "$base_url/$module_path/".path($L->tag);
178
		$url          = "$base_url/$module_path/$post[path]:$post[id]";
179
		return
180
			[
181
				'@id'            => $url,
182
				'@type'          => 'BlogPosting',
183
				'articleSection' => $sections,
184
				'author'         => Json_ld::Person($post['user']),
185
				'datePublished'  => Json_ld::Date($post['date']),
186
				'image'          => $images,
187
				'inLanguage'     => $L->clang,
188
				'url'            => $url,
189
				'datetime'       => $L->to_locale(date($L->_datetime_long, $post['date'] ?: time())),
190
				'sections_paths' => array_map(
191
					function ($section) use ($section_path, $Sections) {
192
						$section = $Sections->get($section);
193
						return "$section_path/$section[full_path]";
194
					},
195
					$post['sections']
196
				),
197
				'tags_paths'     => array_map(
198
					function ($tag) use ($tag_path) {
199
						return "$tag_path/$tag";
200
					},
201
					$post['tags']
202
				)
203
			] + $post;
204
	}
205
	/**
206
	 * Get latest posts
207
	 *
208
	 * @param int $page
209
	 * @param int $count
210
	 *
211
	 * @return int[]
212
	 */
213
	public function get_latest_posts ($page, $count) {
214
		$search_parameters = [
215
			'draft' => 0
216
		];
217
		return $this->search($search_parameters, $page, $count, 'date', false) ?: [];
218
	}
219
	/**
220
	 * Get posts for section
221
	 *
222
	 * @param int $section
223
	 * @param int $page
224
	 * @param int $count
225
	 *
226
	 * @return int[]
227
	 */
228
	public function get_for_section ($section, $page, $count) {
229
		$search_parameters = [
230
			'draft'    => 0,
231
			'sections' => [
232
				'section' => $section
233
			]
234
		];
235
		return $this->search($search_parameters, $page, $count, 'date', false) ?: [];
236
	}
237
	/**
238
	 * Get number of posts for section
239
	 *
240
	 * @param int $section
241
	 *
242
	 * @return int
243
	 */
244
	public function get_for_section_count ($section) {
245
		$search_parameters = [
246
			'draft'       => 0,
247
			'sections'    => [
248
				'section' => $section
249
			],
250
			'total_count' => true
251
		];
252
		return $this->search($search_parameters);
253
	}
254
	/**
255
	 * Get posts for tag
256
	 *
257
	 * @param int $tag
258
	 * @param int $page
259
	 * @param int $count
260
	 *
261
	 * @return int[]
262
	 */
263
	public function get_for_tag ($tag, $page, $count) {
264
		$search_parameters = [
265
			'draft' => 0,
266
			'tags'  => [
267
				'tag' => $tag
268
			]
269
		];
270
		return $this->search($search_parameters, $page, $count, 'date', false) ?: [];
271
	}
272
	/**
273
	 * Get number of posts for tag
274
	 *
275
	 * @param int $tag
276
	 *
277
	 * @return int
278
	 */
279
	public function get_for_tag_count ($tag) {
280
		$search_parameters = [
281
			'draft'       => 0,
282
			'tags'        => [
283
				'tag' => $tag
284
			],
285
			'total_count' => true
286
		];
287
		return $this->search($search_parameters);
288
	}
289
	/**
290
	 * Get drafts
291
	 *
292
	 * @param int $user
293
	 * @param int $page
294
	 * @param int $count
295
	 *
296
	 * @return int[]
297
	 */
298
	public function get_drafts ($user, $page, $count) {
299
		$search_parameters = [
300
			'user'  => $user,
301
			'draft' => 1
302
		];
303
		return $this->search($search_parameters, $page, $count, 'date', false) ?: [];
304
	}
305
	/**
306
	 * Get number of drafts
307
	 *
308
	 * @param int $user
309
	 *
310
	 * @return int
311
	 */
312
	public function get_drafts_count ($user) {
313
		$search_parameters = [
314
			'user'        => $user,
315
			'draft'       => 1,
316
			'total_count' => true
317
		];
318
		return $this->search($search_parameters);
319
	}
320
	/**
321
	 * Add new post
322
	 *
323
	 * @param string   $title
324
	 * @param string   $path
325
	 * @param string   $content
326
	 * @param int[]    $sections
327
	 * @param string[] $tags
328
	 * @param bool     $draft
329
	 *
330
	 * @return false|int Id of created post on success of <b>false</> on failure
331
	 */
332
	public function add ($title, $path, $content, $sections, $tags, $draft) {
333
		if (!$this->check_arguments($content, $sections, $tags)) {
334
			return false;
335
		}
336
		$id = $this->create(
337
			User::instance()->id,
338
			$draft ? 0 : time(),
339
			$title,
340
			path($path ?: $title),
341
			$content,
342
			$draft,
343
			$sections,
344
			$this->prepare_tags($tags)
345
		);
346
		if ($id) {
347
			$this->cache_cleanups($id);
348
		}
349
		return $id;
350
	}
351
	/**
352
	 * Transform array of string tags into array of their ids
353
	 *
354
	 * @param string[] $tags
355
	 *
356
	 * @return int[]
357
	 */
358
	protected function prepare_tags ($tags) {
359
		return Tags::instance()->add($tags) ?: [];
360
	}
361
	/**
362
	 * @param string   $content
363
	 * @param int[]    $sections
364
	 * @param string[] $tags
365
	 *
366
	 * @return bool
367
	 */
368
	protected function check_arguments ($content, &$sections, $tags) {
369
		if (empty($tags) || empty($content)) {
370
			return false;
371
		}
372
		$sections = array_intersect(
373
			array_merge([0], array_column(Sections::instance()->get_all(), 'id')),
374
			$sections
375
		);
376
		$sections = array_values($sections);
377
		return $sections && count($sections) <= Config::instance()->module('Blogs')->max_sections;
378
	}
379
	/**
380
	 * @param int $id
381
	 */
382
	protected function cache_cleanups ($id) {
383
		$Cache = $this->cache;
384
		unset(
385
			$Cache->{"posts/$id"},
386
			$Cache->sections,
387
			$Cache->total_count
388
		);
389
	}
390
	/**
391
	 * Set data of specified post
392
	 *
393
	 * @param int      $id
394
	 * @param string   $title
395
	 * @param string   $path
396
	 * @param string   $content
397
	 * @param int[]    $sections
398
	 * @param string[] $tags
399
	 * @param bool     $draft
400
	 *
401
	 * @return bool
402
	 */
403
	public function set ($id, $title, $path, $content, $sections, $tags, $draft) {
404
		if (!$this->check_arguments($content, $sections, $tags)) {
405
			return false;
406
		}
407
		$old_data = $this->get($id);
408
		$result   = $this->update(
409
			$id,
410
			$old_data['user'],
411
			$old_data['draft'] == 1 && $old_data['date'] == 0 && !$draft ? time() : $old_data['date'],
412
			$title,
413
			path($path ?: $title),
414
			$content,
415
			$draft,
416
			$sections,
417
			$this->prepare_tags($tags)
418
		);
419
		$this->cache_cleanups($id);
420
		return $result;
421
	}
422
	/**
423
	 * Delete specified post
424
	 *
425
	 * @param int $id
426
	 *
427
	 * @return bool
428
	 */
429
	public function del ($id) {
430
		$id     = (int)$id;
431
		$result = $this->delete($id);
432
		if ($result) {
433
			Event::instance()->fire(
434
				'Comments/deleted',
435
				[
436
					'module' => 'Blogs',
437
					'item'   => $id
438
				]
439
			);
440
			$this->cache_cleanups($id);
441
		}
442
		return $result;
443
	}
444
	/**
445
	 * Get total count of posts
446
	 *
447
	 * @return int
448
	 */
449
	public function get_total_count () {
450
		return $this->cache->get(
451
			'total_count',
452
			function () {
453
				$search_parameters = [
454
					'draft'       => 0,
455
					'total_count' => true
456
				];
457
				return $this->search($search_parameters);
458
			}
459
		);
460
	}
461
}
462