Completed
Push — master ( 62549b...430ab9 )
by Nazar
04:10
created

Controller::controller_router_available_methods()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
rs 6.7272
cc 7
eloc 17
nc 4
nop 3
1
<?php
2
/**
3
 * @package   CleverStyle CMS
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
	protected function controller_router ($Request) {
25
		$suffix = '';
26
		if ($Request->cli_path) {
27
			$suffix = '\\cli';
28
		} elseif ($Request->admin_path) {
29
			$suffix = '\\admin';
30
		} elseif ($Request->api_path) {
31
			$suffix = '\\api';
32
		}
33
		$controller_class = "cs\\modules\\$Request->current_module$suffix\\Controller";
34
		foreach ($this->controller_path as $index => $path) {
35
			/**
36
			 * Starting from index 2 we need to maintain underscore-separated string that includes all paths from index 1 and till current
37
			 */
38
			if ($index > 1) {
39
				$path = implode('_', array_slice($this->controller_path, 1, $index));
40
			}
41
			$next_exists = isset($this->controller_path[$index + 1]);
42
			$this->controller_router_handler($Request, $controller_class, $path, !$next_exists);
43
		}
44
	}
45
	/**
46
	 * Call methods that corresponds for specific paths in URL
47
	 *
48
	 * @param \cs\Request $Request
49
	 * @param string      $controller_class
50
	 * @param string      $method_name
51
	 * @param bool        $required
52
	 *
53
	 * @throws \cs\ExitException
54
	 */
55
	protected function controller_router_handler ($Request, $controller_class, $method_name, $required = true) {
56
		$method_name = str_replace('.', '_', $method_name);
57
		$this->controller_router_handler_internal($Request, $controller_class, $method_name, $required);
58
	}
59
	/**
60
	 * @param \cs\Request $Request
61
	 * @param string      $controller_class
62
	 * @param string      $method_name
63
	 * @param bool        $required
64
	 *
65
	 * @throws \cs\ExitException
66
	 */
67
	protected function controller_router_handler_internal ($Request, $controller_class, $method_name, $required) {
68
		$Response = Response::instance();
69
		$found    = $this->controller_router_handler_internal_execute($controller_class, $method_name, $Request, $Response);
70
		if (!$Request->cli_path && !$Request->api_path) {
71
			return;
72
		}
73
		$request_method = strtolower($Request->method);
74
		$found          = $this->controller_router_handler_internal_execute($controller_class, $method_name.'_'.$request_method, $Request, $Response) || $found;
75
		if ($found || !$required) {
76
			return;
77
		}
78
		$this->handler_not_found(
1 ignored issue
show
Bug introduced by
It seems like handler_not_found() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
79
			$this->controller_router_available_methods($this->working_directory, $controller_class, $method_name),
80
			$request_method,
81
			$Request
82
		);
83
	}
84
	/**
85
	 * @param string $working_directory
86
	 * @param string $controller_class
87
	 * @param string $method_name
88
	 *
89
	 * @return string[]
90
	 */
91
	protected function controller_router_available_methods ($working_directory, $controller_class, $method_name) {
92
		$structure = file_exists("$working_directory/index.json") ? file_get_json("$working_directory/index.json") : ['index'];
93
		$structure = $this->controller_router_available_methods_to_flat_structure($structure);
94
		$methods   = array_filter(
95
			get_class_methods($controller_class),
96
			function ($found_method) use ($method_name, $structure) {
97
				if (!preg_match("/^{$method_name}_[a-z_]+$/", $found_method)) {
98
					return false;
99
				}
100
				foreach ($structure as $structure_method) {
101
					if (strpos($found_method, $structure_method) === 0 && strpos($method_name, $structure_method) !== 0) {
102
						return false;
103
					}
104
				}
105
				return true;
106
			}
107
		);
108
		if (method_exists($controller_class, $method_name)) {
109
			$methods[] = $method_name;
110
		}
111
		$methods = _strtoupper(_substr($methods, strlen($method_name) + 1));
112
		natcasesort($methods);
113
		return array_values($methods);
114
	}
115
	/**
116
	 * @param array  $structure
117
	 * @param string $prefix
118
	 *
119
	 * @return string[]
120
	 */
121
	protected function controller_router_available_methods_to_flat_structure ($structure, $prefix = '') {
122
		$flat_structure = [];
123
		foreach ($structure as $path => $nested_structure) {
124
			if (!is_array($nested_structure)) {
125
				$path             = $nested_structure;
126
				$nested_structure = [];
127
			}
128
			$flat_structure[] = $prefix.$path;
129
			/** @noinspection SlowArrayOperationsInLoopInspection */
130
			$flat_structure = array_merge(
131
				$flat_structure,
132
				$this->controller_router_available_methods_to_flat_structure($nested_structure, $prefix.$path.'_')
133
			);
134
		}
135
		return $flat_structure;
136
	}
137
	/**
138
	 * @param string      $controller_class
139
	 * @param string      $method_name
140
	 * @param \cs\Request $Request
141
	 * @param Response    $Response
142
	 *
143
	 * @return bool
144
	 */
145
	protected function controller_router_handler_internal_execute ($controller_class, $method_name, $Request, $Response) {
146
		if (!method_exists($controller_class, $method_name)) {
147
			return false;
148
		}
149
		$result = $controller_class::$method_name($Request, $Response);
150
		if ($result !== null) {
151
			Page::instance()->{$Request->api_path ? 'json' : 'content'}($result);
152
		}
153
		return true;
154
	}
155
}
156