Completed
Push — master ( 9322be...5fd4c1 )
by Nazar
05:36
created

App::allow_closed_site_request()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5

Importance

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