Completed
Push — master ( 667a6a...bef2a6 )
by Nazar
04:24
created

Index::form_button()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
300
	 */
301
	protected function ml_process ($text) {
302
		return Text::instance()->process(Config::instance()->module('System')->db('texts'), $text, true);
303
	}
304
	/**
305
	 * Getter for `controller_path` property (no other properties supported currently)
306
	 *
307
	 * @param string $property
308
	 *
309
	 * @return false|string[]
310
	 */
311
	function __get ($property) {
312
		switch ($property) {
313
			case 'controller_path';
314
				return $this->controller_path;
315
		}
316
		return false;
317
	}
318
	/**
319
	 * Executes plugins processing, blocks and module page generation
320
	 *
321
	 * @throws ExitException
322
	 */
323
	function __finish () {
324
		/**
325
		 * Protection from double calling
326
		 */
327
		if ($this->called_once) {
328
			return;
329
		}
330
		$this->called_once = true;
331
		$Config            = Config::instance();
332
		$Page              = Page::instance();
333
		/**
334
		 * If site is closed
335
		 */
336
		if (!$Config->core['site_mode']) {
337
			if ($this->closed_site($Config)) {
338
				status_code(503);
339
				return;
340
			}
341
			/**
342
			 * Warning about closed site
343
			 */
344
			$Page->warning(get_core_ml_text('closed_title'));
345
		}
346
		Event::instance()->fire('System/Index/load/before');
347
		$this->render_page();
348
		Event::instance()->fire('System/Index/load/after');
349
	}
350
}
351