Completed
Push — master ( 8875c9...813690 )
by Nazar
04:12
created

App::render_title()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 12
rs 9.4285
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
	cs\App\Router;
11
12
/**
13
 * Provides next events:
14
 *  System/App/block_render
15
 *  [
16
 *      'index'           => $index,        //Block index
17
 *      'blocks_array'    => &$blocks_array //Reference to array in form ['top' => '', 'left' => '', 'right' => '', 'bottom' => '']
18
 *  ]
19
 *
20
 *  System/App/construct
21
 *
22
 *  System/App/render/before
23
 *
24
 *  System/App/execute_router/before
25
 *
26
 *  System/App/execute_router/after
27
 *
28
 *  System/App/render/after
29
 *
30
 * @property string[] $controller_path Path that will be used by controller to render page
31
 *
32
 * @method static $this instance($check = false)
33
 */
34
class App {
35
	use
36
		Singleton,
37
		Router;
38
	const INIT_STATE_METHOD = 'init';
39
	protected function init () {
40
		$this->init_router();
41
	}
42
	/**
43
	 * Executes plugins processing, blocks and module page generation
44
	 *
45
	 * @throws ExitException
46
	 */
47
	function execute () {
48
		$Config  = Config::instance();
49
		$Request = Request::instance();
50
		if (!preg_match('/^[0-9a-z_]+$/i', $Request->method)) {
51
			throw new ExitException(400);
52
		}
53
		$this->handle_closed_site(!$Config->core['site_mode'], $Request);
54
		if (!$this->check_permission($Request, 'index')) {
55
			throw new ExitException(403);
56
		}
57
		Event::instance()->fire('System/App/construct');
58
		/**
59
		 * Plugins processing
60
		 */
61
		foreach ($Config->components['plugins'] as $plugin) {
62
			_include(PLUGINS."/$plugin/index.php", false, false);
63
		}
64
		Event::instance()->fire('System/App/render/before');
65
		$this->render($Request);
66
		Event::instance()->fire('System/App/render/after');
67
		Page::instance()->render();
68
	}
69
	/**
70
	 * @param bool    $closed_site
71
	 * @param Request $Request
72
	 *
73
	 * @throws ExitException
74
	 */
75
	protected function handle_closed_site ($closed_site, $Request) {
76
		if (!$closed_site) {
77
			return;
78
		}
79
		/**
80
		 * If site is closed
81
		 */
82
		if (!$this->allow_closed_site_request($Request)) {
83
			throw new ExitException(
84
				[
85
					get_core_ml_text('closed_title'),
86
					get_core_ml_text('closed_text')
87
				],
88
				503
89
			);
90
		}
91
		/**
92
		 * Warning about closed site for administrator
93
		 */
94
		Page::instance()->warning(get_core_ml_text('closed_title'));
95
	}
96
	/**
97
	 * Check if visitor is allowed to make current request to closed site
98
	 *
99
	 * @param Request $Request
100
	 *
101
	 * @return bool
102
	 */
103
	protected function allow_closed_site_request ($Request) {
104
		return
105
			User::instance()->admin() ||
106
			(
107
				$Request->api_path &&
108
				$Request->current_module == 'System' &&
109
				$Request->route === ['user', 'sign_in']
110
			);
111
	}
112
	/**
113
	 * Check whether user allowed to access to specified label
114
	 *
115
	 * @param Request $Request
116
	 * @param string  $label
117
	 *
118
	 * @return bool
119
	 */
120
	protected function check_permission ($Request, $label) {
121
		if ($Request->cli_path) {
122
			return true;
123
		}
124
		$permission_group = $Request->current_module;
125
		if ($Request->admin_path) {
126
			$permission_group = "admin/$permission_group";
127
		} elseif ($Request->api_path) {
128
			$permission_group = "api/$permission_group";
129
		}
130
		return User::instance()->get_permission($permission_group, $label);
131
	}
132
	/**
133
	 * @param Request $Request
134
	 *
135
	 * @throws ExitException
136
	 */
137
	protected function render ($Request) {
138
		if ($Request->cli_path || $Request->api_path) {
139
			$this->execute_router($Request);
140
		} else {
141
			$Page = Page::instance();
142
			$this->render_title($Request, $Page);
143
			$this->execute_router($Request);
144
			$this->render_blocks($Page);
145
		}
146
	}
147
	/**
148
	 * Render page title
149
	 *
150
	 * @param Request $Request
151
	 * @param Page    $Page
152
	 */
153
	protected function render_title ($Request, $Page) {
154
		/**
155
		 * Add generic Home or Module name title
156
		 */
157
		$L = Language::instance();
158
		if ($Request->admin_path) {
159
			$Page->title($L->system_admin_administration);
160
		}
161
		$Page->title(
162
			$L->{$Request->home_page ? 'system_home' : $Request->current_module}
163
		);
164
	}
165
	/**
166
	 * Blocks rendering
167
	 *
168
	 * @param Page $Page
169
	 */
170
	protected function render_blocks ($Page) {
171
		$blocks = Config::instance()->components['blocks'];
172
		/**
173
		 * It is frequent that there is no blocks - so, no need to to anything here
174
		 */
175
		if (!$blocks) {
176
			return;
177
		}
178
		$blocks_array = [
179
			'top'    => '',
180
			'left'   => '',
181
			'right'  => '',
182
			'bottom' => ''
183
		];
184
		foreach ($blocks as $block) {
185
			/**
186
			 * If there is no need to show block or it was rendered by even handler - skip further processing
187
			 */
188
			if (
189
				!$this->should_block_be_rendered($block) ||
190
				!Event::instance()->fire(
191
					'System/Index/block_render',
192
					[
193
						'index'        => $block['index'],
194
						'blocks_array' => &$blocks_array
195
					]
196
				) ||
197
				!Event::instance()->fire(
198
					'System/App/block_render',
199
					[
200
						'index'        => $block['index'],
201
						'blocks_array' => &$blocks_array
202
					]
203
				)
204
			) {
205
				/**
206
				 * Block was rendered by event handler
207
				 */
208
				continue;
209
			}
210
			$block['title'] = $this->ml_process($block['title']);
211
			switch ($block['type']) {
212
				default:
213
					$block['content'] = ob_wrapper(
214
						function () use ($block) {
215
							include BLOCKS."/block.$block[type].php";
216
						}
217
					);
218
					break;
219
				case 'html':
220
				case 'raw_html':
221
					$block['content'] = $this->ml_process($block['content']);
222
					break;
223
			}
224
			/**
225
			 * Template file will have access to `$block` variable, so it can use that
226
			 */
227
			$content = str_replace(
228
				[
229
					'<!--id-->',
230
					'<!--title-->',
231
					'<!--content-->'
232
				],
233
				[
234
					$block['index'],
235
					$block['title'],
236
					$block['content']
237
				],
238
				ob_wrapper(
239
					function () use ($block) {
240
						$template = file_exists(TEMPLATES."/blocks/block.$block[template]") ? $block['template'] : 'default.html';
241
						include TEMPLATES."/blocks/block.$template";
242
					}
243
				)
244
			);
245
			if ($block['position'] == 'floating') {
246
				$Page->replace(
247
					"<!--block#$block[index]-->",
248
					$content
249
				);
250
			} else {
251
				$blocks_array[$block['position']] .= $content;
252
			}
253
		}
254
		$Page->Top .= $blocks_array['top'];
255
		$Page->Left .= $blocks_array['left'];
256
		$Page->Right .= $blocks_array['right'];
257
		$Page->Bottom .= $blocks_array['bottom'];
258
	}
259
	/**
260
	 * Check whether to render block or not based on its properties (active state, when start to show, when it expires and permissions)
261
	 *
262
	 * @param array $block
263
	 *
264
	 * @return bool
265
	 */
266
	protected function should_block_be_rendered ($block) {
267
		return
268
			$block['active'] &&
269
			$block['start'] <= time() &&
270
			(
271
				!$block['expire'] ||
272
				$block['expire'] >= time()
273
			) &&
274
			User::instance()->get_permission('Block', $block['index']);
275
	}
276
	/**
277
	 * @param string $text
278
	 *
279
	 * @return string
280
	 */
281
	protected function ml_process ($text) {
282
		return Text::instance()->process(Config::instance()->module('System')->db('texts'), $text, true);
283
	}
284
	/**
285
	 * Getter for `controller_path` property (no other properties supported currently)
286
	 *
287
	 * @param string $property
288
	 *
289
	 * @return false|string[]
290
	 */
291
	function __get ($property) {
292
		if ($property == 'controller_path') {
293
			return $this->controller_path;
294
		}
295
		return false;
296
	}
297
}
298