Completed
Push — master ( 07f8b3...561c31 )
by Nazar
04:12
created

Index::process_request()   D

Complexity

Conditions 9
Paths 36

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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