Completed
Push — master ( 5f1043...5f6697 )
by Nazar
04:27
created

Controller::new_post()   D

Complexity

Conditions 18
Paths 10

Size

Total Lines 109
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 109
rs 4.7996
cc 18
eloc 73
nc 10
nop 2

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\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
		$data   = static::check_request_data($Request, $Page, $L);
327
		if ($data) {
328
			$Posts = Posts::instance();
329
			$id    = $Posts->add($data['title'], null, $data['content'], $data['sections'], _trim(explode(',', $data['tags'])), $data['mode'] == 'draft');
330
			if ($id) {
331
				$Response->redirect($Config->base_url()."/$module/".$Posts->get($id)['path'].":$id");
332
				return;
333
			} else {
334
				$Page->warning($L->post_adding_error);
335
			}
336
		}
337
		$disabled     = [];
338
		$max_sections = $module_data->max_sections;
339
		$content      = uniqid('post_content', true);
340
		$Page->replace($content, $Request->data('content') ?: '');
341
		$sections = get_sections_select_post($disabled);
342
		if (count($sections['in']) > 1) {
343
			$sections = [
344
				$L->post_section,
345
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
346
					$sections,
347
					[
348
						'name'     => 'sections[]',
349
						'disabled' => $disabled,
350
						'selected' => $Request->data('sections') ?: (isset($Request->route[1]) ? $Request->route[1] : []),
351
						$max_sections < 1 ? 'multiple' : false
352
					]
353
				).
354
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
355
			];
356
		} else {
357
			$sections = false;
358
		}
359
		$Page->content(
360
			h::form(
361
				h::{'h2.cs-text-center'}(
362
					$L->new_post
363
				).
364
				h::{'div.cs-blogs-post-preview-content'}().
365
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
366
					[
367
						$L->post_title,
368
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
369
							$Request->data('title') ?: '<br>'
370
						)
371
					],
372
					$sections,
373
					[
374
						$L->post_content,
375
						(functionality('inline_editor')
376
							? h::{'cs-editor-inline div.cs-blogs-new-post-content'}($content)
377
							: h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
378
								$Request->data('content') ?: ''
379
							)
380
						).
381
						h::br().
382
						$L->post_use_pagebreak
383
					],
384
					[
385
						$L->post_tags,
386
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
387
							[
388
								'value'       => $Request->data('tags') ?: false,
389
								'placeholder' => 'CleverStyle, CMS, Open Source'
390
							]
391
						)
392
					]
393
				).
394
				(
395
				!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : ''
396
				).
397
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
398
					$L->preview
399
				).
400
				h::{'button[is=cs-button][type=submit][name=mode][value=publish]'}(
401
					$L->publish
402
				).
403
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
404
					$L->to_drafts
405
				).
406
				h::{'button[is=cs-button]'}(
407
					$L->cancel,
408
					[
409
						'type'    => 'button',
410
						'onclick' => 'history.go(-1);'
411
					]
412
				)
413
			)
414
		);
415
	}
416
	/**
417
	 * @param \cs\Request $Request
418
	 * @param Page        $Page
419
	 * @param Prefix      $L
420
	 *
421
	 * @return array|false
422
	 */
423
	protected static function check_request_data ($Request, $Page, $L) {
424
		$data = $Request->data('title', 'sections', 'content', 'tags', 'mode');
425
		if ($data && in_array($data['mode'], ['draft', 'publish'])) {
426
			if (empty($data['title'])) {
427
				$Page->warning($L->post_title_empty);
428
				return false;
429
			}
430
			if (empty($data['sections']) && $data['sections'] !== '0') {
431
				$Page->warning($L->no_post_sections_specified);
432
				return false;
433
			}
434
			if (empty($data['content'])) {
435
				$Page->warning($L->post_content_empty);
436
				return false;
437
			}
438
			if (empty($data['tags'])) {
439
				$Page->warning($L->no_post_tags_specified);
440
				return false;
441
			}
442
		}
443
		return $data;
444
	}
445
	/**
446
	 * @param \cs\Request  $Request
447
	 * @param \cs\Response $Response
448
	 *
449
	 * @throws ExitException
450
	 */
451
	static function edit_post ($Request, $Response) {
452
		if (!Event::instance()->fire('Blogs/edit_post')) {
453
			return;
454
		}
455
456
		$Posts       = Posts::instance();
457
		$Config      = Config::instance();
458
		$module_data = $Config->module('Blogs');
459
		$L           = new Prefix('blogs_');
460
		$Page        = Page::instance();
461
		$User        = User::instance();
462
		if ($module_data->new_posts_only_from_admins && !$User->admin()) {
463
			throw new ExitException(403);
464
		}
465
		if (
466
			!isset($Request->route[1]) ||
467
			!($post = $Posts->get($Request->route[1]))
468
		) {
469
			throw new ExitException(404);
470
		}
471
		if (
472
			$post['user'] != $User->id &&
473
			!(
474
				$User->admin() &&
475
				$User->get_permission('admin/Blogs', 'index') &&
476
				$User->get_permission('admin/Blogs', 'edit_post')
477
			)
478
		) {
479
			throw new ExitException(403);
480
		}
481
		$Page->title(
482
			$L->editing_of_post($post['title'])
483
		);
484
		$module = path($L->Blogs);
485
		$data   = static::check_request_data($Request, $Page, $L);
486
		if ($data) {
487
			$result = $Posts->set(
488
				$post['id'],
489
				$data['title'],
490
				null,
491
				$data['content'],
492
				$data['sections'],
493
				_trim(explode(',', $data['tags'])),
494
				$data['mode'] == 'draft'
495
			);
496
			if ($result) {
497
				$Response->redirect($Config->base_url()."/$module/$post[path]:$post[id]");
498
				return;
499
			} else {
500
				$Page->warning($L->post_saving_error);
501
			}
502
		} elseif ($Request->data('mode') == 'delete') {
503
			if ($Posts->del($post['id'])) {
504
				$Response->redirect($Config->base_url()."/$module");
505
				return;
506
			} else {
507
				$Page->warning($L->post_deleting_error);
508
			}
509
		}
510
		$disabled     = [];
511
		$max_sections = $module_data->max_sections;
512
		$content      = uniqid('post_content', true);
513
		$Page->replace($content, $Request->data('content') ?: $post['content']);
514
		$sections = get_sections_select_post($disabled);
515
		if (count($sections['in']) > 1) {
516
			$sections = [
517
				$L->post_section,
518
				h::{'select.cs-blogs-new-post-sections[is=cs-select][size=7][required]'}(
519
					get_sections_select_post($disabled),
520
					[
521
						'name'     => 'sections[]',
522
						'disabled' => $disabled,
523
						'selected' => $Request->data('sections') ?: $post['sections'],
524
						$max_sections < 1 ? 'multiple' : false
525
					]
526
				).
527
				($max_sections > 1 ? h::br().$L->select_sections_num($max_sections) : '')
528
			];
529
		} else {
530
			$sections = false;
531
		}
532
		$Page->content(
533
			h::form(
534
				h::{'h2.cs-text-center'}(
535
					$L->editing_of_post($post['title'])
536
				).
537
				h::{'div.cs-blogs-post-preview-content'}().
538
				h::{'table.cs-table.cs-blogs-post-form[right-left] tr| td'}(
539
					[
540
						$L->post_title,
541
						h::{'h1.cs-blogs-new-post-title[contenteditable=true]'}(
542
							$Request->data('title') ?: $post['title']
543
						)
544
					],
545
					$sections,
546
					[
547
						$L->post_content,
548
						(
549
						functionality('inline_editor') ? h::{'cs-editor-inline div.cs-blogs-new-post-content'}(
550
							$content
551
						) : h::{'cs-editor textarea.cs-blogs-new-post-content[is=cs-textarea][autosize][name=content][required]'}(
552
							$Request->data('content') ?: $post['content']
553
						)
554
						).
555
						h::br().
556
						$L->post_use_pagebreak
557
					],
558
					[
559
						$L->post_tags,
560
						h::{'input.cs-blogs-new-post-tags[is=cs-input-text][name=tags][required]'}(
561
							[
562
								'value'       => $Request->data('tags') ?: implode(', ', $post['tags']),
563
								'placeholder' => 'CleverStyle, CMS, Open Source'
564
							]
565
						)
566
					]
567
				).
568
				(!$sections ? h::{'input[type=hidden][name=sections[]][value=0]'}() : '').
569
				h::{'button.cs-blogs-post-preview[is=cs-button]'}(
570
					$L->preview,
571
					[
572
						'data-id' => $post['id']
573
					]
574
				).
575
				h::{'button[is=cs-button][type=submit][name=mode][value=save]'}(
576
					$L->publish
577
				).
578
				h::{'button[is=cs-button][type=submit][name=mode][value=draft]'}(
579
					$L->to_drafts
580
				).
581
				h::{'button[is=cs-button][type=submit][name=mode][value=delete]'}(
582
					$L->delete
583
				).
584
				h::{'button[is=cs-button]'}(
585
					$L->cancel,
586
					[
587
						'type'    => 'button',
588
						'onclick' => 'history.go(-1);'
589
					]
590
				)
591
			)
592
		);
593
	}
594
	/**
595
	 * @param \cs\Request $Request
596
	 */
597
	static function drafts ($Request) {
598
		if (!Event::instance()->fire('Blogs/drafts')) {
599
			return;
600
		}
601
		$Config = Config::instance();
602
		$L      = new Prefix('blogs_');
603
		$Page   = Page::instance();
604
		$Posts  = Posts::instance();
605
		$User   = User::instance();
606
		$Page->title($L->drafts);
607
		/**
608
		 * Determine current page
609
		 */
610
		$page = static::get_page_and_set_title($Request, $Page, $L);
611
		/**
612
		 * Get posts for current page in JSON-LD structure format
613
		 */
614
		$posts_per_page = $Config->module('Blogs')->posts_per_page;
615
		$posts          = $Posts->get_drafts($User->id, $page, $posts_per_page);
616
		$posts_count    = $Posts->get_drafts_count($User->id);
617
		/**
618
		 * Base url (without page number)
619
		 */
620
		$base_url = $Config->base_url().'/'.path($L->Blogs).'/'.path($L->drafts);
621
		/**
622
		 * Render posts page
623
		 */
624
		Helpers::show_posts_list(
625
			$posts,
626
			$posts_count,
627
			$page,
628
			$base_url
629
		);
630
	}
631
	/**
632
	 * @param \cs\Request  $Request
633
	 * @param \cs\Response $Response
634
	 *
635
	 * @throws ExitException
636
	 */
637
	static function atom_xml ($Request, $Response) {
638
		$Config   = Config::instance();
639
		$L        = new Prefix('blogs_');
640
		$Page     = Page::instance();
641
		$User     = User::instance();
642
		$title    = [
643
			get_core_ml_text('name'),
644
			$L->Blogs
645
		];
646
		$Posts    = Posts::instance();
647
		$Sections = Sections::instance();
648
		$Tags     = Tags::instance();
649
		$number   = $Config->module('Blogs')->posts_per_page;
650
		$section  = $Request->query('section');
651
		$tag      = $Request->query('tag');
652
		if ($section) {
653
			$section = $Sections->get($section);
654
			if (!$section) {
655
				throw new ExitException(404);
656
			}
657
			$title[] = $L->section;
658
			$title[] = $section['title'];
659
			$posts   = $Posts->get_for_section($section['id'], 1, $number);
660
		} elseif ($tag) {
661
			$tag = $Tags->get($tag);
662
			if (!$tag) {
663
				throw new ExitException(404);
664
			}
665
			$title[] = $L->tag;
666
			$title[] = $tag['text'];
667
			$posts   = $Posts->get_for_tag($tag['id'], $L->clang, 1, $number);
668
		} else {
669
			$posts = $Posts->get_latest_posts(1, $number);
670
		}
671
		$title[]  = $L->latest_posts;
672
		$title    = implode($Config->core['title_delimiter'], $title);
673
		$base_url = $Config->base_url();
674
		$Response->header('content-type', 'application/atom+xml');
675
		$Page->interface = false;
676
677
		$url = $Config->core_url().$Request->uri;
678
		$Page->content(
679
			"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
680
			h::feed(
681
				h::title($title).
682
				h::id($url).
683
				str_replace(
684
					'>',
685
					'/>',
686
					h::link(
687
						[
688
							'href' => $url,
689
							'rel'  => 'self'
690
						]
691
					)
692
				).
693
				h::updated(date('c')).
694
				'<icon>'.static::get_favicon_path($Config->core['theme'])."</icon>\n".
695
				h::entry(
696
					array_map(
697
						function ($post) use ($Posts, $Sections, $User, $base_url) {
698
							$post = $Posts->get($post);
699
							return
700
								h::title($post['title']).
701
								h::id("$base_url/Blogs/:$post[id]").
702
								h::updated(date('c', $post['date'])).
703
								h::published(date('c', $post['date'])).
704
								str_replace(
705
									'>',
706
									'/>',
707
									h::link(
708
										[
709
											'href' => "$base_url/Blogs/:$post[id]"
710
										]
711
									)
712
								).
713
								h::{'author name'}($User->username($post['user'])).
714
								h::category(
715
									$post['sections'] == ['0'] ? false : array_map(
716
										function ($category) {
717
											return [
718
												'term'  => $category['title'],
719
												'label' => $category['title']
720
											];
721
										},
722
										$Sections->get($post['sections'])
723
									)
724
								).
725
								h::summary(
726
									htmlentities($post['short_content']),
727
									[
728
										'type' => 'html'
729
									]
730
								).
731
								h::content(
732
									htmlentities($post['content']),
733
									[
734
										'type' => 'html'
735
									]
736
								);
737
						},
738
						$posts ?: []
739
					)
740
				),
741
				[
742
					'xmlns'    => 'http://www.w3.org/2005/Atom',
743
					'xml:lang' => $L->clang,
744
					'xml:base' => "$base_url/"
745
				]
746
			)
747
		);
748
	}
749
	/**
750
	 * @param string $theme
751
	 *
752
	 * @return string
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