Completed
Push — master ( d2e234...56bfde )
by Nazar
04:27
created

Controller::edit_post()   F

Complexity

Conditions 32
Paths 238

Size

Total Lines 175
Code Lines 121

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 175
rs 3.6119
cc 32
eloc 121
nc 238
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Config,
12
	cs\Event,
13
	cs\ExitException,
14
	cs\Language\Prefix,
15
	cs\Page\Meta,
16
	cs\Page,
17
	cs\Request,
18
	cs\Response,
19
	cs\User,
20
	h;
21
22
class Controller {
23
	static function latest_posts () {
24
		if (!Event::instance()->fire('Blogs/latest_posts')) {
25
			return;
26
		}
27
		$Config  = Config::instance();
28
		$L       = new Prefix('blogs_');
29
		$Meta    = Meta::instance();
30
		$Page    = Page::instance();
31
		$Posts   = Posts::instance();
32
		$Request = Request::instance();
33
		/**
34
		 * Page title
35
		 */
36
		$Page->title($L->latest_posts);
37
		/**
38
		 * Now add link to Atom feed for latest posts
39
		 */
40
		$Page->atom('Blogs/atom.xml', $L->latest_posts);
41
		/**
42
		 * Set page of blog type (Open Graph protocol)
43
		 */
44
		$Meta->blog();
45
		/**
46
		 * Determine current page
47
		 */
48
		$page = max(
49
			isset($Request->route_ids[0]) ? array_slice($Request->route_ids, -1)[0] : 1,
50
			1
51
		);
52
		/**
53
		 * If this is not first page - show that in page title
54
		 */
55
		if ($page > 1) {
56
			$Page->title($L->blogs_nav_page($page));
57
		}
58
		/**
59
		 * Get posts for current page in JSON-LD structure format
60
		 */
61
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
62
		$posts          = $Posts->get_latest_posts($page, $posts_per_page);
63
		/**
64
		 * Base url (without page number)
65
		 */
66
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->latest_posts);
67
		/**
68
		 * Render posts page
69
		 */
70
		Helpers::show_posts_list(
71
			$posts,
72
			$Posts->get_total_count(),
73
			$page,
74
			$base_url
75
		);
76
	}
77
	static function section () {
78
		if (!Event::instance()->fire('Blogs/section')) {
79
			return;
80
		}
81
		$Config   = Config::instance();
82
		$L        = new Prefix('blogs_');
83
		$Meta     = Meta::instance();
84
		$Page     = Page::instance();
85
		$Posts    = Posts::instance();
86
		$Request  = Request::instance();
87
		$Sections = Sections::instance();
88
		/**
89
		 * At first - determine part of url and get sections list based on that path
90
		 */
91
		$sections = $Sections->get_by_path(
92
			array_slice($Request->route_path, 1)
93
		);
94
		if (!$sections) {
95
			throw new ExitException(400);
96
		}
97
		$sections = $Sections->get($sections);
98
		/**
99
		 * Now lets set page title using sections names from page path
100
		 * We will not remove `$section` variable after, since it will be direct parent of each shown post
101
		 */
102
		foreach ($sections as $section) {
0 ignored issues
show
Bug introduced by
The expression $sections of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
103
			$Page->title($section['title']);
104
		}
105
		/**
106
		 * Now add link to Atom feed for posts from current section only
107
		 */
108
		/** @noinspection PhpUndefinedVariableInspection */
109
		$Page->atom(
110
			"Blogs/atom.xml/?section=$section[id]",
111
			implode($Config->core['title_delimiter'], [$L->latest_posts, $L->section, $section['title']])
112
		);
113
		/**
114
		 * Set page of blog type (Open Graph protocol)
115
		 */
116
		$Meta->blog();
117
		/**
118
		 * Determine current page
119
		 */
120
		$page = max(
121
			isset($Request->route_ids[0]) ? array_slice($Request->route_ids, -1)[0] : 1,
122
			1
123
		);
124
		/**
125
		 * If this is not first page - show that in page title
126
		 */
127
		if ($page > 1) {
128
			$Page->title($L->blogs_nav_page($page));
129
		}
130
		/**
131
		 * Get posts for current page in JSON-LD structure format
132
		 */
133
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
134
		$posts          = $Posts->get_for_section($section['id'], $page, $posts_per_page);
135
		/**
136
		 * Base url (without page number)
137
		 */
138
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->section)."/$section[full_path]";
139
		/**
140
		 * Render posts page
141
		 */
142
		Helpers::show_posts_list(
143
			$posts,
144
			$section['posts'],
145
			$page,
146
			$base_url
147
		);
148
	}
149
	static function post () {
150
		if (!Event::instance()->fire('Blogs/post')) {
151
			return;
152
		}
153
154
		$Config   = Config::instance();
155
		$Page     = Page::instance();
156
		$User     = User::instance();
157
		$Comments = null;
158
		Event::instance()->fire(
159
			'Comments/instance',
160
			[
161
				'Comments' => &$Comments
162
			]
163
		);
164
		/**
165
		 * @var \cs\modules\Comments\Comments $Comments
166
		 */
167
		$Posts   = Posts::instance();
168
		$rc      = Request::instance()->route;
169
		$post_id = (int)mb_substr($rc[1], mb_strrpos($rc[1], ':') + 1);
170
		if (!$post_id) {
171
			throw new ExitException(404);
172
		}
173
		$post = $Posts->get_as_json_ld($post_id);
174
		if (
175
			!$post ||
176
			(
177
				$post['draft'] && $post['user'] != $User->id
178
			)
179
		) {
180
			throw new ExitException(404);
181
		}
182
		if ($post['path'] != mb_substr($rc[1], 0, mb_strrpos($rc[1], ':'))) {
183
			Response::instance()->redirect($post['url'], 303);
184
			return;
185
		}
186
		$Page->title($post['title']);
0 ignored issues
show
Documentation introduced by
$post['title'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
187
		$Page->Description = description($post['short_content']);
188
		$Page->canonical_url($post['url']);
0 ignored issues
show
Documentation introduced by
$post['url'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
189
		$Meta = Meta::instance();
190
		$Meta
191
			->article()
192
			->article('published_time', date('Y-m-d', $post['date'] ?: TIME))
193
			->article('section', $post['articleSection'] ? $post['articleSection'][0] : false)
194
			->article('tag', $post['tags']);
195
		array_map([$Meta, 'image'], $post['image']);
196
		$comments_enabled = $Config->module('Blogs')->enable_comments && $Comments;
197
		$is_admin         =
198
			$User->admin() &&
199
			$User->get_permission('admin/Blogs', 'index') &&
200
			$User->get_permission('admin/Blogs', 'edit_post');
201
		$Page->content(
202
			h::{'article[is=cs-blogs-post]'}(
203
				h::{'script[type=application/ld+json]'}(
204
					json_encode($post, JSON_UNESCAPED_UNICODE)
205
				),
206
				[
207
					'comments_enabled' => $comments_enabled,
208
					'can_edit'         => $is_admin || $User->id == $post['user'],
209
					'can_delete'       => $is_admin
210
				]
211
			).
212
			($comments_enabled ? $Comments->block($post['id']) : '')
0 ignored issues
show
Documentation introduced by
$post['id'] is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
213
		);
214
	}
215
	static function tag () {
216
		if (!Event::instance()->fire('Blogs/tag')) {
217
			return;
218
		}
219
		$Config  = Config::instance();
220
		$L       = new Prefix('blogs_');
221
		$Meta    = Meta::instance();
222
		$Page    = Page::instance();
223
		$Posts   = Posts::instance();
224
		$Tags    = Tags::instance();
225
		$Request = Request::instance();
226
		/**
227
		 * If no tag specified
228
		 */
229
		if (!isset($Request->route[1])) {
230
			throw new ExitException(404);
231
		}
232
		/**
233
		 * Find tag
234
		 */
235
		$tag = $Tags->get_by_text($Request->route[1]);
236
		if (!$tag) {
237
			throw new ExitException(404);
238
		}
239
		$tag = $Tags->get($tag);
240
		/**
241
		 * Add tag to page title
242
		 */
243
		$Page->title($tag['text']);
244
		/**
245
		 * Now add link to Atom feed for posts with current tag only
246
		 */
247
		$Page->atom(
248
			"Blogs/atom.xml/?tag=$tag[id]",
249
			implode($Config->core['title_delimiter'], [$L->latest_posts, $L->tag, $tag['text']])
250
		);
251
		/**
252
		 * Set page of blog type (Open Graph protocol)
253
		 */
254
		$Meta->blog();
255
		/**
256
		 * Determine current page
257
		 */
258
		$page = max(
259
			isset($Request->route[2]) ? $Request->route[2] : 1,
260
			1
261
		);
262
		/**
263
		 * If this is not first page - show that in page title
264
		 */
265
		if ($page > 1) {
266
			$Page->title($L->blogs_nav_page($page));
267
		}
268
		/**
269
		 * Get posts for current page in JSON-LD structure format
270
		 */
271
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
272
		$posts          = $Posts->get_for_tag($tag['id'], $L->clang, $page, $posts_per_page);
273
		$posts_count    = $Posts->get_for_tag_count($tag['id'], $L->clang);
274
		/**
275
		 * Base url (without page number)
276
		 */
277
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->tag).'/'.$Request->route[1];
278
		/**
279
		 * Render posts page
280
		 */
281
		Helpers::show_posts_list(
282
			$posts,
283
			$posts_count,
284
			$page,
285
			$base_url
286
		);
287
	}
288
	static function new_post () {
289
		if (!Event::instance()->fire('Blogs/new_post')) {
290
			return;
291
		}
292
293
		$Config      = Config::instance();
294
		$module_data = $Config->module('Blogs');
295
		$L           = new Prefix('blogs_');
296
		$Page        = Page::instance();
297
		$Request     = Request::instance();
298
		$User        = User::instance();
299
		$Page->title($L->new_post);
300
		if (!$User->admin() && $module_data->new_posts_only_from_admins) {
301
			throw new ExitException(403);
302
		}
303
		if (!$User->user()) {
304
			$Page->warning($L->for_registered_users_only);
305
			return;
306
		}
307
		$module = path($L->Blogs);
308
		if (isset($_POST['title'], $_POST['sections'], $_POST['content'], $_POST['tags'], $_POST['mode'])) {
309
			$draft = false;
310
			switch ($_POST['mode']) {
311
				case 'draft':
312
					$draft = true;
313
				case 'publish':
314
					$save = true;
315
					if (empty($_POST['title'])) {
316
						$Page->warning($L->post_title_empty);
317
						$save = false;
318
					}
319
					if (empty($_POST['sections']) && $_POST['sections'] !== '0') {
320
						$Page->warning($L->no_post_sections_specified);
321
						$save = false;
322
					}
323
					if (empty($_POST['content'])) {
324
						$Page->warning($L->post_content_empty);
325
						$save = false;
326
					}
327
					if (empty($_POST['tags'])) {
328
						$Page->warning($L->no_post_tags_specified);
329
						$save = false;
330
					}
331
					if ($save) {
332
						$Posts = Posts::instance();
333
						$id    = $Posts->add($_POST['title'], null, $_POST['content'], $_POST['sections'], _trim(explode(',', $_POST['tags'])), $draft);
334
						if ($id) {
335
							$Page->interface = false;
336
							Response::instance()->redirect($Config->base_url()."/$module/".$Posts->get($id)['path'].":$id");
337
							return;
338
						} else {
339
							$Page->warning($L->post_adding_error);
340
						}
341
					}
342
					break;
343
			}
344
		}
345
		$disabled     = [];
346
		$max_sections = $module_data->max_sections;
347
		$content      = uniqid('post_content', true);
348
		$Page->replace($content, isset($_POST['content']) ? $_POST['content'] : '');
349
		$sections = get_sections_select_post($disabled);
350
		if (count($sections['in']) > 1) {
351
			$sections = [
352
				$L->post_section,
353
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
354
					$sections,
355
					[
356
						'name'     => 'sections[]',
357
						'disabled' => $disabled,
358
						'selected' => isset($_POST['sections']) ? $_POST['sections'] : (isset($Request->route[1]) ? $Request->route[1] : []),
359
						$max_sections < 1 ? 'multiple' : false
360
					]
361
				).
362
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
363
			];
364
		} else {
365
			$sections = false;
366
		}
367
		$Page->content(
368
			h::form(
369
				h::{'h2.cs-text-center'}(
370
					$L->new_post
371
				).
372
				h::{'div.cs-blogs-post-preview-content'}().
373
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
374
					[
375
						$L->post_title,
376
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
377
							isset($_POST['title']) ? $_POST['title'] : '<br>'
378
						)
379
					],
380
					$sections,
381
					[
382
						$L->post_content,
383
						(
384
						functionality('inline_editor') ? h::{'cs-editor-inline div.cs-blogs-new-post-content'}(
385
							$content
386
						) : h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
387
							isset($_POST['content']) ? $_POST['content'] : ''
388
						)
389
						).
390
						h::br().
391
						$L->post_use_pagebreak
392
					],
393
					[
394
						$L->post_tags,
395
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
396
							[
397
								'value'       => isset($_POST['tags']) ? $_POST['tags'] : false,
398
								'placeholder' => 'CleverStyle, CMS, Open Source'
399
							]
400
						)
401
					]
402
				).
403
				(
404
				!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : ''
405
				).
406
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
407
					$L->preview
408
				).
409
				h::{'button[is=cs-button][type=submit][name=mode][value=publish]'}(
410
					$L->publish
411
				).
412
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
413
					$L->to_drafts
414
				).
415
				h::{'button[is=cs-button]'}(
416
					$L->cancel,
417
					[
418
						'type'    => 'button',
419
						'onclick' => 'history.go(-1);'
420
					]
421
				)
422
			)
423
		);
424
	}
425
	static function edit_post () {
426
		if (!Event::instance()->fire('Blogs/edit_post')) {
427
			return;
428
		}
429
430
		$Posts       = Posts::instance();
431
		$Config      = Config::instance();
432
		$module_data = $Config->module('Blogs');
433
		$L           = new Prefix('blogs_');
434
		$Page        = Page::instance();
435
		$Request     = Request::instance();
436
		$User        = User::instance();
437
		if ($module_data->new_posts_only_from_admins && !$User->admin()) {
438
			throw new ExitException(403);
439
		}
440
		if (
441
			!isset($Request->route[1]) ||
442
			!($post = $Posts->get($Request->route[1]))
443
		) {
444
			throw new ExitException(404);
445
		}
446
		if (
447
			$post['user'] != $User->id &&
448
			!(
449
				$User->admin() &&
450
				$User->get_permission('admin/Blogs', 'index') &&
451
				$User->get_permission('admin/Blogs', 'edit_post')
452
			)
453
		) {
454
			throw new ExitException(403);
455
		}
456
		$Page->title(
457
			$L->editing_of_post($post['title'])
458
		);
459
		$module = path($L->Blogs);
460
		if (isset($_POST['title'], $_POST['sections'], $_POST['content'], $_POST['tags'], $_POST['mode'])) {
461
			$draft = false;
462
			switch ($_POST['mode']) {
463
				case 'draft':
464
					$draft = true;
465
				case 'save':
466
					$save = true;
467
					if (empty($_POST['title'])) {
468
						$Page->warning($L->post_title_empty);
469
						$save = false;
470
					}
471
					if (empty($_POST['sections']) && $_POST['sections'] !== '0') {
472
						$Page->warning($L->no_post_sections_specified);
473
						$save = false;
474
					}
475
					if (empty($_POST['content'])) {
476
						$Page->warning($L->post_content_empty);
477
						$save = false;
478
					}
479
					if (empty($_POST['tags'])) {
480
						$Page->warning($L->no_post_tags_specified);
481
						$save = false;
482
					}
483
					if ($save) {
484
						if ($Posts->set(
485
							$post['id'],
486
							$_POST['title'],
487
							null,
488
							$_POST['content'],
489
							$_POST['sections'],
490
							_trim(explode(',', $_POST['tags'])),
491
							$draft
492
						)
493
						) {
494
							$Page->interface = false;
495
							Response::instance()->redirect($Config->base_url()."/$module/$post[path]:$post[id]");
496
							return;
497
						} else {
498
							$Page->warning($L->post_saving_error);
499
						}
500
					}
501
					break;
502
				case 'delete':
503
					if ($Posts->del($post['id'])) {
504
						$Page->interface = false;
505
						Response::instance()->redirect($Config->base_url()."/$module");
506
						return;
507
					} else {
508
						$Page->warning($L->post_deleting_error);
509
					}
510
					break;
511
			}
512
		}
513
		$disabled     = [];
514
		$max_sections = $module_data->max_sections;
515
		$content      = uniqid('post_content', true);
516
		$Page->replace($content, isset($_POST['content']) ? $_POST['content'] : $post['content']);
517
		$sections = get_sections_select_post($disabled);
518
		if (count($sections['in']) > 1) {
519
			$sections = [
520
				$L->post_section,
521
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
522
					get_sections_select_post($disabled),
523
					[
524
						'name'     => 'sections[]',
525
						'disabled' => $disabled,
526
						'selected' => isset($_POST['sections']) ? $_POST['sections'] : $post['sections'],
527
						$max_sections < 1 ? 'multiple' : false
528
					]
529
				).
530
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
531
			];
532
		} else {
533
			$sections = false;
534
		}
535
		$Page->content(
536
			h::form(
537
				h::{'h2.cs-text-center'}(
538
					$L->editing_of_post($post['title'])
539
				).
540
				h::{'div.cs-blogs-post-preview-content'}().
541
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
542
					[
543
						$L->post_title,
544
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
545
							isset($_POST['title']) ? $_POST['title'] : $post['title']
546
						)
547
					],
548
					$sections,
549
					[
550
						$L->post_content,
551
						(
552
						functionality('inline_editor') ? h::{'cs-editor-inline div.cs-blogs-new-post-content'}(
553
							$content
554
						) : h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
555
							isset($_POST['content']) ? $_POST['content'] : $post['content']
556
						)
557
						).
558
						h::br().
559
						$L->post_use_pagebreak
560
					],
561
					[
562
						$L->post_tags,
563
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
564
							[
565
								'value'       => htmlspecialchars_decode(
566
									isset($_POST['tags']) ? $_POST['tags'] : implode(', ', $post['tags']),
567
									ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED | ENT_SUBSTITUTE
568
								),
569
								'placeholder' => 'CleverStyle, CMS, Open Source'
570
							]
571
						)
572
					]
573
				).
574
				(!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : '').
575
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
576
					$L->preview,
577
					[
578
						'data-id' => $post['id']
579
					]
580
				).
581
				h::{'button[is=cs-button][type=submit][name=mode][value=save]'}(
582
					$L->publish
583
				).
584
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
585
					$L->to_drafts
586
				).
587
				h::{'button[is=cs-button][type=submit][name=mode][value=delete]'}(
588
					$L->delete
589
				).
590
				h::{'button[is=cs-button]'}(
591
					$L->cancel,
592
					[
593
						'type'    => 'button',
594
						'onclick' => 'history.go(-1);'
595
					]
596
				)
597
			)
598
		);
599
	}
600
	static function drafts () {
601
		if (!Event::instance()->fire('Blogs/drafts')) {
602
			return;
603
		}
604
		$Config  = Config::instance();
605
		$L       = new Prefix('blogs_');
606
		$Page    = Page::instance();
607
		$Posts   = Posts::instance();
608
		$Request = Request::instance();
609
		$User    = User::instance();
610
		$Page->title($L->drafts);
611
		/**
612
		 * Determine current page
613
		 */
614
		$page = max(
615
			isset($Request->route_ids[0]) ? array_slice($Request->route_ids, -1)[0] : 1,
616
			1
617
		);
618
		/**
619
		 * If this is not first page - show that in page title
620
		 */
621
		if ($page > 1) {
622
			$Page->title($L->blogs_nav_page($page));
623
		}
624
		/**
625
		 * Get posts for current page in JSON-LD structure format
626
		 */
627
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
628
		$posts          = $Posts->get_drafts($User->id, $page, $posts_per_page);
629
		$posts_count    = $Posts->get_drafts_count($User->id);
630
		/**
631
		 * Base url (without page number)
632
		 */
633
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->drafts);
634
		/**
635
		 * Render posts page
636
		 */
637
		Helpers::show_posts_list(
638
			$posts,
639
			$posts_count,
640
			$page,
641
			$base_url
642
		);
643
	}
644
	static function atom_xml () {
645
		$Config   = Config::instance();
646
		$L        = new Prefix('blogs_');
647
		$Page     = Page::instance();
648
		$User     = User::instance();
649
		$title    = [
650
			get_core_ml_text('name'),
651
			$L->Blogs
652
		];
653
		$Posts    = Posts::instance();
654
		$Sections = Sections::instance();
655
		$Tags     = Tags::instance();
656
		$number   = $Config->module('Blogs')->posts_per_page;
657
		if (isset($_GET['section'])) {
658
			$section = $Sections->get($_GET['section']);
659
			if (!$section) {
660
				throw new ExitException(404);
661
			}
662
			$title[] = $L->section;
663
			$title[] = $section['title'];
664
			$posts   = $Posts->get_for_section($section['id'], 1, $number);
665
		} elseif (isset($_GET['tag'])) {
666
			$tag = $Tags->get($_GET['tag']);
667
			if (!$tag) {
668
				throw new ExitException(404);
669
			}
670
			$title[] = $L->tag;
671
			$title[] = $tag['text'];
672
			$posts   = $Posts->get_for_tag($tag['id'], $L->clang, 1, $number);
673
		} else {
674
			$posts = $Posts->get_latest_posts(1, $number);
675
		}
676
		$title[]  = $L->latest_posts;
677
		$title    = implode($Config->core['title_delimiter'], $title);
678
		$base_url = $Config->base_url();
679
		Response::instance()->header('content-type', 'application/atom+xml');
680
		$Page->interface = false;
681
682
		$url = $Config->core_url().Request::instance()->uri;
683
		$Page->content(
684
			"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
685
			h::feed(
686
				h::title($title).
687
				h::id($url).
688
				str_replace(
689
					'>',
690
					'/>',
691
					h::link(
692
						[
693
							'href' => $url,
694
							'rel'  => 'self'
695
						]
696
					)
697
				).
698
				h::updated(date('c')).
699
				'<icon>'.static::get_favicon_path($Config->core['theme'])."</icon>\n".
700
				h::entry(
701
					array_map(
702
						function ($post) use ($Posts, $Sections, $User, $base_url) {
703
							$post = $Posts->get($post);
704
							return
705
								h::title($post['title']).
706
								h::id("$base_url/Blogs/:$post[id]").
707
								h::updated(date('c', $post['date'])).
708
								h::published(date('c', $post['date'])).
709
								str_replace(
710
									'>',
711
									'/>',
712
									h::link(
713
										[
714
											'href' => "$base_url/Blogs/:$post[id]"
715
										]
716
									)
717
								).
718
								h::{'author name'}($User->username($post['user'])).
719
								h::category(
720
									$post['sections'] == ['0'] ? false : array_map(
721
										function ($category) {
722
											return [
723
												'term'  => $category['title'],
724
												'label' => $category['title']
725
											];
726
										},
727
										$Sections->get($post['sections'])
728
									)
729
								).
730
								h::summary(
731
									htmlentities($post['short_content']),
732
									[
733
										'type' => 'html'
734
									]
735
								).
736
								h::content(
737
									htmlentities($post['content']),
738
									[
739
										'type' => 'html'
740
									]
741
								);
742
						},
743
						$posts ?: []
744
					)
745
				),
746
				[
747
					'xmlns'    => 'http://www.w3.org/2005/Atom',
748
					'xml:lang' => $L->clang,
749
					'xml:base' => "$base_url/"
750
				]
751
			)
752
		);
753
	}
754
	protected static function get_favicon_path ($theme) {
755
		$theme_favicon = "$theme/img/favicon";
756
		if (file_exists(THEMES."/$theme_favicon.png")) {
757
			return "$theme_favicon.png";
758
		} elseif (file_exists(THEMES."/$theme_favicon.ico")) {
759
			return "$theme_favicon.ico";
760
		}
761
		return 'favicon.ico';
762
	}
763
}
764