Completed
Push — master ( 530ddf...47cb1f )
by Jean-Christophe
02:11
created

CRUDController::getEvents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\admin\viewers\ModelViewer;
9
use Ubiquity\controllers\semantic\MessagesTrait;
10
use Ubiquity\utils\http\URequest;
11
use Ubiquity\utils\http\UResponse;
12
use Ubiquity\controllers\rest\ResponseFormatter;
13
use Ajax\semantic\widgets\datatable\Pagination;
14
use Ubiquity\orm\OrmUtils;
15
use Ubiquity\utils\base\UString;
16
17
abstract class CRUDController extends ControllerBase implements HasModelViewerInterface{
18
	use MessagesTrait;
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
	 */
29
	public function index() {
30
		$objects=$this->getInstances();
31
		$modal=($this->_getModelViewer()->isModal($objects,$this->model))?"modal":"no";
32
		$this->_getModelViewer()->getModelDataTable($objects, $this->model);
33
		$this->jquery->getOnClick ( "#btAddNew", $this->_getBaseRoute() . "/newModel/" . $modal, "#frm-add-update",["hasLoader"=>"internal"] );
34
		$this->crudLoadView($this->_getFiles()->getViewIndex(), [ "classname" => $this->model ]);		
35
	}
36
	
37
	protected function getInstances($page=1,$id=null){
38
		$this->activePage=$page;
39
		$model=$this->model;
40
		$condition=$this->_getInstancesFilter($model);
41
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,DAO::count($model,$condition));
42
		if(is_numeric($recordsPerPage)){
43
			if(isset($id)){
44
				$rownum=DAO::getRownum($model, $id);
45
				$this->activePage=Pagination::getPageOfRow($rownum,$recordsPerPage);
46
			}
47
			return DAO::paginate($model,$this->activePage,$recordsPerPage);
48
		}
49
		return DAO::getAll($model,$condition);
50
	}
51
	
52
	public function _getInstancesFilter($model){
53
		return "1=1";
54
	}
55
	
56
	protected function search($model,$search){
57
		$fields=$this->_getAdminData()->getSearchFieldNames($model);
58
		$condition=$this->_getInstancesFilter($model);
59
		return CRUDHelper::search($model, $search, $fields,$condition);
60
	}
61
	
62
	public function refresh_(){
63
		$model=$this->model;
64
		if(isset($_POST["s"])){
65
			$instances=$this->search($model, $_POST["s"]);
66
		}else{
67
			$instances=$this->getInstances(URequest::post("p",1));
68
		}
69
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,DAO::count($model,$this->_getInstancesFilter($model)));
70
		if(isset($recordsPerPage)){
71
			UResponse::asJSON();
72
			$responseFormatter=new ResponseFormatter();
73
			print_r($responseFormatter->getJSONDatas($instances));
74
		}else{
75
			$this->formModal=($this->_getModelViewer()->isModal($instances,$model))? "modal" : "no";
76
			$compo= $this->_getModelViewer()->getModelDataTable($instances, $model)->refresh(["tbody"]);
77
			$this->jquery->execAtLast('$("#search-query-content").html("'.$_POST["s"].'");$("#search-query").show();$("#table-details").html("");');
78
			$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);
79
		}
80
	}
81
	
82
	/**
83
	 * Edits an instance
84
	 * @param string $modal Accept "no" or "modal" for a modal dialog
85
	 * @param string $ids the primary value(s)
86
	 */
87 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...
88
		if(URequest::isAjax()){
89
			$instance=$this->getModelInstance($ids);
90
			$instance->_new=false;
91
			$this->_edit($instance, $modal);
92
		}else{
93
			$this->jquery->execAtLast("$('._edit[data-ajax={$ids}]').trigger('click');");
94
			$this->index();
95
		}
96
	}
97
	/**
98
	 * Adds a new instance and edits it
99
	 * @param string $modal Accept "no" or "modal" for a modal dialog
100
	 */
101 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...
102
		if(URequest::isAjax()){
103
			$model=$this->model;
104
			$instance=new $model();
105
			$instance->_new=true;
106
			$this->_edit($instance, $modal);
107
		}else{
108
			$this->jquery->execAtLast("$('.ui.button._new').trigger('click');");
109
			$this->index();
110
		}
111
	}
112
	
113
	/**
114
	 * Displays an instance
115
	 * @param string $modal
116
	 * @param string $ids
117
	 */
118
	public function display($modal="no",$ids=""){
119
		if(URequest::isAjax()){
120
			$instance=$this->getModelInstance($ids);
121
			$key=OrmUtils::getFirstKeyValue($instance);
122
			$this->jquery->execOn("click","._close",'$("#table-details").html("");$("#dataTable").show();');
123
			$this->jquery->getOnClick("._edit", $this->_getBaseRoute()."/edit/".$modal."/".$key,"#frm-add-update");
124
			$this->jquery->getOnClick("._delete", $this->_getBaseRoute()."/delete/".$key,"#table-messages");
125
			
126
			$this->_getModelViewer()->getModelDataElement($instance, $this->model,$modal);
127
			$this->jquery->renderView($this->_getFiles()->getViewDisplay(), [ "classname" => $this->model,"instance"=>$instance,"pk"=>$key ]);
128
		}else{
129
			$this->jquery->execAtLast("$('._display[data-ajax={$ids}]').trigger('click');");
130
			$this->index();
131
		}
132
	}
133
	
134
	protected function _edit($instance, $modal="no") {
135
		$_SESSION["instance"]=$instance;
136
		$modal=($modal == "modal");
137
		$form=$this->_getModelViewer()->getForm("frmEdit", $instance);
138
		$this->jquery->click("#action-modal-frmEdit-0", "$('#frmEdit').form('submit');", false);
139
		if (!$modal) {
140
			$this->jquery->click("#bt-cancel", "$('#form-container').transition('drop');");
141
			$this->jquery->compile($this->view);
142
			$this->loadView($this->_getFiles()->getViewForm(), [ "modal" => $modal ]);
143
		} else {
144
			$this->jquery->exec("$('#modal-frmEdit').modal('show');", true);
145
			$form=$form->asModal(\get_class($instance));
146
			$form->setActions([ "Okay","Cancel" ]);
147
			$btOkay=$form->getAction(0);
148
			$btOkay->addClass("green")->setValue("Validate modifications");
149
			$form->onHidden("$('#modal-frmEdit').remove();");
150
			echo $form->compile($this->jquery, $this->view);
151
			echo $this->jquery->compile($this->view);
152
		}
153
	}
154
	
155
	protected function _showModel($id=null) {
156
		$model=$this->model;
157
		$datas=$this->getInstances(1,$id);
158
		$this->formModal=($this->_getModelViewer()->isModal($datas,$model))? "modal" : "no";
159
		return $this->_getModelViewer()->getModelDataTable($datas, $model,$this->activePage);
160
	}
161
	
162
	/**
163
	 * Deletes an instance
164
	 * @param mixed $ids
165
	 */
166
	public function delete($ids) {
167
		if(URequest::isAjax()){
168
			$instance=$this->getModelInstance($ids);
169 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...
170
				$instanceString=$instance . "";
171
			else
172
				$instanceString=get_class($instance);
173
			if (sizeof($_POST) > 0) {
174
				try{
175
					if (DAO::remove($instance)) {
0 ignored issues
show
Bug introduced by
It seems like $instance defined by $this->getModelInstance($ids) on line 168 can also be of type null; however, Ubiquity\orm\traits\DAOUpdatesTrait::remove() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
176
						$message=new CRUDMessage("Deletion of `<b>" . $instanceString . "</b>`","Deletion","info","info circle",4000);
177
						$message=$this->_getEvents()->onSuccessDeleteMessage($message);
178
						$this->jquery->exec("$('._element[data-ajax={$ids}]').remove();", true);
179
					} else {
180
						$message=new CRUDMessage("Can not delete `" . $instanceString . "`","Deletion","warning","warning circle");
181
						$message=$this->_getEvents()->onErrorDeleteMessage($message);
182
					}
183
				}catch (\Exception $e){
184
					$message=new CRUDMessage("Exception : can not delete `" . $instanceString . "`","Exception", "warning", "warning");
185
					$message=$this->_getEvents()->onErrorDeleteMessage($message);
186
				}
187
				$message=$this->_showSimpleMessage($message);
188
			} else {
189
				$message=new CRUDMessage("Do you confirm the deletion of `<b>" . $instanceString . "</b>`?", "Remove confirmation","error");
190
				$this->_getEvents()->onConfDeleteMessage($message);
0 ignored issues
show
Unused Code introduced by
The call to the method Ubiquity\controllers\cru...::onConfDeleteMessage() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
191
				$message=$this->_showConfMessage($message, $this->_getBaseRoute() . "/delete/{$ids}", "#table-messages", $ids);
192
			}
193
			echo $message;
194
			echo $this->jquery->compile($this->view);
195
		}else{
196
			$this->jquery->execAtLast("$('._delete[data-ajax={$ids}]').trigger('click');");
197
			$this->index();
198
		}
199
	}
200
	
201
202
	
203
	public function refreshTable($id=null) {
204
		$compo= $this->_showModel($id);
205
		$this->jquery->execAtLast('$("#table-details").html("");');
206
		$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);	
207
	}
208
	
209
	/**
210
	 * Updates an instance from the data posted in a form
211
	 */
212
	public function update() {
213
		$message=new CRUDMessage("Modifications were successfully saved", "Updating");
214
		$instance=@$_SESSION["instance"];
215
		$isNew=$instance->_new;
216
		try{
217
			$updated=CRUDHelper::update($instance, $_POST,$this->_getAdminData()->getUpdateManyToOneInForm(),$this->_getAdminData()->getUpdateManyToManyInForm());
218
			if($updated){
219
				$message->setType("success")->setIcon("check circle outline");
220
				$message=$this->_getEvents()->onSuccessUpdateMessage($message);
221
				$this->refreshInstance($instance,$isNew);
222
			} else {
223
				$message->setMessage("An error has occurred. Can not save changes.")->setType("error")->setIcon("warning circle");
0 ignored issues
show
Bug introduced by
The method setType cannot be called on $message->setMessage('An...Can not save changes.') (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
224
				$message=$this->_getEvents()->onErrorUpdateMessage($message);
225
			}
226
		}catch(\Exception $e){
227 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...
228
				$instanceString=$instance . "";
229
			else
230
				$instanceString=get_class($instance);
231
			$message=new CRUDMessage("Exception : can not update `" . $instanceString . "`","Exception", "warning", "warning");
232
			$message=$this->_getEvents()->onErrorUpdateMessage($message);
233
		}
234
		echo $this->_showSimpleMessage($message,"updateMsg");
235
		echo $this->jquery->compile($this->view);
236
	}
237
	
238
	protected function refreshInstance($instance,$isNew){
239
		if($this->_getAdminData()->refreshPartialInstance() && !$isNew){
240
			$this->jquery->setJsonToElement(OrmUtils::objectAsJSON($instance));
241
		}else{
242
			$pk=OrmUtils::getFirstKeyValue($instance);
243
			$this->jquery->get($this->_getBaseRoute() . "/refreshTable/".$pk, "#lv", [ "jqueryDone" => "replaceWith" ]);
244
		}
245
	}
246
	
247
	/**
248
	 * Shows associated members with foreign keys
249
	 * @param mixed $ids
250
	 */
251
	public function showDetail($ids) {
252
		if(URequest::isAjax()){
253
			$instance=$this->getModelInstance($ids);
254
			$viewer=$this->_getModelViewer();
255
			$hasElements=false;
256
			$model=$this->model;
257
			$fkInstances=CRUDHelper::getFKIntances($instance, $model);
258
			$semantic=$this->jquery->semantic();
259
			$grid=$semantic->htmlGrid("detail");
260
			if (sizeof($fkInstances) > 0) {
261
				$wide=intval(16 / sizeof($fkInstances));
262
				if ($wide < 4)
263
					$wide=4;
264
					foreach ( $fkInstances as $member=>$fkInstanceArray ) {
265
						$element=$viewer->getFkMemberElementDetails($member,$fkInstanceArray["objectFK"],$fkInstanceArray["fkClass"],$fkInstanceArray["fkTable"]);
266
						if (isset($element)) {
267
							$grid->addCol($wide)->setContent($element);
268
							$hasElements=true;
269
						}
270
					}
271
					if ($hasElements)
272
						echo $grid;
273
						$url=$this->_getEvents()->onDetailClickURL($this->model);
274
					if(UString::isNotNull($url)){
275
						$this->detailClick($url);
276
					}
277
					echo $this->jquery->compile($this->view);
278
			}
279
		}else{
280
			$this->jquery->execAtLast("$('tr[data-ajax={$ids}]').trigger('click');");
281
			$this->index();
282
		}
283
284
	}
285
	
286
	public function detailClick($url) {
287
		$this->jquery->postOnClick(".showTable", $this->_getBaseRoute() . "/".$url,"{}", "#divTable", [ "attr" => "data-ajax","ajaxTransition" => "random" ]);
288
	}
289
	
290
	private function getModelInstance($ids) {
291
		$ids=\explode("_", $ids);
292
		$instance=DAO::getOne($this->model, $ids);
293
		if(isset($instance)){
294
			return $instance;
295
		}
296
		$message=new CRUDMessage("This object does not exist!","Get object","warning","warning circle");
297
		$message=$this->_getEvents()->onNotFoundMessage($message);
298
		echo $this->_showSimpleMessage($message);
299
		echo $this->jquery->compile($this->view);
300
		exit(1);
301
	}
302
	
303
	/**
304
	 * To override for defining a new adminData
305
	 * @return CRUDDatas
306
	 */
307
	protected function getAdminData ():CRUDDatas{
308
		return new CRUDDatas();
309
	}
310
	
311
	public function _getAdminData ():CRUDDatas{
312
		return $this->getSingleton($this->modelViewer,"getAdminData");
313
	}
314
	
315
	/**
316
	 * To override for defining a new ModelViewer
317
	 * @return ModelViewer
318
	 */
319
	protected function getModelViewer ():ModelViewer{
320
		return new ModelViewer($this);
321
	}
322
	
323
	private function _getModelViewer():ModelViewer{
324
		return $this->getSingleton($this->modelViewer,"getModelViewer");
325
	}
326
	
327
	/**
328
	 * To override for changing view files
329
	 * @return CRUDFiles
330
	 */
331
	protected function getFiles ():CRUDFiles{
332
		return new CRUDFiles();
333
	}
334
	
335
	private function _getFiles():CRUDFiles{
336
		return $this->getSingleton($this->crudFiles,"getFiles");
337
	}
338
	
339
	/**
340
	 * To override for changing events
341
	 * @return CRUDEvents
342
	 */
343
	protected function getEvents ():CRUDEvents{
344
		return new CRUDEvents();
0 ignored issues
show
Bug introduced by
The call to CRUDEvents::__construct() misses a required argument $controller.

This check looks for function calls that miss required arguments.

Loading history...
345
	}
346
	
347
	private function _getEvents():CRUDEvents{
348
		return $this->getSingleton($this->events,"getEvents");
349
	}
350
	
351
	private function getSingleton($value, $method) {
352
		if (! isset ( $value )) {
353
			$value = $this->$method ();
354
		}
355
		return $value;
356
	}
357
	
358
	private function crudLoadView($viewName,$vars=[]){
359
		$this->_getEvents()->beforeLoadView($viewName,$vars);
360
		if(!URequest::isAjax()){
361
			$files=$this->_getFiles();
362
			$mainTemplate=$files->getBaseTemplate();
363
			if(isset($mainTemplate)){
364
				$vars["_viewname"]=$viewName;
365
				$vars["_base"]=$mainTemplate;
366
				$this->jquery->renderView($files->getViewBaseTemplate(),$vars);
367
			}else{
368
				$vars["hasScript"]=true;
369
				$this->jquery->renderView($viewName,$vars);
370
			}
371
		}else{
372
			$vars["hasScript"]=true;
373
			$this->jquery->renderView($viewName,$vars);
374
		}
375
	}
376
377
}
378