Completed
Push — master ( 0e1017...87dcd8 )
by Nazar
04:21
created

Controller   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 52.46%

Importance

Changes 0
Metric Value
dl 0
loc 139
rs 10
c 0
b 0
f 0
ccs 32
cts 61
cp 0.5246
wmc 29
lcom 1
cbo 3

6 Methods

Rating   Name   Duplication   Size   Complexity  
A controller_router_handler() 0 4 1
B controller_router_handler_internal() 0 17 6
C controller_router_available_methods() 0 24 8
A controller_router_available_methods_to_flat_structure() 0 13 3
A controller_router_handler_internal_execute() 0 10 4
C controller_router() 0 23 7
1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2015-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\App\Router;
9
use
10
	cs\Page,
11
	cs\Response;
12
13
/**
14
 * @property string[] $controller_path Path that will be used by controller to render page
15
 */
16
trait Controller {
17
	/**
18
	 * Call methods necessary for module page rendering
19
	 *
20
	 * @param \cs\Request $Request
21
	 *
22
	 * @throws \cs\ExitException
23
	 */
24 6
	protected function controller_router ($Request) {
25 6
		$suffix = '';
26 6
		if ($Request->cli_path) {
27
			$suffix = '\\cli';
28 6
		} elseif ($Request->admin_path) {
29
			$suffix = '\\admin';
30 6
		} elseif ($Request->api_path) {
31 4
			$suffix = '\\api';
32
		}
33 6
		$controller_class = class_exists("cs\\custom\\modules\\$Request->current_module$suffix\\Controller")
34
			? "cs\\custom\\modules\\$Request->current_module$suffix\\Controller"
35 6
			: "cs\\modules\\$Request->current_module$suffix\\Controller";
36 6
		foreach ($this->controller_path as $index => $path) {
37
			/**
38
			 * Starting from index 2 we need to maintain underscore-separated string that includes all paths from index 1 and till current
39
			 */
40 6
			if ($index > 1) {
41
				$path = implode('_', array_slice($this->controller_path, 1, $index));
42
			}
43 6
			$next_exists = isset($this->controller_path[$index + 1]);
44 6
			$this->controller_router_handler($Request, $controller_class, $path, !$next_exists);
45
		}
46 6
	}
47
	/**
48
	 * Call methods that corresponds for specific paths in URL
49
	 *
50
	 * @param \cs\Request $Request
51
	 * @param string      $controller_class
52
	 * @param string      $method_name
53
	 * @param bool        $required
54
	 *
55
	 * @throws \cs\ExitException
56
	 */
57 6
	protected function controller_router_handler ($Request, $controller_class, $method_name, $required = true) {
58 6
		$method_name = str_replace('.', '_', $method_name);
59 6
		$this->controller_router_handler_internal($Request, $controller_class, $method_name, $required);
60 6
	}
61
	/**
62
	 * @param \cs\Request $Request
63
	 * @param string      $controller_class
64
	 * @param string      $method_name
65
	 * @param bool        $required
66
	 *
67
	 * @throws \cs\ExitException
68
	 */
69 6
	protected function controller_router_handler_internal ($Request, $controller_class, $method_name, $required) {
70 6
		$Response = Response::instance();
71 6
		$found    = $this->controller_router_handler_internal_execute($controller_class, $method_name, $Request, $Response);
72 6
		if (!$Request->cli_path && !$Request->api_path) {
73 2
			return;
74
		}
75 4
		$request_method = strtolower($Request->method);
76 4
		$found          = $this->controller_router_handler_internal_execute($controller_class, $method_name.'_'.$request_method, $Request, $Response) || $found;
77 4
		if ($found || !$required) {
78 4
			return;
79
		}
80
		$this->handler_not_found(
81
			$this->controller_router_available_methods($this->working_directory, $controller_class, $method_name),
82
			$request_method,
83
			$Request
84
		);
85
	}
86
	/**
87
	 * @param string $working_directory
88
	 * @param string $controller_class
89
	 * @param string $method_name
90
	 *
91
	 * @return string[]
92
	 */
93
	protected function controller_router_available_methods ($working_directory, $controller_class, $method_name) {
94
		$structure = file_exists("$working_directory/index.json") ? file_get_json("$working_directory/index.json") : ['index'];
95
		$structure = $this->controller_router_available_methods_to_flat_structure($structure);
96
		$methods   = array_filter(
97
			get_class_methods($controller_class) ?: [],
98
			function ($found_method) use ($method_name, $structure) {
99
				if (!preg_match("/^{$method_name}_[a-z_]+$/", $found_method)) {
100
					return false;
101
				}
102
				foreach ($structure as $structure_method) {
103
					if (strpos($found_method, $structure_method) === 0 && strpos($method_name, $structure_method) !== 0) {
104
						return false;
105
					}
106
				}
107
				return true;
108
			}
109
		);
110
		if (method_exists($controller_class, $method_name)) {
111
			$methods[] = $method_name;
112
		}
113
		$methods = _strtoupper(_substr($methods, strlen($method_name) + 1));
114
		natcasesort($methods);
115
		return array_values($methods);
116
	}
117
	/**
118
	 * @param array  $structure
119
	 * @param string $prefix
120
	 *
121
	 * @return string[]
122
	 */
123
	protected function controller_router_available_methods_to_flat_structure ($structure, $prefix = '') {
124
		// First key in order to avoid warning when `$flat_structure` is empty at `return`
125
		$flat_structure = [[]];
126
		foreach ($structure as $path => $nested_structure) {
127
			if (!is_array($nested_structure)) {
128
				$path             = $nested_structure;
129
				$nested_structure = [];
130
			}
131
			$flat_structure[] = [$prefix.$path];
132
			$flat_structure[] = $this->controller_router_available_methods_to_flat_structure($nested_structure, $prefix.$path.'_');
133
		}
134
		return array_merge(...$flat_structure);
135
	}
136
	/**
137
	 * @param string      $controller_class
138
	 * @param string      $method_name
139
	 * @param \cs\Request $Request
140
	 * @param Response    $Response
141
	 *
142
	 * @return bool
143
	 */
144 6
	protected function controller_router_handler_internal_execute ($controller_class, $method_name, $Request, $Response) {
145 6
		if (!method_exists($controller_class, $method_name)) {
146 6
			return false;
147
		}
148 4
		$result = $controller_class::$method_name($Request, $Response);
149 4
		if ($result !== null) {
150
			Page::instance()->{$Request->api_path ? 'json' : 'content'}($result);
151
		}
152 4
		return true;
153
	}
154
}
155