Passed
Push — master ( 01b681...b7f456 )
by Jean-Christophe
12:19
created

CRUDController   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 299
Duplicated Lines 0 %

Test Coverage

Coverage 84.07%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 43
eloc 179
c 3
b 1
f 0
dl 0
loc 299
ccs 153
cts 182
cp 0.8407
rs 8.96

15 Methods

Rating   Name   Duplication   Size   Complexity  
A edit() 0 8 2
A refreshAsJson() 0 5 1
A updateMember() 0 25 5
A _setStyle() 0 5 3
A delete() 0 29 5
A newModel() 0 10 2
A display() 0 13 2
B showDetail() 0 32 8
A __construct() 0 5 1
A editMember() 0 10 1
A refreshTable() 0 5 1
A index() 0 8 2
A updateModel() 0 28 4
A refresh_() 0 23 5
A detailClick() 0 2 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Ubiquity\controllers\crud;
4
5
use Ubiquity\orm\DAO;
6
use Ubiquity\controllers\ControllerBase;
7
use Ubiquity\controllers\crud\interfaces\HasModelViewerInterface;
8
use Ubiquity\controllers\semantic\MessagesTrait;
9
use Ubiquity\utils\http\URequest;
10
use Ubiquity\utils\http\UResponse;
11
use Ubiquity\orm\OrmUtils;
12
use Ubiquity\utils\base\UString;
13
use Ajax\semantic\html\collections\HtmlMessage;
14
use Ajax\common\html\HtmlContentOnly;
15
use Ubiquity\controllers\semantic\InsertJqueryTrait;
16
use Ajax\semantic\widgets\datatable\DataTable;
17
18
/**
19
 * Ubiquity\controllers\crud$CRUDController
20
 * This class is part of Ubiquity
21
 *
22
 * @author jc
23
 * @version 1.0.3
24
 *
25
 */
26
abstract class CRUDController extends ControllerBase implements HasModelViewerInterface {
27
	use MessagesTrait,CRUDControllerUtilitiesTrait,InsertJqueryTrait;
28
	protected $model;
29
	protected $activePage=1;
30
	protected $style;
31
	
32 7
	public function __construct() {
33 7
		parent::__construct ();
34 7
		DAO::$transformerOp = 'toView';
35 7
		$this->style = '';
36 7
		$this->_insertJquerySemantic ();
37 7
	}
38
	
39
	/**
40
	 * Return a JSON representation of $instances for the JsonDataTable component
41
	 * @param array $instances
42
	 * @return string
43
	 */
44
	protected function refreshAsJson($instances){
45
		$objects = \array_map ( function ($o) {
46
			return $o->_rest;
47
		}, $instances );
48
			return \json_encode(\array_values ( $objects ));
49
	}
50
	
51 2
	public function _setStyle($elm) {
52 2
		if ($this->style === 'inverted') {
53
			$elm->setInverted ( true );
54
			if ($elm instanceof DataTable) {
55
				$elm->setActiveRowSelector ( 'black' );
56
			}
57
		}
58 2
	}
59
	
60
	/**
61
	 * Default page : list all objects
62
	 * Uses modelViewer.isModal, modelViewer.getModelDataTable
63
	 * Uses CRUDFiles.getViewIndex template (default : @framework/crud/index.html)
64
	 * Triggers the events onDisplayElements,beforeLoadView
65
	 */
66 7
	public function index() {
67 7
		$objects = $this->getInstances ( $totalCount ,$this->activePage);
68 7
		$modal = ($this->_getModelViewer ()->isModal ( $objects, $this->model )) ? "modal" : "no";
69 7
		$dt = $this->_getModelViewer ()->getModelDataTable ( $objects, $this->model, $totalCount ,$this->activePage);
70 7
		$this->jquery->getOnClick ( '#btAddNew', $this->_getBaseRoute () . '/newModel/' . $modal, '#frm-add-update', [ 'hasLoader' => 'internal' ] );
71 7
		$this->_getEvents ()->onDisplayElements ( $dt, $objects, false );
72
		$this->crudLoadView ( $this->_getFiles ()->getViewIndex (), [ 'classname' => $this->model,'messages' => $this->jquery->semantic ()->matchHtmlComponents ( function ($compo) {
73 7
			return $compo instanceof HtmlMessage;
74 7
		} ) ] );
75 7
	}
76
	
77 2
	public function updateMember($member, $callback = false) {
78 2
		$instance = $_SESSION ['instance'] ?? null;
79 2
		if (isset ( $instance )) {
80 2
			$this->_getEvents ()->onBeforeUpdateRequest ( $_POST, false );
81
			$updated = CRUDHelper::update ( $instance, $_POST, true, true, function ($inst) {
82 2
				$this->_getEvents ()->onBeforeUpdate ( $inst, false );
83 2
			} );
84 2
				if ($updated) {
85 2
					if ($callback === false) {
86 1
						$dt = $this->_getModelViewer ()->getModelDataTable ( [ $instance ], $this->model, 1 );
87 1
						$dt->setGroupByFields(null);
88 1
						$dt->compile ();
89 1
						echo new HtmlContentOnly ( $dt->getFieldValue ( $member ) );
90
					} else {
91 1
						if (\method_exists ( $this, $callback )) {
92 1
							$this->$callback ( $member, $instance );
93
						} else {
94 2
							throw new \Exception ( "The method `" . $callback . "` does not exists in " . get_class () );
95
						}
96
					}
97
				} else {
98 2
					UResponse::setResponseCode ( 404 );
99
				}
100
		} else {
101
			throw new \Exception ( '$_SESSION["instance"] is null' );
102
		}
103 2
	}
104
	
105
	/**
106
	 * Refreshes the area corresponding to the DataTable
107
	 */
108 1
	public function refresh_() {
109 1
		$model = $this->model;
110 1
		if (isset ( $_POST ['s'] )) {
111 1
			$instances = $this->search ( $model, $_POST ['s'] );
112
		} else {
113
			$page = URequest::post ( 'p', 1 );
114
			$instances = $this->getInstances ( $totalCount, $page );
115
		}
116 1
		if (! isset ( $totalCount )) {
117 1
			$totalCount = DAO::count ( $model, $this->_getAdminData ()->_getInstancesFilter ( $model ) );
118
		}
119 1
		$recordsPerPage = $this->_getModelViewer ()->recordsPerPage ( $model, $totalCount );
120 1
		$grpByFields = $this->_getModelViewer ()->getGroupByFields ();
121 1
		if (isset ( $recordsPerPage )) {
122
			if (! is_array ( $grpByFields )) {
123
				UResponse::asJSON ();
124
				echo $this->refreshAsJson($instances);
125
			} else {
126
				$this->_renderDataTableForRefresh ( $instances, $model, $totalCount );
127
			}
128
		} else {
129 1
			$this->jquery->execAtLast ( '$("#search-query-content").html("' . $_POST ['s'] . '");$("#search-query").show();$("#table-details").html("");' );
130 1
			$this->_renderDataTableForRefresh ( $instances, $model, $totalCount );
131
		}
132 1
	}
133
	
134
	/**
135
	 * Edits an instance
136
	 *
137
	 * @param string $modal Accept "no" or "modal" for a modal dialog
138
	 * @param string $ids the primary value(s)
139
	 */
140 2
	public function edit($modal = "no", $ids = "") {
141 2
		if (URequest::isAjax ()) {
142 1
			$instance = $this->getModelInstance ( $ids, false );
143 1
			$instance->_new = false;
144 1
			$this->_edit ( $instance, $modal );
145
		} else {
146 2
			$this->jquery->execAtLast ( "$('._edit[data-ajax={$ids}]').trigger('click');" );
147 2
			$this->index ();
148
		}
149 2
	}
150
	
151
	/**
152
	 * Adds a new instance and edits it
153
	 *
154
	 * @param string $modal Accept "no" or "modal" for a modal dialog
155
	 */
156 1
	public function newModel($modal = "no") {
157 1
		if (URequest::isAjax ()) {
158 1
			$model = $this->model;
159 1
			$instance = new $model ();
160 1
			$this->_getEvents()->onNewInstance($instance);
161 1
			$instance->_new = true;
162 1
			$this->_edit ( $instance, $modal );
163
		} else {
164
			$this->jquery->execAtLast ( "$('.ui.button._new').trigger('click');" );
165
			$this->index ();
166
		}
167 1
	}
168
	
169 3
	public function editMember($member) {
170 3
		$ids = URequest::post ( "id" );
171 3
		$td = URequest::post ( "td" );
172 3
		$part = URequest::post ( "part" );
173 3
		$instance = $this->getModelInstance ( $ids, false, $member );
174 3
		$_SESSION ["instance"] = $instance;
175 3
		$instance->_new = false;
176 3
		$form = $this->_getModelViewer ()->getMemberForm ( "frm-member-" . $member, $instance, $member, $td, $part, 'updateMember' );
177 3
		$form->setLibraryId ( "_compo_" );
178 3
		$this->jquery->renderView ( "@framework/main/component.html" );
179 3
	}
180
	
181
	/**
182
	 * Displays an instance
183
	 *
184
	 * @param string $modal
185
	 * @param string $ids
186
	 */
187 2
	public function display($modal = "no", $ids = "") {
188 2
		if (URequest::isAjax ()) {
189 2
			$instance = $this->getModelInstance ( $ids );
190 2
			$key = OrmUtils::getFirstKeyValue ( $instance );
191 2
			$this->jquery->execOn ( "click", "._close", '$("#table-details").html("");$("#dataTable").show();' );
192 2
			$this->jquery->getOnClick ( "._edit", $this->_getBaseRoute () . "/edit/" . $modal . "/" . $key, "#frm-add-update" );
193 2
			$this->jquery->getOnClick ( "._delete", $this->_getBaseRoute () . "/delete/" . $key, "#table-messages" );
194
			
195 2
			$this->_getModelViewer ()->getModelDataElement ( $instance, $this->model, $modal );
196 2
			$this->jquery->renderView ( $this->_getFiles ()->getViewDisplay (), [ "classname" => $this->model,"instance" => $instance,"pk" => $key ] );
197
		} else {
198 2
			$this->jquery->execAtLast ( "$('._display[data-ajax={$ids}]').trigger('click');" );
199 2
			$this->index ();
200
		}
201 2
	}
202
	
203
	/**
204
	 * Deletes an instance
205
	 *
206
	 * @param mixed $ids
207
	 */
208 3
	public function delete($ids) {
209 3
		if (URequest::isAjax ()) {
210 3
			$instance = $this->getModelInstance ( $ids );
211 3
			$instanceString = $this->getInstanceToString ( $instance );
212 3
			if (\count ( $_POST ) > 0) {
213
				try {
214 2
					if (DAO::remove ( $instance )) {
215 1
						$message = new CRUDMessage ( "Deletion of `<b>" . $instanceString . "</b>`", "Deletion", "info", "info circle", 4000 );
216 1
						$message = $this->_getEvents ()->onSuccessDeleteMessage ( $message, $instance );
217 1
						$this->jquery->exec ( "$('._element[data-ajax={$ids}]').remove();", true );
218
					} else {
219 1
						$message = new CRUDMessage ( "Can not delete `" . $instanceString . "`", "Deletion", "warning", "warning circle" );
220 2
						$message = $this->_getEvents ()->onErrorDeleteMessage ( $message, $instance );
221
					}
222
				} catch ( \Exception $e ) {
223
					$message = new CRUDMessage ( "Exception : can not delete `" . $instanceString . "`", "Exception", "warning", "warning" );
224
					$message = $this->_getEvents ()->onErrorDeleteMessage ( $message, $instance );
225
				}
226 2
				$message = $this->showSimpleMessage_ ( $message );
227
			} else {
228 3
				$message = new CRUDMessage ( "Do you confirm the deletion of `<b>" . $instanceString . "</b>`?", "Remove confirmation", "error", "question circle" );
229 3
				$message = $this->_getEvents ()->onConfDeleteMessage ( $message, $instance );
230 3
				$message = $this->showConfMessage_ ( $message, $this->_getBaseRoute () . "/delete/{$ids}", "#table-messages", $ids );
231
			}
232 3
			echo $message;
233 3
			echo $this->jquery->compile ( $this->view );
234
		} else {
235
			$this->jquery->execAtLast ( "$('._delete[data-ajax={$ids}]').trigger('click');" );
236
			$this->index ();
237
		}
238 3
	}
239
	
240 1
	public function refreshTable($id = null) {
241 1
		$compo = $this->_showModel ( $id );
242 1
		$this->jquery->execAtLast ( '$("#table-details").html("");' );
243 1
		$compo->setLibraryId ( "_compo_" );
244 1
		$this->jquery->renderView ( "@framework/main/component.html" );
245 1
	}
246
	
247
	/**
248
	 * Updates an instance from the data posted in a form
249
	 *
250
	 * @return object The updated instance
251
	 */
252 2
	public function updateModel() {
253 2
		$message = new CRUDMessage ( "Modifications were successfully saved", "Updating" );
254 2
		$instance = $_SESSION ["instance"] ?? null;
255 2
		if (isset ( $instance )) {
256 2
			$isNew = $instance->_new;
257
			try {
258 2
				$this->_getEvents ()->onBeforeUpdateRequest ( $_POST, $isNew );
259
				$updated = CRUDHelper::update ( $instance, $_POST, true, true, function ($inst, $isNew) {
260 2
					$this->_getEvents ()->onBeforeUpdate ( $inst, $isNew );
261 2
				} );
262 2
					if ($updated) {
263 2
						$message->setType ( "success" )->setIcon ( "check circle outline" );
264 2
						$message = $this->_getEvents ()->onSuccessUpdateMessage ( $message, $instance );
265 2
						$this->refreshInstance ( $instance, $isNew );
266
					} else {
267
						$message->setMessage ( "An error has occurred. Can not save changes." )->setType ( "error" )->setIcon ( "warning circle" );
268 2
						$message = $this->_getEvents ()->onErrorUpdateMessage ( $message, $instance );
269
					}
270
			} catch ( \Exception $e ) {
271
				$instanceString = $this->getInstanceToString ( $instance );
272
				$message = new CRUDMessage ( "Exception : can not update `" . $instanceString . "`", "Exception", "warning", "warning" );
273
				$message = $this->_getEvents ()->onErrorUpdateMessage ( $message, $instance );
274
			}
275 2
			echo $this->showSimpleMessage_ ( $message, "updateMsg" );
276 2
			echo $this->jquery->compile ( $this->view );
277 2
			return $instance;
278
		} else {
279
			throw new \Exception ( '$_SESSION["instance"] is null' );
280
		}
281
	}
282
	
283
	/**
284
	 * Shows associated members with foreign keys
285
	 *
286
	 * @param mixed $ids
287
	 */
288 2
	public function showDetail($ids) {
289 2
		if (URequest::isAjax ()) {
290 2
			$instance = $this->getModelInstance ( $ids );
291 2
			$viewer = $this->_getModelViewer ();
292 2
			$hasElements = false;
293 2
			$model = $this->model;
294 2
			$fkInstances = CRUDHelper::getFKIntances ( $instance, $model );
295 2
			$semantic = $this->jquery->semantic ();
296 2
			$grid = $semantic->htmlGrid ( "detail" );
297 2
			if (($nb = \count ( $fkInstances )) > 0) {
298 2
				$wide = intval ( 16 / $nb );
299 2
				if ($wide < 4)
300
					$wide = 4;
301 2
					foreach ( $fkInstances as $member => $fkInstanceArray ) {
302 2
						$element = $viewer->getFkMemberElementDetails ( $member, $fkInstanceArray ["objectFK"], $fkInstanceArray ["fkClass"], $fkInstanceArray ["fkTable"] );
303 2
						if (isset ( $element )) {
304 2
							$grid->addCol ( $wide )->setContent ( $element );
305 2
							$hasElements = true;
306
						}
307
					}
308 2
					if ($hasElements) {
309 2
						echo $grid;
310 2
						$url = $this->_getFiles ()->getDetailClickURL ( $this->model );
311 2
						if (UString::isNotNull ( $url )) {
312
							$this->detailClick ( $url );
313
						}
314
					}
315 2
					echo $this->jquery->compile ( $this->view );
316
			}
317
		} else {
318 1
			$this->jquery->execAtLast ( "$('tr[data-ajax={$ids}]').trigger('click');" );
319 1
			$this->index ();
320
		}
321 2
	}
322
	
323 1
	public function detailClick($url,$responseElement='#divTable',$attributes=[ "attr" => "data-ajax"]) {
324 1
		$this->jquery->postOnClick ( ".showTable", $this->_getBaseRoute () . "/" . $url, "{}", $responseElement, $attributes );
325 1
	}
326
}
327