Passed
Push — master ( 9cc803...84b166 )
by Jean-Christophe
05:35
created

ScaffoldController   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Test Coverage

Coverage 90.61%

Importance

Changes 0
Metric Value
wmc 53
eloc 206
dl 0
loc 300
ccs 193
cts 213
cp 0.9061
rs 6.96
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
B _createController() 0 34 6
A getMethods() 0 7 2
A _createMethod() 0 4 1
A createCrudView() 0 21 6
A createCRUDDatasClass() 0 4 1
A createEventsClass() 0 4 1
A createAuthFilesClass() 0 4 1
A createModelViewerClass() 0 4 1
A _createClass() 0 17 3
B addCrudController() 0 58 10
B _newAction() 0 54 11
B addAuthController() 0 40 8
A createCRUDFilesClass() 0 4 1
A _createViewOp() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like ScaffoldController 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 ScaffoldController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ubiquity\scaffolding;
4
5
use Ubiquity\controllers\Startup;
6
use Ubiquity\utils\base\UFileSystem;
7
use Ubiquity\utils\base\UString;
8
use Ubiquity\controllers\admin\utils\CodeUtils;
9
use Ubiquity\utils\base\UIntrospection;
10
use Ubiquity\cache\ClassUtils;
11
12
abstract class ScaffoldController {
13
	public static $views = [ "CRUD" => [ "index" => "@framework/crud/index.html","form" => "@framework/crud/form.html","display" => "@framework/crud/display.html" ],
14
			"auth" => [ "index" => "@framework/auth/index.html","info" => "@framework/auth/info.html","noAccess" => "@framework/auth/noAccess.html","disconnected" => "@framework/auth/disconnected.html","message" => "@framework/auth/message.html","baseTemplate" => "@framework/auth/baseTemplate.html" ] ];
15
16
	protected abstract function getTemplateDir();
17
18
	protected abstract function storeControllerNameInSession($controller);
19
20
	public abstract function showSimpleMessage($content, $type, $title = null, $icon = "info", $timeout = NULL, $staticName = null);
21
22
	protected abstract function _addMessageForRouteCreation($path, $jsCallback = "");
23
24 2
	public function _createMethod($access, $name, $parameters = "", $return = "", $content = "", $comment = "") {
25 2
		$templateDir = $this->getTemplateDir ();
26 2
		$keyAndValues = [ "%access%" => $access,"%name%" => $name,"%parameters%" => $parameters,"%content%" => $content,"%comment%" => $comment,"%return%" => $return ];
27 2
		return UFileSystem::openReplaceInTemplateFile ( $templateDir . "method.tpl", $keyAndValues );
28
	}
29
30 5
	public function _createController($controllerName, $variables = [], $ctrlTemplate = 'controller.tpl', $hasView = false, $jsCallback = "") {
31 5
		$message = "";
32 5
		$templateDir = $this->getTemplateDir ();
33 5
		$controllersNS = \rtrim ( Startup::getNS ( "controllers" ), "\\" );
34 5
		$controllersDir = \ROOT . \DS . str_replace ( "\\", \DS, $controllersNS );
35 5
		$controllerName = \ucfirst ( $controllerName );
36 5
		$filename = $controllersDir . \DS . $controllerName . ".php";
37 5
		if (\file_exists ( $filename ) === false) {
38 5
			$namespace = "";
39 5
			if ($controllersNS !== "") {
40 5
				$namespace = "namespace " . $controllersNS . ";";
41
			}
42 5
			$msgView = "";
43 5
			$indexContent = "";
44 5
			if ($hasView) {
45 1
				$viewDir = \ROOT . \DS . "views" . \DS . $controllerName . \DS;
46 1
				UFileSystem::safeMkdir ( $viewDir );
47 1
				$viewName = $viewDir . \DS . "index.html";
48 1
				UFileSystem::openReplaceWriteFromTemplateFile ( $templateDir . "view.tpl", $viewName, [ "%controllerName%" => $controllerName,"%actionName%" => "index" ] );
49 1
				$msgView = "<br>The default view associated has been created in <b>" . UFileSystem::cleanPathname ( \ROOT . \DS . $viewDir ) . "</b>";
50 1
				$indexContent = "\$this->loadView(\"" . $controllerName . "/index.html\");";
51
			}
52 5
			$variables = \array_merge ( $variables, [ "%controllerName%" => $controllerName,"%indexContent%" => $indexContent,"%namespace%" => $namespace ] );
53 5
			UFileSystem::openReplaceWriteFromTemplateFile ( $templateDir . $ctrlTemplate, $filename, $variables );
54 5
			$msgContent = "The <b>" . $controllerName . "</b> controller has been created in <b>" . UFileSystem::cleanFilePathname ( $filename ) . "</b>." . $msgView;
55 5
			if (isset ( $variables ["%path%"] ) && $variables ["%path%"] !== "") {
56
				$msgContent .= $this->_addMessageForRouteCreation ( $variables ["%path%"], $jsCallback );
57
			}
58 5
			$this->storeControllerNameInSession ( $controllersNS . "\\" . $controllerName );
59 5
			$message = $this->showSimpleMessage ( $msgContent, "success", null, "checkmark circle", NULL, "msgGlobal" );
60
		} else {
61
			$message = $this->showSimpleMessage ( "The file <b>" . $filename . "</b> already exists.<br>Can not create the <b>" . $controllerName . "</b> controller!", "warning", null, "warning circle", 100000, "msgGlobal" );
62
		}
63 5
		return $message;
64
	}
65
66 1
	public function addCrudController($crudControllerName, $resource, $crudDatas = null, $crudViewer = null, $crudEvents = null, $crudViews = null, $routePath = '') {
67 1
		$classContent = "";
68 1
		$uses = [ ];
69 1
		$controllerNS = Startup::getNS ( "controllers" );
70 1
		$messages = [ ];
71 1
		$routeName = $crudControllerName;
72 1
		$this->_createMethod ( "public", "__construct", "", "", "\n\t\tparent::__construct();\n\$this->model=\"{$resource}\";" );
73
74 1
		if (isset ( $crudDatas )) {
75 1
			$uses [] = "use controllers\\crud\\datas\\{$crudControllerName}Datas;";
76 1
			$uses [] = "use Ubiquity\\controllers\\crud\\CRUDDatas;";
77
78 1
			$classContent .= $this->_createMethod ( "protected", "getAdminData", "", ": CRUDDatas", "\t\treturn new {$crudControllerName}Datas(\$this);" );
79 1
			$messages [] = $this->createCRUDDatasClass ( $crudControllerName );
80
		}
81
82 1
		if (isset ( $crudViewer )) {
83 1
			$uses [] = "use controllers\\crud\\viewers\\{$crudControllerName}Viewer;";
84 1
			$uses [] = "use Ubiquity\\controllers\\admin\\viewers\\ModelViewer;";
85
86 1
			$classContent .= $this->_createMethod ( "protected", "getModelViewer", "", ": ModelViewer", "\t\treturn new {$crudControllerName}Viewer(\$this);" );
87 1
			$messages [] = $this->createModelViewerClass ( $crudControllerName );
88
		}
89 1
		if (isset ( $crudEvents )) {
90 1
			$uses [] = "use controllers\\crud\\events\\{$crudControllerName}Events;";
91 1
			$uses [] = "use Ubiquity\\controllers\\crud\\CRUDEvents;";
92
93 1
			$classContent .= $this->_createMethod ( "protected", "getEvents", "", ": CRUDEvents", "\t\treturn new {$crudControllerName}Events(\$this);" );
94 1
			$messages [] = $this->createEventsClass ( $crudControllerName );
95
		}
96
97 1
		if (isset ( $crudViews )) {
98 1
			$crudViews = explode ( ",", $crudViews );
99 1
			$uses [] = "use controllers\\crud\\files\\{$crudControllerName}Files;";
100 1
			$uses [] = "use Ubiquity\\controllers\\crud\\CRUDFiles;";
101 1
			$classContent .= $this->_createMethod ( "protected", "getFiles", "", ": CRUDFiles", "\t\treturn new {$crudControllerName}Files();" );
102 1
			$classFilesContent = [ ];
103 1
			foreach ( $crudViews as $file ) {
104 1
				if (isset ( self::$views ["CRUD"] [$file] )) {
105 1
					$frameworkViewname = self::$views ["CRUD"] [$file];
106 1
					$this->createCrudView ( $frameworkViewname, $crudControllerName, $file );
107 1
					$classFilesContent [] = $this->_createMethod ( "public", "getView" . ucfirst ( $file ), "", "", "\t\treturn \"" . $crudControllerName . "/" . $file . ".html\";" );
108
				}
109
			}
110 1
			$messages [] = $this->createCRUDFilesClass ( $crudControllerName, implode ( "", $classFilesContent ) );
111
		}
112 1
		if ($routePath != null) {
113 1
			if (UString::isNotNull ( $routePath )) {
114 1
				if (! UString::startswith ( $routePath, "/" )) {
115 1
					$routePath = "/" . $routePath;
116
				}
117 1
				$routeName = $routePath;
118 1
				$routePath = "\n * @route(\"{$routePath}\",\"inherited\"=>true,\"automated\"=>true)";
119
			}
120
		}
121 1
		$uses = implode ( "\n", $uses );
122 1
		$messages [] = $this->_createController ( $crudControllerName, [ "%routeName%" => $routeName,"%route%" => $routePath,"%resource%" => $resource,"%uses%" => $uses,"%namespace%" => $controllerNS,"%baseClass%" => "\\Ubiquity\\controllers\\crud\\CRUDController","%content%" => $classContent ], "crudController.tpl" );
123 1
		echo implode ( "\n", $messages );
124 1
	}
125
126 1
	public function addAuthController($authControllerName, $baseClass, $authViews = null, $routePath = "") {
127 1
		$classContent = "";
128 1
		if ($baseClass == "\\Ubiquity\\controllers\\auth\\AuthController") {
129 1
			$controllerTemplate = "authController.tpl";
130 1
			$uses = [ "use Ubiquity\\utils\\http\\USession;","use Ubiquity\\utils\\http\\URequest;" ];
131
		} else {
132
			$controllerTemplate = "authController_.tpl";
133
			$uses = [ ];
134
		}
135 1
		$controllerNS = Startup::getNS ( "controllers" );
136
137 1
		$messages = [ ];
138 1
		$routeName = $authControllerName;
139 1
		if (isset ( $authViews )) {
140 1
			$authViews = explode ( ",", $authViews );
141 1
			$uses [] = "use controllers\\auth\\files\\{$authControllerName}Files;";
142 1
			$uses [] = "use Ubiquity\\controllers\\auth\\AuthFiles;";
143 1
			$classContent .= $this->_createMethod ( "protected", "getFiles", "", ": AuthFiles", "\t\treturn new {$authControllerName}Files();" );
144 1
			$classFilesContent = [ ];
145 1
			foreach ( $authViews as $file ) {
146 1
				if (isset ( self::$views ["auth"] [$file] )) {
147 1
					$frameworkViewname = self::$views ["auth"] [$file];
148 1
					$this->createCrudView ( $frameworkViewname, $authControllerName, $file );
149 1
					$classFilesContent [] = $this->_createMethod ( "public", "getView" . ucfirst ( $file ), "", "", "\t\treturn \"" . $authControllerName . "/" . $file . ".html\";" );
150
				}
151
			}
152 1
			$messages [] = $this->createAuthFilesClass ( $authControllerName, implode ( "", $classFilesContent ) );
153
		}
154 1
		if ($routePath != null) {
155 1
			if (UString::isNotNull ( $routePath )) {
156 1
				if (! UString::startswith ( $routePath, "/" )) {
157 1
					$routePath = "/" . $routePath;
158
				}
159 1
				$routeName = $routePath;
160 1
				$routePath = "\n * @route(\"{$routePath}\",\"inherited\"=>true,\"automated\"=>true)";
161
			}
162
		}
163 1
		$uses = implode ( "\n", $uses );
164 1
		$messages [] = $this->_createController ( $authControllerName, [ "%routeName%" => $routeName,"%route%" => $routePath,"%uses%" => $uses,"%namespace%" => $controllerNS,"%baseClass%" => $baseClass,"%content%" => $classContent ], $controllerTemplate );
165 1
		echo implode ( "\n", $messages );
166 1
	}
167
168 2
	public function _createClass($template, $classname, $namespace, $uses, $extendsOrImplements, $classContent) {
169 2
		$namespaceVar = "";
170 2
		if (UString::isNotNull ( $namespace )) {
171 2
			$namespaceVar = "namespace {$namespace};";
172
		}
173 2
		$variables = [ "%classname%" => $classname,"%namespace%" => $namespaceVar,"%uses%" => $uses,"%extendsOrImplements%" => $extendsOrImplements,"%classContent%" => $classContent ];
174 2
		$templateDir = $this->getTemplateDir ();
175 2
		$directory = UFileSystem::getDirFromNamespace ( $namespace );
176 2
		UFileSystem::safeMkdir ( $directory );
177 2
		$filename = UFileSystem::cleanFilePathname ( $directory . \DS . $classname . ".php" );
178 2
		if (! file_exists ( $filename )) {
179 2
			UFileSystem::openReplaceWriteFromTemplateFile ( $templateDir . $template, $filename, $variables );
180 2
			$message = $this->showSimpleMessage ( "The <b>" . $classname . "</b> class has been created in <b>" . $filename . "</b>.", "success", "Creation", "checkmark circle" );
181
		} else {
182
			$message = $this->showSimpleMessage ( "The file <b>" . $filename . "</b> already exists.<br>Can not create the <b>" . $classname . "</b> class!", "warning", "Creation", "warning circle" );
183
		}
184 2
		return $message;
185
	}
186
187 1
	public function _newAction($controller, $action, $parameters = null, $content = '', $routeInfo = null, $createView = false) {
188 1
		$templateDir = $this->getTemplateDir ();
189 1
		$msgContent = "";
190 1
		$r = new \ReflectionClass ( $controller );
191 1
		if (! method_exists ( $controller, $action )) {
192 1
			$ctrlFilename = $r->getFileName ();
193 1
			$content = CodeUtils::indent ( $content, 2 );
194 1
			$fileContent = \implode ( "", UIntrospection::getClassCode ( $controller ) );
0 ignored issues
show
Bug introduced by
It seems like Ubiquity\utils\base\UInt...tClassCode($controller) can also be of type false; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

194
			$fileContent = \implode ( "", /** @scrutinizer ignore-type */ UIntrospection::getClassCode ( $controller ) );
Loading history...
195 1
			$fileContent = \trim ( $fileContent );
196 1
			$posLast = \strrpos ( $fileContent, "}" );
197 1
			if ($posLast !== false) {
198 1
				if ($createView) {
199 1
					$viewname = $this->_createViewOp ( ClassUtils::getClassSimpleName ( $controller ), $action );
200 1
					$content .= "\n\t\t\$this->loadView('" . $viewname . "');\n";
201 1
					$msgContent .= "<br>Created view : <b>" . $viewname . "</b>";
202
				}
203 1
				$routeAnnotation = "";
204 1
				if (is_array ( $routeInfo )) {
205 1
					$name = "route";
206 1
					$path = $routeInfo ["path"];
207 1
					$routeProperties = [ '"' . $path . '"' ];
208 1
					$methods = $routeInfo ["methods"];
209 1
					if (UString::isNotNull ( $methods )) {
210
						$routeProperties [] = '"methods"=>' . $this->getMethods ( $methods );
211
					}
212 1
					if (isset ( $routeInfo ["ck-Cache"] )) {
213
						$routeProperties [] = '"cache"=>true';
214
						if (isset ( $routeInfo ["duration"] )) {
215
							$duration = $routeInfo ["duration"];
216
							if (\ctype_digit ( $duration )) {
217
								$routeProperties [] = '"duration"=>' . $duration;
218
							}
219
						}
220
					}
221 1
					$routeProperties = \implode ( ",", $routeProperties );
222 1
					$routeAnnotation = UFileSystem::openReplaceInTemplateFile ( $templateDir . "annotation.tpl", [ "%name%" => $name,"%properties%" => $routeProperties ] );
223
224 1
					$msgContent .= $this->_addMessageForRouteCreation ( $path );
225
				}
226 1
				$parameters = CodeUtils::cleanParameters ( $parameters );
227 1
				$actionContent = UFileSystem::openReplaceInTemplateFile ( $templateDir . "action.tpl", [ "%route%" => "\n" . $routeAnnotation,"%actionName%" => $action,"%parameters%" => $parameters,"%content%" => $content ] );
1 ignored issue
show
Bug introduced by
Are you sure $routeAnnotation of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

227
				$actionContent = UFileSystem::openReplaceInTemplateFile ( $templateDir . "action.tpl", [ "%route%" => "\n" . /** @scrutinizer ignore-type */ $routeAnnotation,"%actionName%" => $action,"%parameters%" => $parameters,"%content%" => $content ] );
Loading history...
228 1
				$fileContent = \substr_replace ( $fileContent, "\n%content%", $posLast - 1, 0 );
229 1
				if (! CodeUtils::isValidCode ( '<?php ' . $content )) {
230
					echo $this->showSimpleMessage ( "Errors parsing action content!", "warning", "Creation", "warning circle", null, "msgControllers" );
231
					return;
232
				} else {
233 1
					if (UFileSystem::replaceWriteFromContent ( $fileContent . "\n", $ctrlFilename, [ '%content%' => $actionContent ] )) {
234 1
						$msgContent = "The action <b>{$action}</b> is created in controller <b>{$controller}</b>" . $msgContent;
235 1
						echo $this->showSimpleMessage ( $msgContent, "info", "Creation", "info circle", null, "msgControllers" );
236
					}
237
				}
238
			}
239
		} else {
240
			echo $this->showSimpleMessage ( "The action {$action} already exists in {$controller}!", "error", "Creation", "warning circle", null, "msgControllers" );
241
		}
242 1
	}
243
244
	protected function getMethods($strMethods) {
245
		$methods = \explode ( ",", $strMethods );
246
		$result = [ ];
247
		foreach ( $methods as $method ) {
248
			$result [] = '"' . $method . '"';
249
		}
250
		return "[" . \implode ( ",", $result ) . "]";
251
	}
252
253 1
	protected function _createViewOp($controller, $action) {
254 1
		$viewName = $controller . "/" . $action . ".html";
255 1
		UFileSystem::safeMkdir ( \ROOT . \DS . "views" . \DS . $controller );
256 1
		$templateDir = $this->getTemplateDir ();
257 1
		UFileSystem::openReplaceWriteFromTemplateFile ( $templateDir . "view.tpl", \ROOT . \DS . "views" . \DS . $viewName, [ "%controllerName%" => $controller,"%actionName%" => $action ] );
258 1
		return $viewName;
259
	}
260
261 1
	protected function createCRUDDatasClass($crudControllerName) {
262 1
		$ns = Startup::getNS ( "controllers" ) . "crud\\datas";
263 1
		$uses = "\nuse Ubiquity\\controllers\\crud\\CRUDDatas;";
264 1
		return $this->_createClass ( "class.tpl", $crudControllerName . "Datas", $ns, $uses, "extends CRUDDatas", "\t//use override/implement Methods" );
265
	}
266
267 1
	protected function createModelViewerClass($crudControllerName) {
268 1
		$ns = Startup::getNS ( "controllers" ) . "crud\\viewers";
269 1
		$uses = "\nuse Ubiquity\\controllers\\admin\\viewers\\ModelViewer;";
270 1
		return $this->_createClass ( "class.tpl", $crudControllerName . "Viewer", $ns, $uses, "extends ModelViewer", "\t//use override/implement Methods" );
271
	}
272
273 1
	protected function createEventsClass($crudControllerName) {
274 1
		$ns = Startup::getNS ( "controllers" ) . "crud\\events";
275 1
		$uses = "\nuse Ubiquity\\controllers\\crud\\CRUDEvents;";
276 1
		return $this->_createClass ( "class.tpl", $crudControllerName . "Events", $ns, $uses, "extends CRUDEvents", "\t//use override/implement Methods" );
277
	}
278
279 1
	protected function createCRUDFilesClass($crudControllerName, $classContent = "") {
280 1
		$ns = Startup::getNS ( "controllers" ) . "crud\\files";
281 1
		$uses = "\nuse Ubiquity\\controllers\\crud\\CRUDFiles;";
282 1
		return $this->_createClass ( "class.tpl", $crudControllerName . "Files", $ns, $uses, "extends CRUDFiles", $classContent );
283
	}
284
285 1
	protected function createAuthFilesClass($authControllerName, $classContent = "") {
286 1
		$ns = Startup::getNS ( "controllers" ) . "auth\\files";
287 1
		$uses = "\nuse Ubiquity\\controllers\\auth\\AuthFiles;";
288 1
		return $this->_createClass ( "class.tpl", $authControllerName . "Files", $ns, $uses, "extends AuthFiles", $classContent );
289
	}
290
291 2
	protected function createCrudView($frameworkName, $controllerName, $newName) {
292 2
		$folder = \ROOT . \DS . "views" . \DS . $controllerName;
293 2
		UFileSystem::safeMkdir ( $folder );
294
		try {
295 2
			$teInstance = Startup::getTempateEngineInstance ();
296 2
			if (isset ( $teInstance )) {
297 2
				$blocks = $teInstance->getBlockNames ( $frameworkName );
298 2
				if (sizeof ( $blocks ) > 0) {
299 2
					$content = [ "{% extends \"" . $frameworkName . "\" %}\n" ];
300 2
					foreach ( $blocks as $blockname ) {
301 2
						$content [] = "{% block " . $blockname . " %}\n\t{{ parent() }}\n{% endblock %}\n";
302
					}
303
				} else {
304 2
					$content = [ $teInstance->getCode ( $frameworkName ) ];
305
				}
306
			}
307 1
		} catch ( \Exception $e ) {
308 1
			$content = [ $teInstance->getCode ( $frameworkName ) ];
309
		}
310 2
		if (isset ( $content )) {
311 2
			return UFileSystem::save ( $folder . \DS . $newName . ".html", implode ( "", $content ) );
312
		}
313
	}
314
}
315
316