Passed
Push — main ( 915a08...2be97f )
by Sammy
01:45
created

KadroController   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 245
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 92
dl 0
loc 245
rs 8.5599
c 1
b 0
f 0
wmc 48

21 Methods

Rating   Name   Duplication   Size   Complexity  
A set_container() 0 3 1
A logger() 0 3 1
A router() 0 3 1
A container() 0 3 1
A __toString() 0 1 1
A box() 0 7 2
A operator() 0 3 1
A requires_operator() 0 3 1
A has_route_back() 0 3 1
A trim_request_data() 0 7 2
B authorize() 0 14 7
A route_factory() 0 15 4
A execute() 0 19 5
A viewport() 0 21 6
A display() 0 31 3
A find_template() 0 35 5
A template_base() 0 3 1
A route_back() 0 6 2
A conclude() 0 1 1
A prepare() 0 3 1
A tracer() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like KadroController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use KadroController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace HexMakina\kadro\Controllers;
4
5
use \Psr\Container\{ContainerInterface,ContainerExceptionInterface,NotFoundExceptionInterface};
0 ignored issues
show
Bug introduced by
The type Psr\Container\ContainerExceptionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type Psr\Container\NotFoundExceptionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type Psr\Container\ContainerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
7
use \HexMakina\kadro\Auth\{OperatorInterface, AccessRefusedException};
8
use \HexMakina\kadro\Router\RouterInterface;
9
use \HexMakina\kadro\Logger\LoggerInterface;
10
11
class KadroController implements Interfaces\DisplayController
12
{
13
  protected $template_variables = [];
14
  protected $container = null;
15
16
  protected $route_back = null;
17
18
  public function __toString(){ return get_called_class();}
19
20
  // -------- Controller Container
21
  public function set_container(ContainerInterface $container)
22
  {
23
    $this->container = $container;
24
  }
25
26
  public function container() : ContainerInterface
27
  {
28
    return $this->container;
29
  }
30
31
  // shortcut for (un)boxing
32
  public function box($key, $instance=null)
33
  {
34
    if(!is_null($instance))
35
      $this->container->register($key, $instance);
36
37
    // dd($this->container->get($key));
38
    return $this->container->get($key);
39
  }
40
41
  public function logger() : LoggerInterface
42
  {
43
    return $this->box('LoggerInterface');
44
  }
45
46
// -------- Controller Router
47
48
  public function router() : RouterInterface
49
  {
50
    return $this->box('RouterInterface');
51
  }
52
53
  public function operator() : OperatorInterface
54
  {
55
    return $this->box('OperatorInterface');
56
  }
57
58
  public function tracer() : TracerInterface
0 ignored issues
show
Bug introduced by
The type HexMakina\kadro\Controllers\TracerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
59
  {
60
    return $this->box('TracerInterface');
61
  }
62
63
  public function requires_operator()
64
  {
65
    return true; // security by default
66
  }
67
68
  public function authorize($permission=null)
69
  {
70
    // if(!$this->requires_operator() || is_null($permission))
71
    if(!$this->requires_operator())
72
      return true;
73
74
    $operator = $this->operator();
75
    if(is_null($operator) || $operator->is_new() || !$operator->is_active())
0 ignored issues
show
Bug introduced by
The method is_new() does not exist on HexMakina\kadro\Auth\OperatorInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
    if(is_null($operator) || $operator->/** @scrutinizer ignore-call */ is_new() || !$operator->is_active())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
76
      throw new AccessRefusedException();
77
78
    if(!is_null($permission) && !$operator->has_permission($permission))
0 ignored issues
show
Bug introduced by
The method has_permission() does not exist on HexMakina\kadro\Auth\OperatorInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to HexMakina\kadro\Auth\OperatorInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
    if(!is_null($permission) && !$operator->/** @scrutinizer ignore-call */ has_permission($permission))
Loading history...
79
      throw new AccessRefusedException();
80
81
    return true;
82
  }
83
84
  public function viewport($key=null, $value=null, $coercion=false)
85
  {
86
    // no key, returns all
87
    if(is_null($key))
88
      return $this->template_variables;
89
90
    // got key, got null value, returns $[$key]
91
    if(is_null($value))
92
    {
93
      if($coercion === true) // break rule 1 ?
94
        $this->template_variables[$key] = null;
95
96
      return $this->template_variables[$key] ?? null;
97
    }
98
99
    // got key, got value
100
    // sets or coerces $[$key]=$value and returns $[$key]
101
    if(!isset($this->template_variables[$key]) || $coercion === true)
102
      $this->template_variables[$key] = $value;
103
104
    return $this->template_variables[$key] ?? null;
105
  }
106
107
  public function execute()
108
  {
109
    $this->authorize();
110
111
    $custom_template = null;
112
113
    if(method_exists($this, 'prepare'))
114
    	$this->prepare();
115
116
  	if(method_exists($this, $method = $this->router()->target_method()))
0 ignored issues
show
Bug introduced by
The method target_method() does not exist on HexMakina\kadro\Router\RouterInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to HexMakina\kadro\Router\RouterInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
  	if(method_exists($this, $method = $this->router()->/** @scrutinizer ignore-call */ target_method()))
Loading history...
117
    {
118
      $custom_template = $this->$method();
119
    }
120
121
    if(method_exists($this, 'conclude'))
122
    	$this->conclude();
123
124
    if(method_exists($this, 'display'))
125
    	$template = $this->display($custom_template);
0 ignored issues
show
Unused Code introduced by
The assignment to $template is dead and can be removed.
Loading history...
126
  }
127
128
  public function conclude(){}
129
130
  public function prepare()
131
  {
132
    $this->trim_request_data();
133
  }
134
135
  private function trim_request_data()
136
  {
137
    array_walk_recursive($_GET, function(&$value){$value = trim($value);});
138
    array_walk_recursive($_REQUEST, function(&$value){$value = trim($value);});
139
140
    if($this->router()->submits())
141
      array_walk_recursive($_POST, function(&$value){$value = trim($value);});
142
  }
143
144
  public function display($custom_template = null, $standalone=false)
145
  {
146
    $smarty = $this->box('template_engine');
147
148
    $template = $this->find_template($smarty, $custom_template); // throws Exception if nothing found
149
150
		$this->viewport('controller', $this);
151
152
    $this->viewport('user_messages', $this->logger()->get_user_report());
153
154
155
  	$this->viewport('file_root', $this->router()->file_root());
156
  	$this->viewport('view_path', $this->router()->file_root() . $this->box('settings.smarty.template_path').'app/');
157
  	$this->viewport('web_root', $this->router()->web_root());
158
  	$this->viewport('view_url', $this->router()->web_root() . $this->box('settings.smarty.template_path'));
159
  	$this->viewport('images_url', $this->router()->web_root() . $this->box('settings.smarty.template_path') . 'images/');
160
161
    foreach($this->viewport() as $template_var_name => $value)
162
      $smarty->assign($template_var_name, $value);
163
164
    if($standalone === false)
165
    {
166
      $smarty->display(sprintf('%s|%s', $this->box('settings.smarty.template_inclusion_path'), $template));
167
    }
168
    else
169
    {
170
      $smarty->display($template);
171
    }
172
173
174
    return true;
175
  }
176
177
  private function template_base()
178
  {
179
    return strtolower(str_replace('Controller', '', (new \ReflectionClass(get_called_class()))->getShortName()));
180
  }
181
182
  protected function find_template($smarty, $custom_template = null)
183
  {
184
    $controller_template_path = $this->template_base();
185
    $templates = [];
186
187
    if(!empty($custom_template))
188
    {
189
      // 1. check for custom template in the current controller directory
190
      $templates ['custom_3']= sprintf('%s/%s.html', $controller_template_path, $custom_template);
191
      // 2. check for custom template formatted as controller/view
192
      $templates ['custom_2']= $custom_template.'.html';
193
      $templates ['custom_1']= '_layouts/'.$custom_template.'.html';
194
    }
195
196
    if(!empty($this->router()->target_method()))
197
    {
198
      // 1. check for template in controller-related directory
199
      $templates ['target_1']= sprintf('%s/%s.html', $controller_template_path, $this->router()->target_method());
200
      // 2. check for template in app-related directory
201
      $templates ['target_2']= sprintf('_layouts/%s.html', $this->router()->target_method());
202
      // 3. check for template in kadro directory
203
      $templates ['target_3']= sprintf('%s.html', $this->router()->target_method());
204
    }
205
206
    $templates ['default_3']= sprintf('%s/edit.html', $controller_template_path);
207
    $templates ['default_4']= 'edit.tpl';
208
    $templates = array_unique($templates);
209
210
    while(!is_null($tpl_path = array_shift($templates)))
211
    {
212
      if($smarty->templateExists($tpl_path))
213
        return $tpl_path;
214
    }
215
216
    throw new \Exception('KADRO_ERR_NO_TEMPLATE_TO_DISPLAY');
217
  }
218
219
220
  public function has_route_back() : bool
221
  {
222
    return is_null($this->route_back);
223
  }
224
225
  /*
226
   * returns string, a URL formatted by RouterInterface::pre_hop()
227
   *
228
   * USAGE
229
   * route_back($route_name=null) returns previously set $route_back or RouterInterface::ROUTE_HOME_NAME
230
   * route_back($route_name [,$route_params]), sets $route_back using route_factory()
231
   *
232
   */
233
  public function route_back($route_name=null, $route_params=[]) : string
234
	{
235
    if(is_null($route_name))
236
		  return $this->route_back ?? $this->router()->prehop(RouterInterface::ROUTE_HOME_NAME);
237
238
    return $this->route_back = $this->route_factory($route_name, $route_params);
239
	}
240
241
  public function route_factory($route_name=null, $route_params=[]) : string
242
  {
243
    $route = null;
244
245
    if(is_string($route_name) && !empty($route_name))
246
    {
247
      if($this->router()->route_exists($route_name))
248
        $route = $this->router()->prehop($route_name, $route_params);
249
      else
250
        $route = $route_name;
251
252
      return $route;
253
    }
254
255
    throw new \Exception('ROUTE_FACTORY_PARAM_TYPE_ERROR');
256
  }
257
}
258
259
260