Completed
Push — master ( 56bfde...5f1043 )
by Nazar
04:19
created

Controller::atom_xml()   C

Complexity

Conditions 7
Paths 5

Size

Total Lines 110
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 110
rs 6.4589
cc 7
eloc 79
nc 5
nop 2

How to fix   Long Method   

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\User,
18
	h;
19
20
class Controller {
21
	/**
22
	 * @param \cs\Request $Request
23
	 */
24
	static function latest_posts ($Request) {
25
		if (!Event::instance()->fire('Blogs/latest_posts')) {
26
			return;
27
		}
28
		$Config = Config::instance();
29
		$L      = new Prefix('blogs_');
30
		$Meta   = Meta::instance();
31
		$Page   = Page::instance();
32
		$Posts  = Posts::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 = static::get_page_and_set_title($Request, $Page, $L);
49
		/**
50
		 * Get posts for current page in JSON-LD structure format
51
		 */
52
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
53
		$posts          = $Posts->get_latest_posts($page, $posts_per_page);
54
		/**
55
		 * Base url (without page number)
56
		 */
57
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->latest_posts);
58
		/**
59
		 * Render posts page
60
		 */
61
		Helpers::show_posts_list(
62
			$posts,
63
			$Posts->get_total_count(),
64
			$page,
65
			$base_url
66
		);
67
	}
68
	/**
69
	 * @param \cs\Request $Request
70
	 * @param Page        $Page
71
	 * @param Prefix      $L
72
	 *
73
	 * @return int
74
	 */
75
	protected static function get_page_and_set_title ($Request, $Page, $L) {
76
		$page = max(
77
			isset($Request->route_ids[0]) ? array_slice($Request->route_ids, -1)[0] : 1,
78
			1
79
		);
80
		/**
81
		 * If this is not first page - show that in page title
82
		 */
83
		if ($page > 1) {
84
			$Page->title($L->page_number($page));
85
		}
86
		return $page;
87
	}
88
	/**
89
	 * @param \cs\Request $Request
90
	 *
91
	 * @throws ExitException
92
	 */
93
	static function section ($Request) {
94
		if (!Event::instance()->fire('Blogs/section')) {
95
			return;
96
		}
97
		$Config   = Config::instance();
98
		$L        = new Prefix('blogs_');
99
		$Meta     = Meta::instance();
100
		$Page     = Page::instance();
101
		$Posts    = Posts::instance();
102
		$Sections = Sections::instance();
103
		/**
104
		 * At first - determine part of url and get sections list based on that path
105
		 */
106
		$sections = $Sections->get_by_path(
107
			array_slice($Request->route_path, 1)
108
		);
109
		if (!$sections) {
110
			throw new ExitException(400);
111
		}
112
		$sections = $Sections->get($sections);
113
		/**
114
		 * Now lets set page title using sections names from page path
115
		 * We will not remove `$section` variable after, since it will be direct parent of each shown post
116
		 */
117
		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...
118
			$Page->title($section['title']);
119
		}
120
		/**
121
		 * Now add link to Atom feed for posts from current section only
122
		 */
123
		/** @noinspection PhpUndefinedVariableInspection */
124
		$Page->atom(
125
			"Blogs/atom.xml/?section=$section[id]",
126
			implode($Config->core['title_delimiter'], [$L->latest_posts, $L->section, $section['title']])
127
		);
128
		/**
129
		 * Set page of blog type (Open Graph protocol)
130
		 */
131
		$Meta->blog();
132
		/**
133
		 * Determine current page
134
		 */
135
		$page = static::get_page_and_set_title($Request, $Page, $L);
136
		/**
137
		 * Get posts for current page in JSON-LD structure format
138
		 */
139
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
140
		$posts          = $Posts->get_for_section($section['id'], $page, $posts_per_page);
141
		/**
142
		 * Base url (without page number)
143
		 */
144
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->section)."/$section[full_path]";
145
		/**
146
		 * Render posts page
147
		 */
148
		Helpers::show_posts_list(
149
			$posts,
150
			$section['posts'],
151
			$page,
152
			$base_url
153
		);
154
	}
155
	/**
156
	 * @param \cs\Request  $Request
157
	 * @param \cs\Response $Response
158
	 *
159
	 * @throws ExitException
160
	 */
161
	static function post ($Request, $Response) {
162
		if (!Event::instance()->fire('Blogs/post')) {
163
			return;
164
		}
165
166
		$Config   = Config::instance();
167
		$Page     = Page::instance();
168
		$User     = User::instance();
169
		$Comments = null;
170
		Event::instance()->fire(
171
			'Comments/instance',
172
			[
173
				'Comments' => &$Comments
174
			]
175
		);
176
		/**
177
		 * @var \cs\modules\Comments\Comments $Comments
178
		 */
179
		$Posts   = Posts::instance();
180
		$rc      = $Request->route;
181
		$post_id = (int)mb_substr($rc[1], mb_strrpos($rc[1], ':') + 1);
182
		if (!$post_id) {
183
			throw new ExitException(404);
184
		}
185
		$post = $Posts->get_as_json_ld($post_id);
186
		if (
187
			!$post ||
188
			(
189
				$post['draft'] && $post['user'] != $User->id
190
			)
191
		) {
192
			throw new ExitException(404);
193
		}
194
		if ($post['path'] != mb_substr($rc[1], 0, mb_strrpos($rc[1], ':'))) {
195
			$Response->redirect($post['url'], 303);
196
			return;
197
		}
198
		$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...
199
		$Page->Description = description($post['short_content']);
200
		$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...
201
		$Meta = Meta::instance();
202
		$Meta
203
			->article()
204
			->article('published_time', date('Y-m-d', $post['date'] ?: TIME))
205
			->article('section', $post['articleSection'] ? $post['articleSection'][0] : false)
206
			->article('tag', $post['tags']);
207
		array_map([$Meta, 'image'], $post['image']);
208
		$comments_enabled = $Config->module('Blogs')->enable_comments && $Comments;
209
		$is_admin         =
210
			$User->admin() &&
211
			$User->get_permission('admin/Blogs', 'index') &&
212
			$User->get_permission('admin/Blogs', 'edit_post');
213
		$Page->content(
214
			h::{'article[is=cs-blogs-post]'}(
215
				h::{'script[type=application/ld+json]'}(
216
					json_encode($post, JSON_UNESCAPED_UNICODE)
217
				),
218
				[
219
					'comments_enabled' => $comments_enabled,
220
					'can_edit'         => $is_admin || $User->id == $post['user'],
221
					'can_delete'       => $is_admin
222
				]
223
			).
224
			($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...
225
		);
226
	}
227
	/**
228
	 * @param \cs\Request $Request
229
	 *
230
	 * @throws ExitException
231
	 */
232
	static function tag ($Request) {
233
		if (!Event::instance()->fire('Blogs/tag')) {
234
			return;
235
		}
236
		$Config = Config::instance();
237
		$L      = new Prefix('blogs_');
238
		$Meta   = Meta::instance();
239
		$Page   = Page::instance();
240
		$Posts  = Posts::instance();
241
		$Tags   = Tags::instance();
242
		/**
243
		 * If no tag specified
244
		 */
245
		if (!isset($Request->route[1])) {
246
			throw new ExitException(404);
247
		}
248
		/**
249
		 * Find tag
250
		 */
251
		$tag = $Tags->get_by_text($Request->route[1]);
252
		if (!$tag) {
253
			throw new ExitException(404);
254
		}
255
		$tag = $Tags->get($tag);
256
		/**
257
		 * Add tag to page title
258
		 */
259
		$Page->title($tag['text']);
260
		/**
261
		 * Now add link to Atom feed for posts with current tag only
262
		 */
263
		$Page->atom(
264
			"Blogs/atom.xml/?tag=$tag[id]",
265
			implode($Config->core['title_delimiter'], [$L->latest_posts, $L->tag, $tag['text']])
266
		);
267
		/**
268
		 * Set page of blog type (Open Graph protocol)
269
		 */
270
		$Meta->blog();
271
		/**
272
		 * Determine current page
273
		 */
274
		$page = max($Request->route(2) ?: 1, 1);
275
		/**
276
		 * If this is not first page - show that in page title
277
		 */
278
		if ($page > 1) {
279
			$Page->title($L->blogs_nav_page($page));
280
		}
281
		/**
282
		 * Get posts for current page in JSON-LD structure format
283
		 */
284
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
285
		$posts          = $Posts->get_for_tag($tag['id'], $L->clang, $page, $posts_per_page);
286
		$posts_count    = $Posts->get_for_tag_count($tag['id'], $L->clang);
287
		/**
288
		 * Base url (without page number)
289
		 */
290
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->tag).'/'.$Request->route[1];
291
		/**
292
		 * Render posts page
293
		 */
294
		Helpers::show_posts_list(
295
			$posts,
296
			$posts_count,
297
			$page,
298
			$base_url
299
		);
300
	}
301
	/**
302
	 * @param \cs\Request  $Request
303
	 * @param \cs\Response $Response
304
	 *
305
	 * @throws ExitException
306
	 */
307
	static function new_post ($Request, $Response) {
308
		if (!Event::instance()->fire('Blogs/new_post')) {
309
			return;
310
		}
311
312
		$Config      = Config::instance();
313
		$module_data = $Config->module('Blogs');
314
		$L           = new Prefix('blogs_');
315
		$Page        = Page::instance();
316
		$User        = User::instance();
317
		$Page->title($L->new_post);
318
		if (!$User->admin() && $module_data->new_posts_only_from_admins) {
319
			throw new ExitException(403);
320
		}
321
		if (!$User->user()) {
322
			$Page->warning($L->for_registered_users_only);
323
			return;
324
		}
325
		$module = path($L->Blogs);
326
		if (isset($_POST['title'], $_POST['sections'], $_POST['content'], $_POST['tags'], $_POST['mode'])) {
327
			$draft = false;
328
			switch ($_POST['mode']) {
329
				case 'draft':
330
					$draft = true;
331
				case 'publish':
332
					$save = true;
333
					if (empty($_POST['title'])) {
334
						$Page->warning($L->post_title_empty);
335
						$save = false;
336
					}
337
					if (empty($_POST['sections']) && $_POST['sections'] !== '0') {
338
						$Page->warning($L->no_post_sections_specified);
339
						$save = false;
340
					}
341
					if (empty($_POST['content'])) {
342
						$Page->warning($L->post_content_empty);
343
						$save = false;
344
					}
345
					if (empty($_POST['tags'])) {
346
						$Page->warning($L->no_post_tags_specified);
347
						$save = false;
348
					}
349
					if ($save) {
350
						$Posts = Posts::instance();
351
						$id    = $Posts->add($_POST['title'], null, $_POST['content'], $_POST['sections'], _trim(explode(',', $_POST['tags'])), $draft);
352
						if ($id) {
353
							$Page->interface = false;
354
							$Response->redirect($Config->base_url()."/$module/".$Posts->get($id)['path'].":$id");
355
							return;
356
						} else {
357
							$Page->warning($L->post_adding_error);
358
						}
359
					}
360
					break;
361
			}
362
		}
363
		$disabled     = [];
364
		$max_sections = $module_data->max_sections;
365
		$content      = uniqid('post_content', true);
366
		$Page->replace($content, isset($_POST['content']) ? $_POST['content'] : '');
367
		$sections = get_sections_select_post($disabled);
368
		if (count($sections['in']) > 1) {
369
			$sections = [
370
				$L->post_section,
371
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
372
					$sections,
373
					[
374
						'name'     => 'sections[]',
375
						'disabled' => $disabled,
376
						'selected' => isset($_POST['sections']) ? $_POST['sections'] : (isset($Request->route[1]) ? $Request->route[1] : []),
377
						$max_sections < 1 ? 'multiple' : false
378
					]
379
				).
380
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
381
			];
382
		} else {
383
			$sections = false;
384
		}
385
		$Page->content(
386
			h::form(
387
				h::{'h2.cs-text-center'}(
388
					$L->new_post
389
				).
390
				h::{'div.cs-blogs-post-preview-content'}().
391
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
392
					[
393
						$L->post_title,
394
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
395
							isset($_POST['title']) ? $_POST['title'] : '<br>'
396
						)
397
					],
398
					$sections,
399
					[
400
						$L->post_content,
401
						(
402
						functionality('inline_editor') ? h::{'cs-editor-inline div.cs-blogs-new-post-content'}(
403
							$content
404
						) : h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
405
							isset($_POST['content']) ? $_POST['content'] : ''
406
						)
407
						).
408
						h::br().
409
						$L->post_use_pagebreak
410
					],
411
					[
412
						$L->post_tags,
413
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
414
							[
415
								'value'       => isset($_POST['tags']) ? $_POST['tags'] : false,
416
								'placeholder' => 'CleverStyle, CMS, Open Source'
417
							]
418
						)
419
					]
420
				).
421
				(
422
				!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : ''
423
				).
424
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
425
					$L->preview
426
				).
427
				h::{'button[is=cs-button][type=submit][name=mode][value=publish]'}(
428
					$L->publish
429
				).
430
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
431
					$L->to_drafts
432
				).
433
				h::{'button[is=cs-button]'}(
434
					$L->cancel,
435
					[
436
						'type'    => 'button',
437
						'onclick' => 'history.go(-1);'
438
					]
439
				)
440
			)
441
		);
442
	}
443
	/**
444
	 * @param \cs\Request  $Request
445
	 * @param \cs\Response $Response
446
	 *
447
	 * @throws ExitException
448
	 */
449
	static function edit_post ($Request, $Response) {
450
		if (!Event::instance()->fire('Blogs/edit_post')) {
451
			return;
452
		}
453
454
		$Posts       = Posts::instance();
455
		$Config      = Config::instance();
456
		$module_data = $Config->module('Blogs');
457
		$L           = new Prefix('blogs_');
458
		$Page        = Page::instance();
459
		$User        = User::instance();
460
		if ($module_data->new_posts_only_from_admins && !$User->admin()) {
461
			throw new ExitException(403);
462
		}
463
		if (
464
			!isset($Request->route[1]) ||
465
			!($post = $Posts->get($Request->route[1]))
466
		) {
467
			throw new ExitException(404);
468
		}
469
		if (
470
			$post['user'] != $User->id &&
471
			!(
472
				$User->admin() &&
473
				$User->get_permission('admin/Blogs', 'index') &&
474
				$User->get_permission('admin/Blogs', 'edit_post')
475
			)
476
		) {
477
			throw new ExitException(403);
478
		}
479
		$Page->title(
480
			$L->editing_of_post($post['title'])
481
		);
482
		$module = path($L->Blogs);
483
		if (isset($_POST['title'], $_POST['sections'], $_POST['content'], $_POST['tags'], $_POST['mode'])) {
484
			$draft = false;
485
			switch ($_POST['mode']) {
486
				case 'draft':
487
					$draft = true;
488
				case 'save':
489
					$save = true;
490
					if (empty($_POST['title'])) {
491
						$Page->warning($L->post_title_empty);
492
						$save = false;
493
					}
494
					if (empty($_POST['sections']) && $_POST['sections'] !== '0') {
495
						$Page->warning($L->no_post_sections_specified);
496
						$save = false;
497
					}
498
					if (empty($_POST['content'])) {
499
						$Page->warning($L->post_content_empty);
500
						$save = false;
501
					}
502
					if (empty($_POST['tags'])) {
503
						$Page->warning($L->no_post_tags_specified);
504
						$save = false;
505
					}
506
					if ($save) {
507
						if ($Posts->set(
508
							$post['id'],
509
							$_POST['title'],
510
							null,
511
							$_POST['content'],
512
							$_POST['sections'],
513
							_trim(explode(',', $_POST['tags'])),
514
							$draft
515
						)
516
						) {
517
							$Page->interface = false;
518
							$Response->redirect($Config->base_url()."/$module/$post[path]:$post[id]");
519
							return;
520
						} else {
521
							$Page->warning($L->post_saving_error);
522
						}
523
					}
524
					break;
525
				case 'delete':
526
					if ($Posts->del($post['id'])) {
527
						$Page->interface = false;
528
						$Response->redirect($Config->base_url()."/$module");
529
						return;
530
					} else {
531
						$Page->warning($L->post_deleting_error);
532
					}
533
					break;
534
			}
535
		}
536
		$disabled     = [];
537
		$max_sections = $module_data->max_sections;
538
		$content      = uniqid('post_content', true);
539
		$Page->replace($content, isset($_POST['content']) ? $_POST['content'] : $post['content']);
540
		$sections = get_sections_select_post($disabled);
541
		if (count($sections['in']) > 1) {
542
			$sections = [
543
				$L->post_section,
544
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
545
					get_sections_select_post($disabled),
546
					[
547
						'name'     => 'sections[]',
548
						'disabled' => $disabled,
549
						'selected' => isset($_POST['sections']) ? $_POST['sections'] : $post['sections'],
550
						$max_sections < 1 ? 'multiple' : false
551
					]
552
				).
553
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
554
			];
555
		} else {
556
			$sections = false;
557
		}
558
		$Page->content(
559
			h::form(
560
				h::{'h2.cs-text-center'}(
561
					$L->editing_of_post($post['title'])
562
				).
563
				h::{'div.cs-blogs-post-preview-content'}().
564
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
565
					[
566
						$L->post_title,
567
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
568
							isset($_POST['title']) ? $_POST['title'] : $post['title']
569
						)
570
					],
571
					$sections,
572
					[
573
						$L->post_content,
574
						(
575
						functionality('inline_editor') ? h::{'cs-editor-inline div.cs-blogs-new-post-content'}(
576
							$content
577
						) : h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
578
							isset($_POST['content']) ? $_POST['content'] : $post['content']
579
						)
580
						).
581
						h::br().
582
						$L->post_use_pagebreak
583
					],
584
					[
585
						$L->post_tags,
586
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
587
							[
588
								'value'       => htmlspecialchars_decode(
589
									isset($_POST['tags']) ? $_POST['tags'] : implode(', ', $post['tags']),
590
									ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED | ENT_SUBSTITUTE
591
								),
592
								'placeholder' => 'CleverStyle, CMS, Open Source'
593
							]
594
						)
595
					]
596
				).
597
				(!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : '').
598
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
599
					$L->preview,
600
					[
601
						'data-id' => $post['id']
602
					]
603
				).
604
				h::{'button[is=cs-button][type=submit][name=mode][value=save]'}(
605
					$L->publish
606
				).
607
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
608
					$L->to_drafts
609
				).
610
				h::{'button[is=cs-button][type=submit][name=mode][value=delete]'}(
611
					$L->delete
612
				).
613
				h::{'button[is=cs-button]'}(
614
					$L->cancel,
615
					[
616
						'type'    => 'button',
617
						'onclick' => 'history.go(-1);'
618
					]
619
				)
620
			)
621
		);
622
	}
623
	/**
624
	 * @param \cs\Request $Request
625
	 */
626
	static function drafts ($Request) {
627
		if (!Event::instance()->fire('Blogs/drafts')) {
628
			return;
629
		}
630
		$Config = Config::instance();
631
		$L      = new Prefix('blogs_');
632
		$Page   = Page::instance();
633
		$Posts  = Posts::instance();
634
		$User   = User::instance();
635
		$Page->title($L->drafts);
636
		/**
637
		 * Determine current page
638
		 */
639
		$page = static::get_page_and_set_title($Request, $Page, $L);
640
		/**
641
		 * Get posts for current page in JSON-LD structure format
642
		 */
643
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
644
		$posts          = $Posts->get_drafts($User->id, $page, $posts_per_page);
645
		$posts_count    = $Posts->get_drafts_count($User->id);
646
		/**
647
		 * Base url (without page number)
648
		 */
649
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->drafts);
650
		/**
651
		 * Render posts page
652
		 */
653
		Helpers::show_posts_list(
654
			$posts,
655
			$posts_count,
656
			$page,
657
			$base_url
658
		);
659
	}
660
	/**
661
	 * @param \cs\Request  $Request
662
	 * @param \cs\Response $Response
663
	 *
664
	 * @throws ExitException
665
	 */
666
	static function atom_xml ($Request, $Response) {
667
		$Config   = Config::instance();
668
		$L        = new Prefix('blogs_');
669
		$Page     = Page::instance();
670
		$User     = User::instance();
671
		$title    = [
672
			get_core_ml_text('name'),
673
			$L->Blogs
674
		];
675
		$Posts    = Posts::instance();
676
		$Sections = Sections::instance();
677
		$Tags     = Tags::instance();
678
		$number   = $Config->module('Blogs')->posts_per_page;
679
		if (isset($_GET['section'])) {
680
			$section = $Sections->get($_GET['section']);
681
			if (!$section) {
682
				throw new ExitException(404);
683
			}
684
			$title[] = $L->section;
685
			$title[] = $section['title'];
686
			$posts   = $Posts->get_for_section($section['id'], 1, $number);
687
		} elseif (isset($_GET['tag'])) {
688
			$tag = $Tags->get($_GET['tag']);
689
			if (!$tag) {
690
				throw new ExitException(404);
691
			}
692
			$title[] = $L->tag;
693
			$title[] = $tag['text'];
694
			$posts   = $Posts->get_for_tag($tag['id'], $L->clang, 1, $number);
695
		} else {
696
			$posts = $Posts->get_latest_posts(1, $number);
697
		}
698
		$title[]  = $L->latest_posts;
699
		$title    = implode($Config->core['title_delimiter'], $title);
700
		$base_url = $Config->base_url();
701
		$Response->header('content-type', 'application/atom+xml');
702
		$Page->interface = false;
703
704
		$url = $Config->core_url().$Request->uri;
705
		$Page->content(
706
			"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
707
			h::feed(
708
				h::title($title).
709
				h::id($url).
710
				str_replace(
711
					'>',
712
					'/>',
713
					h::link(
714
						[
715
							'href' => $url,
716
							'rel'  => 'self'
717
						]
718
					)
719
				).
720
				h::updated(date('c')).
721
				'<icon>'.static::get_favicon_path($Config->core['theme'])."</icon>\n".
722
				h::entry(
723
					array_map(
724
						function ($post) use ($Posts, $Sections, $User, $base_url) {
725
							$post = $Posts->get($post);
726
							return
727
								h::title($post['title']).
728
								h::id("$base_url/Blogs/:$post[id]").
729
								h::updated(date('c', $post['date'])).
730
								h::published(date('c', $post['date'])).
731
								str_replace(
732
									'>',
733
									'/>',
734
									h::link(
735
										[
736
											'href' => "$base_url/Blogs/:$post[id]"
737
										]
738
									)
739
								).
740
								h::{'author name'}($User->username($post['user'])).
741
								h::category(
742
									$post['sections'] == ['0'] ? false : array_map(
743
										function ($category) {
744
											return [
745
												'term'  => $category['title'],
746
												'label' => $category['title']
747
											];
748
										},
749
										$Sections->get($post['sections'])
750
									)
751
								).
752
								h::summary(
753
									htmlentities($post['short_content']),
754
									[
755
										'type' => 'html'
756
									]
757
								).
758
								h::content(
759
									htmlentities($post['content']),
760
									[
761
										'type' => 'html'
762
									]
763
								);
764
						},
765
						$posts ?: []
766
					)
767
				),
768
				[
769
					'xmlns'    => 'http://www.w3.org/2005/Atom',
770
					'xml:lang' => $L->clang,
771
					'xml:base' => "$base_url/"
772
				]
773
			)
774
		);
775
	}
776
	/**
777
	 * @param string $theme
778
	 *
779
	 * @return string
780
	 */
781
	protected static function get_favicon_path ($theme) {
782
		$theme_favicon = "$theme/img/favicon";
783
		if (file_exists(THEMES."/$theme_favicon.png")) {
784
			return "$theme_favicon.png";
785
		} elseif (file_exists(THEMES."/$theme_favicon.ico")) {
786
			return "$theme_favicon.ico";
787
		}
788
		return 'favicon.ico';
789
	}
790
}
791