Completed
Push — master ( b7b84b...78616b )
by Nazar
04:19
created

App::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
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\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/render/after
25
 */
26
class App {
27
	use
28
		Singleton,
29
		Router;
30
	const INIT_STATE_METHOD = 'init';
31
	/**
32
	 * @var string
33
	 */
34
	protected $working_directory;
35
	protected function init () {
36
		$this->working_directory = '';
37
		$this->controller_path   = ['index'];
38
	}
39
	/**
40
	 * Executes plugins processing, blocks and module page generation
41
	 *
42
	 * @throws ExitException
43
	 */
44
	function execute () {
45
		$Config  = Config::instance();
46
		$Request = Request::instance();
47
		if (!preg_match('/^[0-9a-z_]+$/i', $Request->method)) {
48
			throw new ExitException(400);
49
		}
50
		$this->handle_closed_site(!$Config->core['site_mode'], $Request);
1 ignored issue
show
Documentation introduced by
$Request is of type object<cs\False_class>|object<cs\Singleton\Base>, but the function expects a object<cs\Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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