Completed
Push — master ( cac30c...ca9f6a )
by Jean-Christophe
01:57
created

CRUDController::update()   B

Complexity

Conditions 4
Paths 14

Size

Total Lines 25
Code Lines 22

Duplication

Lines 4
Ratio 16 %

Importance

Changes 0
Metric Value
dl 4
loc 25
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 22
nc 14
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->jquery->compile($this->view);
35
		$this->loadView($this->_getFiles()->getViewIndex(), [ "classname" => $this->model ]);		
36
	}
37
	
38
	protected function getInstances($page=1,$id=null){
39
		$this->activePage=$page;
40
		$model=$this->model;
41
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,DAO::count($model));
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);
50
	}
51
	
52
	protected function search($model,$search){
53
		$fields=$this->_getAdminData()->getSearchFieldNames($model);
54
		return CRUDHelper::search($model, $search, $fields);
55
	}
56
	
57
	public function refresh_(){
58
		$model=$this->model;
59
		if(isset($_POST["s"])){
60
			$instances=$this->search($model, $_POST["s"]);
61
		}else{
62
			$instances=$this->getInstances(URequest::post("p",1));
63
		}
64
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,DAO::count($model));
65
		if(isset($recordsPerPage)){
66
			UResponse::asJSON();
67
			$responseFormatter=new ResponseFormatter();
68
			print_r($responseFormatter->getJSONDatas($instances));
69
		}else{
70
			$this->formModal=($this->_getModelViewer()->isModal($instances,$model))? "modal" : "no";
71
			$compo= $this->_getModelViewer()->getModelDataTable($instances, $model)->refresh(["tbody"]);
72
			$this->jquery->execAtLast('$("#search-query-content").html("'.$_POST["s"].'");$("#search-query").show();$("#table-details").html("");');
73
			$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);
74
		}
75
	}
76
	
77
	/**
78
	 * Edits an instance
79
	 * @param string $modal Accept "no" or "modal" for a modal dialog
80
	 * @param string $ids the primary value(s)
81
	 */
82
	public function edit($modal="no", $ids="") {
83
		$instance=$this->getModelInstance($ids);
84
		$instance->_new=false;
85
		$this->_edit($instance, $modal);
86
	}
87
	/**
88
	 * Adds a new instance and edits it
89
	 * @param string $modal Accept "no" or "modal" for a modal dialog
90
	 */
91
	public function newModel($modal="no") {
92
		$model=$this->model;
93
		$instance=new $model();
94
		$instance->_new=true;
95
		$this->_edit($instance, $modal);
96
	}
97
	
98
	/**
99
	 * Displays an instance
100
	 * @param string $modal
101
	 * @param string $ids
102
	 */
103
	public function display($modal="no",$ids=""){
104
		$instance=$this->getModelInstance($ids);
105
		$key=OrmUtils::getFirstKeyValue($instance);
106
		$this->jquery->execOn("click","._close",'$("#table-details").html("");$("#dataTable").show();');
107
		$this->jquery->getOnClick("._edit", $this->_getBaseRoute()."/edit/".$modal."/".$key,"#frm-add-update");
108
		$this->jquery->getOnClick("._delete", $this->_getBaseRoute()."/delete/".$key,"#table-messages");
109
		
110
		$this->_getModelViewer()->getModelDataElement($instance, $this->model,$modal);
111
		$this->jquery->renderView($this->_getFiles()->getViewDisplay(), [ "classname" => $this->model,"instance"=>$instance,"pk"=>$key ]);
112
	}
113
	
114
	protected function _edit($instance, $modal="no") {
115
		$_SESSION["instance"]=$instance;
116
		$modal=($modal == "modal");
117
		$form=$this->_getModelViewer()->getForm("frmEdit", $instance);
118
		$this->jquery->click("#action-modal-frmEdit-0", "$('#frmEdit').form('submit');", false);
119
		if (!$modal) {
120
			$this->jquery->click("#bt-cancel", "$('#form-container').transition('drop');");
121
			$this->jquery->compile($this->view);
122
			$this->loadView($this->_getFiles()->getViewForm(), [ "modal" => $modal ]);
123
		} else {
124
			$this->jquery->exec("$('#modal-frmEdit').modal('show');", true);
125
			$form=$form->asModal(\get_class($instance));
126
			$form->setActions([ "Okay","Cancel" ]);
127
			$btOkay=$form->getAction(0);
128
			$btOkay->addClass("green")->setValue("Validate modifications");
129
			$form->onHidden("$('#modal-frmEdit').remove();");
130
			echo $form->compile($this->jquery, $this->view);
131
			echo $this->jquery->compile($this->view);
132
		}
133
	}
134
	
135
	protected function _showModel($id=null) {
136
		$model=$this->model;
137
		$datas=$this->getInstances(1,$id);
138
		$this->formModal=($this->_getModelViewer()->isModal($datas,$model))? "modal" : "no";
139
		return $this->_getModelViewer()->getModelDataTable($datas, $model,$this->activePage);
140
	}
141
	
142
	/**
143
	 * Deletes an instance
144
	 * @param mixed $ids
145
	 */
146
	public function delete($ids) {
147
		$instance=$this->getModelInstance($ids);
148 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...
149
			$instanceString=$instance . "";
150
		else
151
			$instanceString=get_class($instance);
152
		if (sizeof($_POST) > 0) {
153
			try{
154
				if (DAO::remove($instance)) {
0 ignored issues
show
Bug introduced by
It seems like $instance defined by $this->getModelInstance($ids) on line 147 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...
155
					$message=new CRUDMessage("Deletion of `<b>" . $instanceString . "</b>`","Deletion","info","info circle",4000);
156
					$message=$this->_getEvents()->onSuccessDeleteMessage($message);
157
					$this->jquery->exec("$('._element[data-ajax={$ids}]').remove();", true);
158
				} else {
159
					$message=new CRUDMessage("Can not delete `" . $instanceString . "`","Deletion","warning","warning circle");
160
					$message=$this->_getEvents()->onErrorDeleteMessage($message);
161
				}
162
			}catch (\Exception $e){
163
				$message=new CRUDMessage("Exception : can not delete `" . $instanceString . "`","Exception", "warning", "warning");
164
				$message=$this->_getEvents()->onErrorDeleteMessage($message);
165
			}
166
			$message=$this->_showSimpleMessage($message);
167
		} else {
168
			$message=new CRUDMessage("Do you confirm the deletion of `<b>" . $instanceString . "</b>`?", "Remove confirmation","error");
169
			$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...
170
			$message=$this->_showConfMessage($message, $this->_getBaseRoute() . "/delete/{$ids}", "#table-messages", $ids);
171
		}
172
		echo $message;
173
		echo $this->jquery->compile($this->view);
174
	}
175
	
176
177
	
178
	public function refreshTable($id=null) {
179
		$compo= $this->_showModel($id);
180
		$this->jquery->execAtLast('$("#table-details").html("");');
181
		$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);	
182
	}
183
	
184
	/**
185
	 * Updates an instance from the data posted in a form
186
	 */
187
	public function update() {
188
		$message=new CRUDMessage("Modifications were successfully saved", "Updating");
189
		$instance=@$_SESSION["instance"];
190
		$isNew=$instance->_new;
191
		try{
192
			$updated=CRUDHelper::update($instance, $_POST,$this->_getAdminData()->getUpdateManyToOneInForm(),$this->_getAdminData()->getUpdateManyToManyInForm());
193
			if($updated){
194
				$message->setType("success")->setIcon("check circle outline");
195
				$message=$this->_getEvents()->onSuccessUpdateMessage($message);
196
				$this->refreshInstance($instance,$isNew);
197
			} else {
198
				$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...
199
				$message=$this->_getEvents()->onErrorUpdateMessage($message);
200
			}
201
		}catch(\Exception $e){
202 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...
203
				$instanceString=$instance . "";
204
			else
205
				$instanceString=get_class($instance);
206
			$message=new CRUDMessage("Exception : can not update `" . $instanceString . "`","Exception", "warning", "warning");
207
			$message=$this->_getEvents()->onErrorUpdateMessage($message);
208
		}
209
		echo $this->_showSimpleMessage($message,"updateMsg");
210
		echo $this->jquery->compile($this->view);
211
	}
212
	
213
	protected function refreshInstance($instance,$isNew){
214
		if($this->_getAdminData()->refreshPartialInstance() && !$isNew){
215
			$this->jquery->setJsonToElement(OrmUtils::objectAsJSON($instance));
216
		}else{
217
			$pk=OrmUtils::getFirstKeyValue($instance);
218
			$this->jquery->get($this->_getBaseRoute() . "/refreshTable/".$pk, "#lv", [ "jqueryDone" => "replaceWith" ]);
219
		}
220
	}
221
	
222
	/**
223
	 * Shows associated members with foreign keys
224
	 * @param mixed $ids
225
	 */
226
	public function showDetail($ids) {
227
		$instance=$this->getModelInstance($ids);
228
		$viewer=$this->_getModelViewer();
229
		$hasElements=false;
230
		$model=$this->model;
231
		$fkInstances=CRUDHelper::getFKIntances($instance, $model);
232
		$semantic=$this->jquery->semantic();
233
		$grid=$semantic->htmlGrid("detail");
234
		if (sizeof($fkInstances) > 0) {
235
			$wide=intval(16 / sizeof($fkInstances));
236
			if ($wide < 4)
237
				$wide=4;
238
				foreach ( $fkInstances as $member=>$fkInstanceArray ) {
239
					$element=$viewer->getFkMemberElementDetails($member,$fkInstanceArray["objectFK"],$fkInstanceArray["fkClass"],$fkInstanceArray["fkTable"]);
240
					if (isset($element)) {
241
						$grid->addCol($wide)->setContent($element);
242
						$hasElements=true;
243
					}
244
				}
245
				if ($hasElements)
246
					echo $grid;
247
					$url=$this->_getEvents()->onDetailClickURL($this->model);
248
				if(UString::isNotNull($url)){
249
					$this->detailClick($url);
250
				}
251
				echo $this->jquery->compile($this->view);
252
		}
253
254
	}
255
	
256
	public function detailClick($url) {
257
		$this->jquery->postOnClick(".showTable", $this->_getBaseRoute() . "/".$url,"{}", "#divTable", [ "attr" => "data-ajax","ajaxTransition" => "random" ]);
258
	}
259
	
260
	private function getModelInstance($ids) {
261
		$ids=\explode("_", $ids);
262
		$instance=DAO::getOne($this->model, $ids);
263
		if(isset($instance)){
264
			return $instance;
265
		}
266
		$message=new CRUDMessage("This object does not exist!","Get object","warning","warning circle");
267
		$message=$this->_getEvents()->onNotFoundMessage($message);
268
		echo $this->_showSimpleMessage($message);
269
		echo $this->jquery->compile($this->view);
270
		exit(1);
271
	}
272
	
273
	/**
274
	 * To override for defining a new adminData
275
	 * @return CRUDDatas
276
	 */
277
	protected function getAdminData ():CRUDDatas{
278
		return new CRUDDatas();
279
	}
280
	
281
	public function _getAdminData ():CRUDDatas{
282
		return $this->getSingleton($this->modelViewer,"getAdminData");
283
	}
284
	
285
	/**
286
	 * To override for defining a new ModelViewer
287
	 * @return ModelViewer
288
	 */
289
	protected function getModelViewer ():ModelViewer{
290
		return new ModelViewer($this);
291
	}
292
	
293
	private function _getModelViewer():ModelViewer{
294
		return $this->getSingleton($this->modelViewer,"getModelViewer");
295
	}
296
	
297
	/**
298
	 * To override for changing view files
299
	 * @return CRUDFiles
300
	 */
301
	protected function getFiles ():CRUDFiles{
302
		return new CRUDFiles();
303
	}
304
	
305
	private function _getFiles():CRUDFiles{
306
		return $this->getSingleton($this->crudFiles,"getFiles");
307
	}
308
	
309
	/**
310
	 * To override for changing events
311
	 * @return CRUDEvents
312
	 */
313
	protected function getEvents ():CRUDEvents{
314
		return new CRUDEvents();
315
	}
316
	
317
	private function _getEvents():CRUDEvents{
318
		return $this->getSingleton($this->events,"getEvents");
319
	}
320
	
321
	private function getSingleton($value, $method) {
322
		if (! isset ( $value )) {
323
			$value = $this->$method ();
324
		}
325
		return $value;
326
	}
327
}
328