Completed
Push — master ( ceccd5...145e32 )
by Jean-Christophe
01:37
created

CRUDController   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 261
Duplicated Lines 11.11 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 14
dl 29
loc 261
rs 9.36
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A index() 0 8 2
A updateMember() 0 19 4
A refresh_() 0 26 5
A edit() 10 10 2
A newModel() 11 11 2
A editMember() 0 11 1
A display() 0 15 2
B delete() 4 34 6
A refreshTable() 0 6 1
A update() 4 26 4
B showDetail() 0 35 8
A detailClick() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Ubiquity\controllers\crud;
4
5
use Ubiquity\orm\DAO;
6
use Ubiquity\controllers\ControllerBase;
7
use Ubiquity\controllers\admin\interfaces\HasModelViewerInterface;
8
use Ubiquity\controllers\semantic\MessagesTrait;
9
use Ubiquity\utils\http\URequest;
10
use Ubiquity\utils\http\UResponse;
11
use Ubiquity\controllers\rest\ResponseFormatter;
12
use Ubiquity\orm\OrmUtils;
13
use Ubiquity\utils\base\UString;
14
use Ajax\semantic\html\collections\HtmlMessage;
15
use Ajax\common\html\HtmlContentOnly;
16
17
abstract class CRUDController extends ControllerBase implements HasModelViewerInterface{
18
	use MessagesTrait,CRUDControllerUtilitiesTrait;
19
	protected $model;
20
	protected $modelViewer;
21
	protected $events;
22
	protected $crudFiles;
23
	protected $adminDatas;
24
	protected $activePage;
25
	
26
	/**
27
	 * Default page : list all objects
28
	 * Uses modelViewer.isModal, modelViewer.getModelDataTable
29
	 * Uses CRUDFiles.getViewIndex template (default : @framework/crud/index.html)
30
	 * Triggers the events onDisplayElements,beforeLoadView
31
	 */
32
	public function index() {
33
		$objects=$this->getInstances($totalCount);
34
		$modal=($this->_getModelViewer()->isModal($objects,$this->model))?"modal":"no";
35
		$dt=$this->_getModelViewer()->getModelDataTable($objects, $this->model,$totalCount);
36
		$this->jquery->getOnClick ( "#btAddNew", $this->_getBaseRoute() . "/newModel/" . $modal, "#frm-add-update",["hasLoader"=>"internal"] );
37
		$this->_getEvents()->onDisplayElements($dt,$objects,false);
38
		$this->crudLoadView($this->_getFiles()->getViewIndex(), [ "classname" => $this->model ,"messages"=>$this->jquery->semantic()->matchHtmlComponents(function($compo){return $compo instanceof HtmlMessage;})]);		
39
	}
40
	
41
	public function updateMember($member,$callback=false){
42
		$instance=@$_SESSION["instance"];
43
		$updated=CRUDHelper::update($instance, $_POST);
44
		if($updated){
45
			if($callback===false){
46
				$dt=$this->_getModelViewer()->getModelDataTable([$instance], $this->model, 1);
47
				$dt->compile();
48
				echo new HtmlContentOnly($dt->getFieldValue($member));
49
			}else{
50
				if(method_exists($this, $callback)){
51
					$this->$callback($member,$instance);
52
				}else{
53
					throw new \Exception("The method `".$callback."` does not exists in ".get_class());
54
				}
55
			}
56
		}else{
57
			UResponse::setResponseCode(404);
58
		}
59
	}
60
	
61
	/**
62
	 * Refreshes the area corresponding to the DataTable
63
	 */
64
	public function refresh_(){
65
		$model=$this->model;
66
		if(isset($_POST["s"])){
67
			$instances=$this->search($model, $_POST["s"]);
68
		}else{
69
			$page=URequest::post("p",1);
70
			$instances=$this->getInstances($totalCount,$page);
71
		}
72
		if(!isset($totalCount)){
73
			$totalCount=DAO::count($model,$this->_getAdminData()->_getInstancesFilter($model));
74
		}
75
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,$totalCount);
76
		$grpByFields=$this->_getModelViewer()->getGroupByFields();
77
		if(isset($recordsPerPage)){
78
			if(!is_array($grpByFields)){
79
				UResponse::asJSON();
80
				$responseFormatter=new ResponseFormatter();
81
				print_r($responseFormatter->getJSONDatas($instances));
82
			}else{
83
				$this->_renderDataTableForRefresh($instances, $model,$totalCount);
84
			}
85
		}else{
86
			$this->jquery->execAtLast('$("#search-query-content").html("'.$_POST["s"].'");$("#search-query").show();$("#table-details").html("");');
87
			$this->_renderDataTableForRefresh($instances, $model,$totalCount);
88
		}
89
	}
90
91
	/**
92
	 * Edits an instance
93
	 * @param string $modal Accept "no" or "modal" for a modal dialog
94
	 * @param string $ids the primary value(s)
95
	 */
96 View Code Duplication
	public function edit($modal="no", $ids="") {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
97
		if(URequest::isAjax()){
98
			$instance=$this->getModelInstance($ids);
99
			$instance->_new=false;
100
			$this->_edit($instance, $modal);
101
		}else{
102
			$this->jquery->execAtLast("$('._edit[data-ajax={$ids}]').trigger('click');");
103
			$this->index();
104
		}
105
	}
106
	/**
107
	 * Adds a new instance and edits it
108
	 * @param string $modal Accept "no" or "modal" for a modal dialog
109
	 */
110 View Code Duplication
	public function newModel($modal="no") {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
		if(URequest::isAjax()){
112
			$model=$this->model;
113
			$instance=new $model();
114
			$instance->_new=true;
115
			$this->_edit($instance, $modal);
116
		}else{
117
			$this->jquery->execAtLast("$('.ui.button._new').trigger('click');");
118
			$this->index();
119
		}
120
	}
121
	
122
	public function editMember($member){
123
		$ids=URequest::post("id");
124
		$td=URequest::post("td");
125
		$part=URequest::post("part");
126
		$instance=$this->getModelInstance($ids,$member);
127
		$_SESSION["instance"]=$instance;
128
		$instance->_new=false;
129
		$form=$this->_getModelViewer()->getMemberForm("frm-member-".$member, $instance, $member,$td,$part);
130
		$form->setLibraryId("_compo_");
131
		$this->jquery->renderView("@framework/main/component.html");
132
	}
133
	
134
	/**
135
	 * Displays an instance
136
	 * @param string $modal
137
	 * @param string $ids
138
	 */
139
	public function display($modal="no",$ids=""){
140
		if(URequest::isAjax()){
141
			$instance=$this->getModelInstance($ids);
142
			$key=OrmUtils::getFirstKeyValue($instance);
143
			$this->jquery->execOn("click","._close",'$("#table-details").html("");$("#dataTable").show();');
144
			$this->jquery->getOnClick("._edit", $this->_getBaseRoute()."/edit/".$modal."/".$key,"#frm-add-update");
145
			$this->jquery->getOnClick("._delete", $this->_getBaseRoute()."/delete/".$key,"#table-messages");
146
			
147
			$this->_getModelViewer()->getModelDataElement($instance, $this->model,$modal);
148
			$this->jquery->renderView($this->_getFiles()->getViewDisplay(), [ "classname" => $this->model,"instance"=>$instance,"pk"=>$key ]);
149
		}else{
150
			$this->jquery->execAtLast("$('._display[data-ajax={$ids}]').trigger('click');");
151
			$this->index();
152
		}
153
	}
154
	
155
	/**
156
	 * Deletes an instance
157
	 * @param mixed $ids
158
	 */
159
	public function delete($ids) {
160
		if(URequest::isAjax()){
161
			$instance=$this->getModelInstance($ids);
162 View Code Duplication
			if (method_exists($instance, "__toString"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
				$instanceString=$instance . "";
164
			else
165
				$instanceString=get_class($instance);
166
			if (sizeof($_POST) > 0) {
167
				try{
168
					if (DAO::remove($instance)) {
1 ignored issue
show
Documentation introduced by
$instance is of type array<integer,?>|null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
						$message=new CRUDMessage("Deletion of `<b>" . $instanceString . "</b>`","Deletion","info","info circle",4000);
170
						$message=$this->_getEvents()->onSuccessDeleteMessage($message,$instance);
1 ignored issue
show
Documentation introduced by
$instance is of type array<integer,?>|null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
171
						$this->jquery->exec("$('._element[data-ajax={$ids}]').remove();", true);
172
					} else {
173
						$message=new CRUDMessage("Can not delete `" . $instanceString . "`","Deletion","warning","warning circle");
174
						$message=$this->_getEvents()->onErrorDeleteMessage($message,$instance);
1 ignored issue
show
Documentation introduced by
$instance is of type array<integer,?>|null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
175
					}
176
				}catch (\Exception $e){
177
					$message=new CRUDMessage("Exception : can not delete `" . $instanceString . "`","Exception", "warning", "warning");
178
					$message=$this->_getEvents()->onErrorDeleteMessage($message,$instance);
1 ignored issue
show
Documentation introduced by
$instance is of type array<integer,?>|null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
179
				}
180
				$message=$this->_showSimpleMessage($message);
181
			} else {
182
				$message=new CRUDMessage("Do you confirm the deletion of `<b>" . $instanceString . "</b>`?", "Remove confirmation","error","question circle");
183
				$message=$this->_getEvents()->onConfDeleteMessage($message,$instance);
1 ignored issue
show
Documentation introduced by
$instance is of type array<integer,?>|null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
184
				$message=$this->_showConfMessage($message, $this->_getBaseRoute() . "/delete/{$ids}", "#table-messages", $ids);
185
			}
186
			echo $message;
187
			echo $this->jquery->compile($this->view);
188
		}else{
189
			$this->jquery->execAtLast("$('._delete[data-ajax={$ids}]').trigger('click');");
190
			$this->index();
191
		}
192
	}
193
	
194
	public function refreshTable($id=null) {
195
		$compo= $this->_showModel($id);
196
		$this->jquery->execAtLast('$("#table-details").html("");');
197
		$compo->setLibraryId("_compo_");
198
		$this->jquery->renderView("@framework/main/component.html");	
199
	}
200
	
201
	/**
202
	 * Updates an instance from the data posted in a form
203
	 * @return object The updated instance
204
	 */
205
	public function update() {
206
		$message=new CRUDMessage("Modifications were successfully saved", "Updating");
207
		$instance=@$_SESSION["instance"];
208
		$isNew=$instance->_new;
209
		try{
210
			$updated=CRUDHelper::update($instance, $_POST);
211
			if($updated){
212
				$message->setType("success")->setIcon("check circle outline");
213
				$message=$this->_getEvents()->onSuccessUpdateMessage($message,$instance);
214
				$this->refreshInstance($instance,$isNew);
215
			} else {
216
				$message->setMessage("An error has occurred. Can not save changes.")->setType("error")->setIcon("warning circle");
217
				$message=$this->_getEvents()->onErrorUpdateMessage($message,$instance);
218
			}
219
		}catch(\Exception $e){
220 View Code Duplication
			if (method_exists($instance, "__toString"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
				$instanceString=$instance . "";
222
			else
223
				$instanceString=get_class($instance);
224
			$message=new CRUDMessage("Exception : can not update `" . $instanceString . "`","Exception", "warning", "warning");
225
			$message=$this->_getEvents()->onErrorUpdateMessage($message,$instance);
226
		}
227
		echo $this->_showSimpleMessage($message,"updateMsg");
228
		echo $this->jquery->compile($this->view);
229
		return $instance;
230
	}
231
232
	
233
	/**
234
	 * Shows associated members with foreign keys
235
	 * @param mixed $ids
236
	 */
237
	public function showDetail($ids) {
238
		if(URequest::isAjax()){
239
			$instance=$this->getModelInstance($ids);
240
			$viewer=$this->_getModelViewer();
241
			$hasElements=false;
242
			$model=$this->model;
243
			$fkInstances=CRUDHelper::getFKIntances($instance, $model);
244
			$semantic=$this->jquery->semantic();
245
			$grid=$semantic->htmlGrid("detail");
246
			if (sizeof($fkInstances) > 0) {
247
				$wide=intval(16 / sizeof($fkInstances));
248
				if ($wide < 4)
249
					$wide=4;
250
					foreach ( $fkInstances as $member=>$fkInstanceArray ) {
251
						$element=$viewer->getFkMemberElementDetails($member,$fkInstanceArray["objectFK"],$fkInstanceArray["fkClass"],$fkInstanceArray["fkTable"]);
252
						if (isset($element)) {
253
							$grid->addCol($wide)->setContent($element);
254
							$hasElements=true;
255
						}
256
					}
257
					if ($hasElements){
258
						echo $grid;
259
						$url=$this->_getFiles()->getDetailClickURL($this->model);
260
						if(UString::isNotNull($url)){
261
							$this->detailClick($url);
262
						}
263
					}
264
					echo $this->jquery->compile($this->view);
265
			}
266
		}else{
267
			$this->jquery->execAtLast("$('tr[data-ajax={$ids}]').trigger('click');");
268
			$this->index();
269
		}
270
271
	}
272
	
273
	public function detailClick($url) {
274
		$this->jquery->postOnClick(".showTable", $this->_getBaseRoute() . "/".$url,"{}", "#divTable", [ "attr" => "data-ajax","ajaxTransition" => "random" ]);
275
	}
276
277
}
278