Completed
Push — master ( 218a8b...6e2144 )
by Nazar
04:00
created

functions.php ➔ pages()   C

Complexity

Conditions 13
Paths 5

Size

Total Lines 81
Code Lines 57

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 13
eloc 57
nc 5
nop 4
dl 0
loc 81
rs 5.0112

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
/**
9
 * Base system functions, do not edit this file, or make it very carefully
10
 * otherwise system workability may be broken
11
 */
12
use
13
	cs\Cache,
14
	cs\Config,
15
	cs\Language,
16
	cs\Page,
17
	cs\Text;
18
19
/**
20
 * Auto Loading of classes
21
 */
22
spl_autoload_register(
23
	function ($class) {
24
		static $cache, $aliases;
25
		if (!isset($cache)) {
26
			$cache   = file_exists(CACHE.'/classes/autoload') ? file_get_json(CACHE.'/classes/autoload') : [];
27
			$aliases = file_exists(CACHE.'/classes/aliases') ? file_get_json(CACHE.'/classes/aliases') : [];
28
		}
29
		if (isset($aliases[$class])) {
30
			spl_autoload_call($aliases[$class]);
31
			return class_exists($aliases[$class]) || class_alias($aliases[$class], $class);
32
		}
33
		if (isset($cache[$class])) {
34
			return $cache[$class] ? require_once $cache[$class] : false;
35
		}
36
		$prepared_class_name = ltrim($class, '\\');
37
		if (strpos($prepared_class_name, 'cs\\') === 0) {
38
			$prepared_class_name = substr($prepared_class_name, 3);
39
		}
40
		$prepared_class_name = explode('\\', $prepared_class_name);
41
		$namespace           = count($prepared_class_name) > 1 ? implode('/', array_slice($prepared_class_name, 0, -1)) : '';
42
		$class_name          = array_pop($prepared_class_name);
43
		$cache[$class]       = false;
44
		/** @noinspection MkdirRaceConditionInspection */
45
		@mkdir(CACHE.'/classes', 0770, true);
46
		/**
47
		 * Try to load classes from different places. If not found in one place - try in another.
48
		 */
49
		if (
50
			_require_once($file = DIR."/core/classes/$namespace/$class_name.php", false) ||    //Core classes
51
			_require_once($file = DIR."/core/thirdparty/$namespace/$class_name.php", false) || //Third party classes
52
			_require_once($file = DIR."/core/traits/$namespace/$class_name.php", false) ||     //Core traits
53
			_require_once($file = ENGINES."/$namespace/$class_name.php", false) ||             //Core engines
54
			_require_once($file = MODULES."/../$namespace/$class_name.php", false) ||          //Classes in modules
55
			_require_once($file = PLUGINS."/../$namespace/$class_name.php", false)             //Classes in plugins
56
		) {
57
			$cache[$class] = realpath($file);
58
			file_put_json(CACHE.'/classes/autoload', $cache);
59
			return (bool)$cache[$class];
60
		}
61
		// Processing components aliases
62
		if (strpos($namespace, 'modules') === 0 || strpos($namespace, 'plugins') === 0) {
63
			$Config      = Config::instance();
64
			$directories = [];
65
			foreach ($Config->components['modules'] ?: [] as $module_name => $module_data) {
66
				if ($module_data['active'] == Config\Module_Properties::UNINSTALLED) {
67
					continue;
68
				}
69
				$directories[] = MODULES."/$module_name";
70
			}
71
			foreach ($Config->components['plugins'] ?: [] as $plugin_name) {
72
				$directories[] = PLUGINS."/$plugin_name";
73
			}
74
			$class_exploded = explode('\\', $class);
75
			foreach ($directories as $directory) {
76
				if (file_exists("$directory/meta.json")) {
77
					$meta = file_get_json("$directory/meta.json") + ['provide' => []];
78
					if ($class_exploded[2] != $meta['package'] && in_array($class_exploded[2], (array)$meta['provide'])) {
79
						$class_exploded[2] = $meta['package'];
80
						$alias             = implode('\\', $class_exploded);
81
						$aliases[$class]   = $alias;
82
						file_put_json(CACHE.'/classes/aliases', $aliases);
83
						spl_autoload_call($alias);
84
						return class_exists($alias) || class_alias($alias, $class);
85
					}
86
				}
87
			}
88
		}
89
		return false;
90
	},
91
	true,
92
	true
93
);
94
95
/**
96
 * Clean cache of classes autoload and customization
97
 */
98
function clean_classes_cache () {
99
	@unlink(CACHE.'/classes/autoload');
100
	@unlink(CACHE.'/classes/aliases');
101
	@unlink(CACHE.'/classes/modified');
102
}
103
104
/**
105
 * Get or set modified classes (used in Singleton trait)
106
 *
107
 * @param array|null $updated_modified_classes
108
 *
109
 * @return array
110
 */
111
function modified_classes ($updated_modified_classes = null) {
112
	static $modified_classes;
113
	if (!defined('CACHE')) {
114
		return [];
115
	}
116
	/** @noinspection MkdirRaceConditionInspection */
117
	@mkdir(CACHE.'/classes', 0770, true);
118
	if (!isset($modified_classes)) {
119
		$modified_classes = file_exists(CACHE.'/classes/modified') ? file_get_json(CACHE.'/classes/modified') : [];
120
	}
121
	if ($updated_modified_classes) {
122
		$modified_classes = $updated_modified_classes;
123
		file_put_json(CACHE.'/classes/modified', $modified_classes);
124
	}
125
	return $modified_classes;
126
}
127
128
/**
129
 * Easy getting of translations
130
 *
131
 * @param string  $item
132
 * @param mixed[] $arguments There can be any necessary number of arguments here
133
 *
134
 * @return string
135
 */
136
function __ ($item, ...$arguments) {
137
	$L = Language::instance();
138
	if (func_num_args() > 1) {
139
		return $L->format($item, ...$arguments);
140
	} else {
141
		return $L->$item;
142
	}
143
}
144
145
/**
146
 * Get file url by it's destination in file system
147
 *
148
 * @param string $source
149
 *
150
 * @return false|string
151
 */
152
function url_by_source ($source) {
153
	$Config = Config::instance(true);
154
	if (!$Config) {
155
		return false;
156
	}
157
	$source = realpath($source);
158
	if (mb_strpos($source, DIR) === 0) {
159
		return $Config->core_url().mb_substr($source, mb_strlen(DIR));
160
	}
161
	return false;
162
}
163
164
/**
165
 * Get file destination in file system by it's url
166
 *
167
 * @param string $url
168
 *
169
 * @return false|string
170
 */
171
function source_by_url ($url) {
172
	$Config = Config::instance(true);
173
	if (!$Config) {
174
		return false;
175
	}
176
	if (mb_strpos($url, $Config->core_url()) === 0) {
177
		return DIR.mb_substr($url, mb_strlen($Config->core_url()));
178
	}
179
	return false;
180
}
181
182
/**
183
 * Public cache cleaning
184
 *
185
 * @return bool
186
 */
187
function clean_pcache () {
188
	$ok   = true;
189
	$list = get_files_list(PUBLIC_CACHE, false, 'fd', true, true, 'name|desc');
190
	foreach ($list as $item) {
191
		if (is_writable($item)) {
192
			is_dir($item) ? @rmdir($item) : @unlink($item);
193
		} else {
194
			$ok = false;
195
		}
196
	}
197
	return $ok;
198
}
199
200
/**
201
 * Formatting of time in seconds to human-readable form
202
 *
203
 * @param int $time Time in seconds
204
 *
205
 * @return string
206
 */
207
function format_time ($time) {
208
	if (!is_numeric($time)) {
209
		return $time;
210
	}
211
	$L   = Language::instance();
212
	$res = [];
213
	if ($time >= 31536000) {
214
		$time_x = round($time / 31536000);
215
		$time -= $time_x * 31536000;
216
		$res[] = $L->time($time_x, 'y');
217
	}
218
	if ($time >= 2592000) {
219
		$time_x = round($time / 2592000);
220
		$time -= $time_x * 2592000;
221
		$res[] = $L->time($time_x, 'M');
222
	}
223
	if ($time >= 86400) {
224
		$time_x = round($time / 86400);
225
		$time -= $time_x * 86400;
226
		$res[] = $L->time($time_x, 'd');
227
	}
228
	if ($time >= 3600) {
229
		$time_x = round($time / 3600);
230
		$time -= $time_x * 3600;
231
		$res[] = $L->time($time_x, 'h');
232
	}
233
	if ($time >= 60) {
234
		$time_x = round($time / 60);
235
		$time -= $time_x * 60;
236
		$res[] = $L->time($time_x, 'm');
237
	}
238
	if ($time > 0 || empty($res)) {
239
		$res[] = $L->time($time, 's');
240
	}
241
	return implode(' ', $res);
242
}
243
244
/**
245
 * Formatting of data size in bytes to human-readable form
246
 *
247
 * @param int      $size
248
 * @param bool|int $round
249
 *
250
 * @return float|string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
251
 */
252
function format_filesize ($size, $round = false) {
253
	if (!is_numeric($size)) {
254
		return $size;
255
	}
256
	$L    = Language::prefix('system_filesize_');
257
	$unit = '';
258
	if ($size >= 1099511627776) {
259
		$size /= 1099511627776;
260
		$unit = " $L->TiB";
261
	} elseif ($size >= 1073741824) {
262
		$size /= 1073741824;
263
		$unit = " $L->GiB";
264
	} elseif ($size >= 1048576) {
265
		$size /= 1048576;
266
		$unit = " $L->MiB";
267
	} elseif ($size >= 1024) {
268
		$size /= 1024;
269
		$unit = " $L->KiB";
270
	} else {
271
		$size = "$size $L->Bytes";
272
	}
273
	return $round ? round($size, $round).$unit : $size.$unit;
274
}
275
276
/**
277
 * Get list of timezones
278
 *
279
 * @return array
280
 */
281
function get_timezones_list () {
282
	$timezones = [];
283
	foreach (timezone_identifiers_list() as $timezone) {
284
		$offset          = (new DateTimeZone($timezone))->getOffset(new DateTime);
285
		$key             = (39600 + $offset).$timezone;
286
		$sign            = ($offset < 0 ? '-' : '+');
287
		$hours           = str_pad(floor(abs($offset / 3600)), 2, 0, STR_PAD_LEFT);
288
		$minutes         = str_pad(abs(($offset % 3600) / 60), 2, 0, STR_PAD_LEFT);
289
		$timezones[$key] = [
290
			'key'   => str_replace('_', ' ', $timezone)." ($sign$hours:$minutes)",
291
			'value' => $timezone
292
		];
293
	}
294
	ksort($timezones, SORT_NATURAL);
295
	return array_column($timezones, 'value', 'key');
296
}
297
298
/**
299
 * Get multilingual value from $Config->core array
300
 *
301
 * @param string $item
302
 *
303
 * @return false|string
304
 */
305
function get_core_ml_text ($item) {
306
	$Config = Config::instance(true);
307
	if (!$Config) {
308
		return false;
309
	}
310
	return Text::instance()->process($Config->module('System')->db('texts'), $Config->core[$item], true);
311
}
312
313
/**
314
 * Set multilingual value from $Config->core array
315
 *
316
 * @param string $item
317
 * @param string $value
318
 *
319
 * @return false|string
320
 */
321
function set_core_ml_text ($item, $value) {
322
	$Config = Config::instance(true);
323
	if (!$Config || !isset($Config->core[$item])) {
324
		return false;
325
	}
326
	return Text::instance()->set($Config->module('System')->db('texts'), 'System/Config/core', $item, $value);
327
}
328
329
/**
330
 * String representation of HTTP status code
331
 *
332
 * @param int $code
333
 *
334
 * @return null|string
335
 */
336
function status_code_string ($code) {
337
	switch ($code) {
338
		case 201:
339
			$string_code = '201 Created';
340
			break;
341
		case 202:
342
			$string_code = '202 Accepted';
343
			break;
344
		case 301:
345
			$string_code = '301 Moved Permanently';
346
			break;
347
		case 302:
348
			$string_code = '302 Found';
349
			break;
350
		case 303:
351
			$string_code = '303 See Other';
352
			break;
353
		case 307:
354
			$string_code = '307 Temporary Redirect';
355
			break;
356
		case 400:
357
			$string_code = '400 Bad Request';
358
			break;
359
		case 403:
360
			$string_code = '403 Forbidden';
361
			break;
362
		case 404:
363
			$string_code = '404 Not Found';
364
			break;
365
		case 405:
366
			$string_code = '405 Method Not Allowed';
367
			break;
368
		case 409:
369
			$string_code = '409 Conflict';
370
			break;
371
		case 429:
372
			$string_code = '429 Too Many Requests';
373
			break;
374
		case 500:
375
			$string_code = '500 Internal Server Error';
376
			break;
377
		case 501:
378
			$string_code = '501 Not Implemented';
379
			break;
380
		case 503:
381
			$string_code = '503 Service Unavailable';
382
			break;
383
		default:
384
			return null;
385
	}
386
	return $string_code;
387
}
388
389
/**
390
 * Pages navigation based on links
391
 *
392
 * @param int             $page       Current page
393
 * @param int             $total      Total pages number
394
 * @param callable|string $url        if string - it will be formatted with sprintf with one parameter - page number<br>
395
 *                                    if callable - one parameter will be given, callable should return url string
396
 * @param bool            $head_links If <b>true</b> - links with rel="prev" and rel="next" will be added
397
 *
398
 * @return bool|string <b>false</b> if single page, otherwise string, set of navigation links
399
 */
400
function pages ($page, $total, $url, $head_links = false) {
401
	if ($total == 1) {
402
		return false;
403
	}
404
	$Page             = Page::instance();
405
	$original_url     = $url;
406
	$base_url         = Config::instance()->base_url();
407
	$url              = function ($page) use ($original_url, $base_url) {
408
		$href = is_callable($original_url) ? $original_url($page) : sprintf($original_url, $page);
409
		if (is_string($href) && strpos($href, 'http') !== 0) {
410
			$href = ltrim($href, '/');
411
			$href = "$base_url/$href";
412
		}
413
		return $href;
414
	};
415
	$output           = [];
416
	$render_page_item = function ($i) use ($Page, $page, $url, $head_links, &$output) {
417
		$href = $url($i);
418
		if ($head_links) {
419
			switch ($i) {
420
				case $page - 1:
421
					$Page->link(['href' => $href, 'rel' => 'prev']);
422
					break;
423
				case $page + 1:
424
					$Page->link(['href' => $href, 'rel' => 'next']);
425
					break;
426
				case $page:
427
					$Page->canonical_url($href);
428
					break;
429
			}
430
		}
431
		$output[] = [
432
			$i,
433
			[
434
				'href'    => $i == $page ? false : $href,
435
				'is'      => 'cs-link-button',
436
				'primary' => $i == $page
437
			]
438
		];
439
	};
440
	if ($total <= 11) {
441
		array_map($render_page_item, range(1, $total));
442
	} else {
443
		if ($page <= 6) {
444
			array_map($render_page_item, range(1, 7));
445
			$output[] = [
446
				'...',
447
				[
448
					'disabled' => true
449
				]
450
			];
451
			array_map($render_page_item, range($total - 2, $total));
452
		} elseif ($page >= $total - 5) {
453
			array_map($render_page_item, range(1, 3));
454
			$output[] = [
455
				'...',
456
				[
457
					'disabled' => true
458
				]
459
			];
460
			array_map($render_page_item, range($total - 6, $total));
461
		} else {
462
			array_map($render_page_item, range(1, 2));
463
			$output[] = [
464
				'...',
465
				[
466
					'disabled' => true
467
				]
468
			];
469
			array_map($render_page_item, range($page - 2, $page + 2));
470
			$output[] = [
471
				'...',
472
				[
473
					'disabled' => true
474
				]
475
			];
476
			array_map($render_page_item, range($total - 1, $total));
477
		}
478
	}
479
	return h::{'a[is=cs-link-button]'}($output);
480
}
481
482
/**
483
 * Pages navigation based on buttons (for search forms, etc.)
484
 *
485
 * @param int                  $page  Current page
486
 * @param int                  $total Total pages number
487
 * @param bool|callable|string $url   Adds <i>formaction</i> parameter to every button<br>
488
 *                                    if <b>false</b> - only form parameter <i>page</i> will we added<br>
489
 *                                    if string - it will be formatted with sprintf with one parameter - page number<br>
490
 *                                    if callable - one parameter will be given, callable should return url string
491
 *
492
 * @return false|string                        <b>false</b> if single page, otherwise string, set of navigation buttons
493
 */
494
function pages_buttons ($page, $total, $url = false) {
495
	if ($total == 1) {
496
		return false;
497
	}
498
	if (!is_callable($url)) {
499
		$original_url = $url;
500
		$url          = function ($page) use ($original_url) {
501
			return sprintf($original_url, $page);
502
		};
503
	}
504
	$output           = [];
505
	$render_page_item = function ($i) use ($page, $url, &$output) {
506
		$output[] = [
507
			$i,
508
			[
509
				'formaction' => $i == $page || $url === false ? false : $url($i),
510
				'value'      => $i == $page ? false : $i,
511
				'type'       => $i == $page ? 'button' : 'submit',
512
				'primary'    => $i == $page
513
			]
514
		];
515
	};
516
	if ($total <= 11) {
517
		array_map($render_page_item, range(1, $total));
518
	} else {
519
		if ($page <= 6) {
520
			array_map($render_page_item, range(1, 7));
521
			$output[] = [
522
				'...',
523
				[
524
					'type' => 'button',
525
					'disabled'
526
				]
527
			];
528
			array_map($render_page_item, range($total - 2, $total));
529
		} elseif ($page >= $total - 5) {
530
			array_map($render_page_item, range(1, 3));
531
			$output[] = [
532
				'...',
533
				[
534
					'type' => 'button',
535
					'disabled'
536
				]
537
			];
538
			array_map($render_page_item, range($total - 6, $total));
539
		} else {
540
			array_map($render_page_item, range(1, 2));
541
			$output[] = [
542
				'...',
543
				[
544
					'type' => 'button',
545
					'disabled'
546
				]
547
			];
548
			array_map($render_page_item, range($page - 2, $page + 2));
549
			$output[] = [
550
				'...',
551
				[
552
					'type' => 'button',
553
					'disabled'
554
				]
555
			];
556
			array_map($render_page_item, range($total - 1, $total));
557
		}
558
	}
559
	return h::{'button[is=cs-button][name=page]'}($output);
560
}
561
562
/**
563
 * Checks whether specified functionality available or not
564
 *
565
 * @param string|string[] $functionality One functionality or array of them
566
 *
567
 * @return bool `true` if all functionality available, `false` otherwise
568
 */
569
function functionality ($functionality) {
570
	if (is_array($functionality)) {
571
		$result = true;
572
		foreach ($functionality as $f) {
573
			$result = $result && functionality($f);
574
		}
575
		return $result;
576
	}
577
	$all = Cache::instance()->get(
578
		'functionality',
579
		function () {
580
			$functionality = [];
581
			$Config        = Config::instance();
582
			$components    = $Config->components;
583
			foreach (array_keys($components['modules']) as $module) {
584
				if (!$Config->module($module)->enabled() || !file_exists(MODULES."/$module/meta.json")) {
585
					continue;
586
				}
587
				$functionality[] = [$module];
588
				$meta            = file_get_json(MODULES."/$module/meta.json");
589
				if (isset($meta['provide'])) {
590
					$functionality[] = (array)$meta['provide'];
591
				}
592
			}
593
			foreach ($components['plugins'] as $plugin) {
594
				if (!file_exists(PLUGINS."/$plugin/meta.json")) {
595
					continue;
596
				}
597
				$functionality[] = [$plugin];
598
				$meta            = file_get_json(PLUGINS."/$plugin/meta.json");
599
				if (isset($meta['provide'])) {
600
					$functionality[] = (array)$meta['provide'];
601
				}
602
			}
603
			return array_merge(...$functionality);
604
		}
605
	);
606
	return in_array($functionality, $all);
607
}
608