Completed
Push — master ( 061e97...b7fcec )
by Nazar
04:11
created

Page::prepare()   C

Complexity

Conditions 7
Paths 3

Size

Total Lines 92
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 92
rs 6.4983
cc 7
eloc 55
nc 3
nop 0

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   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
use
10
	h,
11
	cs\Page\Includes,
12
	cs\Page\Meta;
13
14
/**
15
 * @method static Page instance($check = false)
16
 */
17
class Page {
18
	use
19
		Singleton,
20
		Includes;
21
	public $Content;
22
	public $interface   = true;
23
	public $pre_Html    = '';
24
	public $Html        = '';
25
	public $Description = '';
26
	/**
27
	 * @var string|string[]
28
	 */
29
	public $Title     = [];
30
	public $Head      = '';
31
	public $pre_Body  = '';
32
	public $Left      = '';
33
	public $Top       = '';
34
	public $Right     = '';
35
	public $Bottom    = '';
36
	public $post_Body = '';
37
	public $post_Html = '';
38
	/**
39
	 * Number of tabs by default for indentation the substitution of values into template
40
	 *
41
	 * @var array
42
	 */
43
	public $level = [
44
		'Head'      => 0,
45
		'pre_Body'  => 1,
46
		'Left'      => 3,
47
		'Top'       => 3,
48
		'Content'   => 4,
49
		'Bottom'    => 3,
50
		'Right'     => 3,
51
		'post_Body' => 1
52
	];
53
	/**
54
	 * @var array[]
55
	 */
56
	protected $link = [];
57
	/**
58
	 * @var string[]
59
	 */
60
	protected $search_replace = [];
61
	/**
62
	 * @var false|string
63
	 */
64
	protected $canonical_url      = false;
65
	protected $theme;
66
	protected $error_showed       = false;
67
	protected $finish_called_once = false;
68
	/**
69
	 * @param string $property
70
	 *
71
	 * @return false|null|string
72
	 */
73
	function __get ($property) {
74
		// For internal use by \cs\Meta class
75
		if ($property === 'canonical_url') {
76
			return $this->canonical_url;
77
		}
78
		return false;
79
	}
80
	/**
81
	 * Initialization: setting of title and theme according to specified parameters
82
	 *
83
	 * @param string $title
84
	 * @param string $theme
85
	 *
86
	 * @return Page
87
	 */
88
	function init ($title, $theme) {
89
		$this->Title[0] = htmlentities($title, ENT_COMPAT, 'utf-8');
90
		$this->set_theme($theme);
91
		return $this;
92
	}
93
	/**
94
	 * Theme changing
95
	 *
96
	 * @param string $theme
97
	 *
98
	 * @return Page
99
	 */
100
	function set_theme ($theme) {
101
		$this->theme = $theme;
102
		return $this;
103
	}
104
	/**
105
	 * Adding of content on the page
106
	 *
107
	 * @param string   $add
108
	 * @param bool|int $level
109
	 *
110
	 * @return Page
111
	 */
112
	function content ($add, $level = false) {
113
		if ($level !== false) {
114
			$this->Content .= h::level($add, $level);
115
		} else {
116
			$this->Content .= $add;
117
		}
118
		return $this;
119
	}
120
	/**
121
	 * Sets body with content, that is transformed into JSON format
122
	 *
123
	 * @param mixed $add
124
	 *
125
	 * @return Page
126
	 */
127
	function json ($add) {
128
		_header('Content-Type: application/json; charset=utf-8', true);
129
		interface_off();
130
		$this->Content = _json_encode($add);
131
		return $this;
132
	}
133
	/**
134
	 * Loading of theme template
135
	 *
136
	 * @return bool
137
	 */
138
	protected function get_template () {
139
		/**
140
		 * Theme is fixed for administration, and may vary for other pages
141
		 */
142
		if (admin_path()) {
143
			$this->theme = 'CleverStyle';
144
		}
145
		$theme_dir = THEMES."/$this->theme";
146
		_include("$theme_dir/prepare.php", false, false);
147
		ob_start();
148
		$return = true;
149
		/**
150
		 * If website is closed and user is not an administrator - send `503 Service Unavailable` header and show closed site page
151
		 */
152
		if (
153
			!Config::instance()->core['site_mode'] &&
154
			!User::instance(true)->admin() &&
155
			status_code(503) &&
156
			!_include("$theme_dir/closed.php", false, false) &&
157
			!_include("$theme_dir/closed.html", false, false)
158
		) {
159
			echo
160
				"<!doctype html>\n".
161
				h::title(get_core_ml_text('closed_title')).
162
				get_core_ml_text('closed_text');
163
			$return = false;
164
		} else {
165
			_include("$theme_dir/index.php", false, false) || _include("$theme_dir/index.html");
166
		}
167
		$this->Html = ob_get_clean();
168
		return $return;
169
	}
170
	/**
171
	 * Processing of template, substituting of content, preparing for the output
172
	 *
173
	 * @return Page
0 ignored issues
show
Documentation introduced by
Should the return type not be Page|null?

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

Loading history...
174
	 */
175
	protected function prepare () {
176
		$Config = Config::instance(true);
177
		/**
178
		 * Loading of template
179
		 */
180
		if (!$this->get_template()) {
181
			return;
182
		}
183
		/**
184
		 * Forming page title
185
		 */
186
		$this->Title = array_filter($this->Title, 'trim');
187
		$this->Title = $Config->core['title_reverse'] ? array_reverse($this->Title) : $this->Title;
188
		$this->Title = implode($Config->core['title_delimiter'] ?: '|', $this->Title);
189
		/**
190
		 * Forming <head> content
191
		 */
192
		$this->Head =
193
			h::title($this->Title).
194
			h::meta(
195
				[
196
					'charset' => 'utf-8'
197
				]
198
			).
199
			h::meta(
200
				$this->Description ? [
201
					'name'    => 'description',
202
					'content' => $this->Description
203
				] : false
204
			).
205
			h::meta(
206
				[
207
					'name'    => 'generator',
208
					'content' => 'CleverStyle CMS by Mokrynskyi Nazar'
209
				]
210
			).
211
			h::base(
212
				$Config ? [
213
					'href' => $Config->base_url().'/'
214
				] : false
215
			).
216
			$this->Head.
217
			h::link(
218
				[
219
					'rel'  => 'shortcut icon',
220
					'href' => $this->get_favicon_path()
221
				]
222
			).
223
			h::link(array_values($this->link) ?: false);
224
		/**
225
		 * Addition of CSS, JavaScript and Web Components includes
226
		 */
227
		$this->add_includes_on_page();
228
		/**
229
		 * Generation of Open Graph protocol information
230
		 */
231
		Meta::instance()->render();
232
		/**
233
		 * Substitution of information into template
234
		 */
235
		$this->Html = str_replace(
236
			[
237
				'<!--pre_Html-->',
238
				'<!--head-->',
239
				'<!--pre_Body-->',
240
				'<!--left_blocks-->',
241
				'<!--top_blocks-->',
242
				'<!--content-->',
243
				'<!--bottom_blocks-->',
244
				'<!--right_blocks-->',
245
				'<!--post_Body-->',
246
				'<!--post_Html-->'
247
			],
248
			_rtrim(
249
				[
250
					$this->pre_Html,
251
					$this->get_property_with_indentation('Head'),
252
					$this->get_property_with_indentation('pre_Body'),
253
					$this->get_property_with_indentation('Left'),
254
					$this->get_property_with_indentation('Top'),
255
					$this->get_property_with_indentation('Content'),
256
					$this->get_property_with_indentation('Bottom'),
257
					$this->get_property_with_indentation('Right'),
258
					$this->get_property_with_indentation('post_Body'),
259
					$this->post_Html
260
				],
261
				"\t"
262
			),
263
			$this->Html
264
		);
265
		return $this;
266
	}
267
	/**
268
	 * @return string
269
	 */
270
	protected function get_favicon_path () {
271
		$file = file_exists_with_extension(THEMES."/$this->theme/img/favicon", ['png', 'ico']);
272
		if ($file) {
273
			return str_replace(THEMES, 'themes', $file);
274
		}
275
		return 'favicon.ico';
276
	}
277
	/**
278
	 * @param string $property
279
	 *
280
	 * @return string
281
	 */
282
	protected function get_property_with_indentation ($property) {
283
		return h::level($this->$property, $this->level[$property]);
284
	}
285
	/**
286
	 * Replacing anything in source code of finally generated page
287
	 *
288
	 * Parameters may be both simply strings for str_replace() and regular expressions for preg_replace()
289
	 *
290
	 * @param string|string[] $search
291
	 * @param string|string[] $replace
292
	 *
293
	 * @return Page
294
	 */
295
	function replace ($search, $replace = '') {
296
		if (is_array($search)) {
297
			$this->search_replace = $search + $this->search_replace;
298
		} else {
299
			$this->search_replace[$search] = $replace;
300
		}
301
		return $this;
302
	}
303
	/**
304
	 * Processing of replacing in content
305
	 *
306
	 * @param string $content
307
	 *
308
	 * @return string
309
	 */
310
	protected function process_replacing ($content) {
311
		foreach ($this->search_replace as $search => $replace) {
312
			$content = _preg_replace($search, $replace, $content) ?: str_replace($search, $replace, $content);
313
		}
314
		$this->search_replace = [];
315
		return $content;
316
	}
317
	/**
318
	 * Adding links
319
	 *
320
	 * @param array $data According to h class syntax
321
	 *
322
	 * @return Page
323
	 */
324
	function link ($data) {
325
		if ($data !== false) {
326
			$this->link[] = $data;
327
		}
328
		return $this;
329
	}
330
	/**
331
	 * Simple wrapper of $Page->link() for inserting Atom feed on page
332
	 *
333
	 * @param string $href
334
	 * @param string $title
335
	 *
336
	 * @return Page
337
	 */
338
	function atom ($href, $title = 'Atom Feed') {
339
		return $this->link(
340
			[
341
				'href'  => $href,
342
				'title' => $title,
343
				'rel'   => 'alternate',
344
				'type'  => 'application/atom+xml'
345
			]
346
		);
347
	}
348
	/**
349
	 * Simple wrapper of $Page->link() for inserting RSS feed on page
350
	 *
351
	 * @param string $href
352
	 * @param string $title
353
	 *
354
	 * @return Page
355
	 */
356
	function rss ($href, $title = 'RSS Feed') {
357
		return $this->link(
358
			[
359
				'href'  => $href,
360
				'title' => $title,
361
				'rel'   => 'alternate',
362
				'type'  => 'application/rss+xml'
363
			]
364
		);
365
	}
366
	/**
367
	 * Specify canonical url of current page
368
	 *
369
	 * @param string $url
370
	 *
371
	 * @return Page
372
	 */
373
	function canonical_url ($url) {
374
		$this->canonical_url         = $url;
375
		$this->link['canonical_url'] = [
376
			'href' => $this->canonical_url,
377
			'rel'  => 'canonical'
378
		];
379
		return $this;
380
	}
381
	/**
382
	 * Adding text to the title page
383
	 *
384
	 * @param string $title
385
	 * @param bool   $replace Replace whole title by this
386
	 *
387
	 * @return Page
388
	 */
389
	function title ($title, $replace = false) {
390
		$title = htmlentities($title, ENT_COMPAT, 'utf-8');
391
		if ($replace) {
392
			$this->Title = [$title];
393
		} else {
394
			$this->Title[] = $title;
395
		}
396
		return $this;
397
	}
398
	/**
399
	 * Display success message
400
	 *
401
	 * @param string $success_text
402
	 *
403
	 * @return Page
404
	 */
405
	function success ($success_text) {
406
		return $this->top_message($success_text, 'success');
407
	}
408
	/**
409
	 * Display notice message
410
	 *
411
	 * @param string $notice_text
412
	 *
413
	 * @return Page
414
	 */
415
	function notice ($notice_text) {
416
		return $this->top_message($notice_text, 'warning');
417
	}
418
	/**
419
	 * Display warning message
420
	 *
421
	 * @param string $warning_text
422
	 *
423
	 * @return Page
424
	 */
425
	function warning ($warning_text) {
426
		return $this->top_message($warning_text, 'error');
427
	}
428
	/**
429
	 * Generic method for 3 methods above
430
	 *
431
	 * @param string $message
432
	 * @param string $class_ending
433
	 *
434
	 * @return Page
435
	 */
436
	protected function top_message ($message, $class_ending) {
437
		$this->Top .= h::div(
438
			$message,
439
			[
440
				'class' => "cs-text-center cs-block-$class_ending cs-text-$class_ending"
441
			]
442
		);
443
		return $this;
444
	}
445
	/**
446
	 * Error pages processing
447
	 *
448
	 * @param null|string|string[] $custom_text Custom error text instead of text like "404 Not Found" or array with two elements: [error, error_description]
449
	 * @param bool                 $json        Force JSON return format
450
	 * @param int                  $error_code  HTTP status code
451
	 *
452
	 * @throws ExitException
453
	 */
454
	function error ($custom_text = null, $json = false, $error_code = 500) {
455
		if ($this->error_showed) {
456
			return;
457
		}
458
		$this->error_showed = true;
459
		/**
460
		 * Hack for 403 after sign out in administration
461
		 */
462
		if ($error_code == 403 && !api_path() && _getcookie('sign_out')) {
463
			_header('Location: /', true, 302);
464
			$this->Content = '';
465
			throw new ExitException;
466
		}
467
		interface_off();
468
		$status_text       = status_code($error_code);
469
		$error_description = $status_text;
470
		if (is_array($custom_text)) {
471
			list($error_code, $error_description) = $custom_text;
472
		} elseif ($custom_text) {
473
			$error_description = $custom_text;
474
		}
475
		if ($json || api_path()) {
476
			if ($json) {
477
				_header('Content-Type: application/json; charset=utf-8', true);
478
				interface_off();
479
			}
480
			$this->json(
481
				[
482
					'error'             => $error_code,
483
					'error_description' => $error_description
484
				]
485
			);
486
		} else {
487
			ob_start();
488
			if (
489
				!_include(THEMES."/$this->theme/error.html", false, false) &&
490
				!_include(THEMES."/$this->theme/error.php", false, false)
491
			) {
492
				echo
493
					"<!doctype html>\n".
494
					h::title(status_code($error_code)).
495
					$error_description;
496
			}
497
			$this->Content = ob_get_clean();
498
		}
499
		$this->__finish();
500
		throw new ExitException;
501
	}
502
	/**
503
	 * Provides next events:
504
	 *  System/Page/display/before
505
	 *
506
	 *  System/Page/display/after
507
	 *
508
	 * Page generation
509
	 */
510
	function __finish () {
511
		/**
512
		 * Protection from double calling
513
		 */
514
		if ($this->finish_called_once) {
515
			return;
516
		}
517
		$this->finish_called_once = true;
518
		/**
519
		 * For AJAX and API requests only content without page template
520
		 */
521
		$api = api_path();
522
		if ($api || !$this->interface) {
523
			/**
524
			 * Processing of replacing in content
525
			 */
526
			echo $this->process_replacing($this->Content ?: ($api ? 'null' : ''));
527
		} else {
528
			Event::instance()->fire('System/Page/display/before');
529
			/**
530
			 * Processing of template, substituting of content, preparing for the output
531
			 */
532
			$this->prepare();
533
			/**
534
			 * Processing of replacing in content
535
			 */
536
			$this->Html = $this->process_replacing($this->Html);
537
			Event::instance()->fire('System/Page/display/after');
538
			echo rtrim($this->Html);
539
		}
540
	}
541
}
542